diff --git a/src/autoconf/Config.py b/src/autoconf/Config.py index 630216137..2725c563b 100644 --- a/src/autoconf/Config.py +++ b/src/autoconf/Config.py @@ -77,20 +77,25 @@ class Config(ConfigCaller): ) sleep(5) + # update instances in database + err = self._db.update_instances(self.__instances) + if err: + self.__logger.error(f"Failed to update instances: {err}") + # save config to database - ret = self._db.save_config(self.__config, "autoconf") - if ret: + err = self._db.save_config(self.__config, "autoconf") + if err: success = False self.__logger.error( - f"Can't save autoconf config in database: {ret}", + f"Can't save autoconf config in database: {err}", ) # save custom configs to database - ret = self._db.save_custom_configs(custom_configs, "autoconf") - if ret: + err = self._db.save_custom_configs(custom_configs, "autoconf") + if err: success = False self.__logger.error( - f"Can't save autoconf custom configs in database: {ret}", + f"Can't save autoconf custom configs in database: {err}", ) return success diff --git a/src/autoconf/Dockerfile b/src/autoconf/Dockerfile index d7f9464d7..b9c44dd1f 100644 --- a/src/autoconf/Dockerfile +++ b/src/autoconf/Dockerfile @@ -9,7 +9,7 @@ RUN mkdir -p /usr/share/bunkerweb/deps && \ rm -rf /tmp/req # Install dependencies -RUN apk add --no-cache --virtual .build-deps g++ gcc libffi-dev && \ +RUN apk add --no-cache --virtual .build-deps g++ gcc musl-dev jpeg-dev zlib-dev libffi-dev cairo-dev pango-dev gdk-pixbuf-dev && \ pip install --no-cache-dir --upgrade pip && \ pip install wheel && \ mkdir -p /usr/share/bunkerweb/deps/python && \ diff --git a/src/bw/lua/api.lua b/src/bw/lua/api.lua index 68bce8d72..5a25c0faa 100644 --- a/src/bw/lua/api.lua +++ b/src/bw/lua/api.lua @@ -19,7 +19,7 @@ api.global.GET["^/ping$"] = function(api) end api.global.POST["^/reload$"] = function(api) - local status = os.execute("/usr/sbin/nginx -s reload") + local status = os.execute("nginx -s reload") if status == 0 then return api:response(ngx.HTTP_OK, "success", "reload successful") end @@ -27,7 +27,7 @@ api.global.POST["^/reload$"] = function(api) end api.global.POST["^/stop$"] = function(api) - local status = os.execute("/usr/sbin/nginx -s quit") + local status = os.execute("nginx -s quit") if status == 0 then return api:response(ngx.HTTP_OK, "success", "stop successful") end diff --git a/src/common/core/jobs/jobs/download-plugins.py b/src/common/core/jobs/jobs/download-plugins.py index 989db6b2a..f2e65ed10 100644 --- a/src/common/core/jobs/jobs/download-plugins.py +++ b/src/common/core/jobs/jobs/download-plugins.py @@ -108,10 +108,10 @@ try: external_plugins.append(plugin_file) if external_plugins: - ret = db.update_external_plugins(external_plugins) - if ret: + err = db.update_external_plugins(external_plugins) + if err: logger.error( - f"Couldn't update external plugins to database: {ret}", + f"Couldn't update external plugins to database: {err}", ) except: diff --git a/src/common/core/letsencrypt/jobs/certbot-auth.py b/src/common/core/letsencrypt/jobs/certbot-auth.py index 7bc55d4e1..a1245066c 100755 --- a/src/common/core/letsencrypt/jobs/certbot-auth.py +++ b/src/common/core/letsencrypt/jobs/certbot-auth.py @@ -1,32 +1,46 @@ #!/usr/bin/python3 -import sys, os, traceback +from os import getenv, makedirs +from os.path import exists +from sys import exit as sys_exit, path as sys_path +from traceback import format_exc -sys.path.append("/usr/share/bunkerweb/deps/python") -sys.path.append("/usr/share/bunkerweb/utils") -sys.path.append("/usr/share/bunkerweb/api") +sys_path.append("/usr/share/bunkerweb/deps/python") +sys_path.append("/usr/share/bunkerweb/utils") +sys_path.append("/usr/share/bunkerweb/api") +sys_path.append("/usr/share/bunkerweb/db") +from Database import Database from logger import setup_logger from API import API -logger = setup_logger("Lets-encrypt", os.getenv("LOG_LEVEL", "INFO")) +logger = setup_logger("Lets-encrypt", getenv("LOG_LEVEL", "INFO")) +db = Database( + logger, + sqlalchemy_string=getenv("DATABASE_URI", None), +) status = 0 try: # Get env vars - is_kubernetes_mode = os.getenv("KUBERNETES_MODE") == "yes" - is_swarm_mode = os.getenv("SWARM_MODE") == "yes" - is_autoconf_mode = os.getenv("AUTOCONF_MODE") == "yes" - token = os.getenv("CERTBOT_TOKEN") - validation = os.getenv("CERTBOT_VALIDATION") + bw_integration = None + if getenv("KUBERNETES_MODE") == "yes": + bw_integration = "Swarm" + elif getenv("SWARM_MODE") == "yes": + bw_integration = "Kubernetes" + elif getenv("AUTOCONF_MODE") == "yes": + bw_integration = "Autoconf" + elif exists("/usr/share/bunkerweb/INTEGRATION"): + with open("/usr/share/bunkerweb/INTEGRATION", "r") as f: + bw_integration = f.read().strip() + token = getenv("CERTBOT_TOKEN") + validation = getenv("CERTBOT_VALIDATION") # Cluster case - if is_kubernetes_mode or is_swarm_mode or is_autoconf_mode: - for variable, value in os.environ.items(): - if not variable.startswith("CLUSTER_INSTANCE_"): - continue - endpoint = value.split(" ")[0] - host = value.split(" ")[1] + if bw_integration in ("Docker", "Swarm", "Kubernetes", "Autoconf"): + for instance in db.get_instances(): + endpoint = f"http://{instance['hostname']}:{instance['port']}" + host = instance["server_name"] api = API(endpoint, host=host) sent, err, status, resp = api.request( "POST", @@ -49,15 +63,14 @@ try: f"Successfully sent API request to {api.get_endpoint()}/lets-encrypt/challenge", ) - # Docker or Linux case + # Linux case else: root_dir = "/var/tmp/bunkerweb/lets-encrypt/.well-known/acme-challenge/" - os.makedirs(root_dir, exist_ok=True) - with open(root_dir + token, "w") as f: + makedirs(root_dir, exist_ok=True) + with open(f"{root_dir}{token}", "w") as f: f.write(validation) except: status = 1 - logger.error("Exception while running certbot-auth.py :") - print(traceback.format_exc()) + logger.error(f"Exception while running certbot-auth.py :\n{format_exc()}") -sys.exit(status) +sys_exit(status) diff --git a/src/common/core/letsencrypt/jobs/certbot-cleanup.py b/src/common/core/letsencrypt/jobs/certbot-cleanup.py index f51c2b768..cb6d886ad 100755 --- a/src/common/core/letsencrypt/jobs/certbot-cleanup.py +++ b/src/common/core/letsencrypt/jobs/certbot-cleanup.py @@ -1,31 +1,45 @@ #!/usr/bin/python3 -import sys, os, traceback +from os import getenv, remove +from os.path import exists, isfile +from sys import exit as sys_exit, path as sys_path +from traceback import format_exc -sys.path.append("/usr/share/bunkerweb/deps/python") -sys.path.append("/usr/share/bunkerweb/utils") -sys.path.append("/usr/share/bunkerweb/api") +sys_path.append("/usr/share/bunkerweb/deps/python") +sys_path.append("/usr/share/bunkerweb/utils") +sys_path.append("/usr/share/bunkerweb/api") +sys_path.append("/usr/share/bunkerweb/db") +from Database import Database from logger import setup_logger from API import API -logger = setup_logger("Lets-encrypt", os.getenv("LOG_LEVEL", "INFO")) +logger = setup_logger("Lets-encrypt", getenv("LOG_LEVEL", "INFO")) +db = Database( + logger, + sqlalchemy_string=getenv("DATABASE_URI", None), +) status = 0 try: # Get env vars - is_kubernetes_mode = os.getenv("KUBERNETES_MODE") == "yes" - is_swarm_mode = os.getenv("SWARM_MODE") == "yes" - is_autoconf_mode = os.getenv("AUTOCONF_MODE") == "yes" - token = os.getenv("CERTBOT_TOKEN") + bw_integration = None + if getenv("KUBERNETES_MODE") == "yes": + bw_integration = "Swarm" + elif getenv("SWARM_MODE") == "yes": + bw_integration = "Kubernetes" + elif getenv("AUTOCONF_MODE") == "yes": + bw_integration = "Autoconf" + elif exists("/usr/share/bunkerweb/INTEGRATION"): + with open("/usr/share/bunkerweb/INTEGRATION", "r") as f: + bw_integration = f.read().strip() + token = getenv("CERTBOT_TOKEN") # Cluster case - if is_kubernetes_mode or is_swarm_mode or is_autoconf_mode: - for variable, value in os.environ.items(): - if not variable.startswith("CLUSTER_INSTANCE_"): - continue - endpoint = value.split(" ")[0] - host = value.split(" ")[1] + if bw_integration in ("Docker", "Swarm", "Kubernetes", "Autoconf"): + for instance in db.get_instances(): + endpoint = f"http://{instance['hostname']}:{instance['port']}" + host = instance["server_name"] api = API(endpoint, host=host) sent, err, status, resp = api.request( "DELETE", "/lets-encrypt/challenge", data={"token": token} @@ -45,17 +59,15 @@ try: logger.info( f"Successfully sent API request to {api.get_endpoint()}/lets-encrypt/challenge", ) - - # Docker or Linux case + # Linux case else: challenge_path = ( f"/var/tmp/bunkerweb/lets-encrypt/.well-known/acme-challenge/{token}" ) - if os.path.isfile(challenge_path): - os.remove(challenge_path) + if isfile(challenge_path): + remove(challenge_path) except: status = 1 - logger.error("Exception while running certbot-cleanup.py :") - print(traceback.format_exc()) + logger.error(f"Exception while running certbot-cleanup.py :\n{format_exc()}") -sys.exit(status) +sys_exit(status) diff --git a/src/common/core/letsencrypt/jobs/certbot-deploy.py b/src/common/core/letsencrypt/jobs/certbot-deploy.py index 3d2b6305f..4e21428b4 100755 --- a/src/common/core/letsencrypt/jobs/certbot-deploy.py +++ b/src/common/core/letsencrypt/jobs/certbot-deploy.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 from io import BytesIO -from os import environ, getenv +from os import getenv from os.path import exists from subprocess import run, DEVNULL, STDOUT from sys import exit as sys_exit, path as sys_path @@ -11,13 +11,17 @@ from traceback import format_exc sys_path.append("/usr/share/bunkerweb/deps/python") sys_path.append("/usr/share/bunkerweb/utils") sys_path.append("/usr/share/bunkerweb/api") +sys_path.append("/usr/share/bunkerweb/db") -from docker import DockerClient - +from Database import Database from logger import setup_logger from API import API logger = setup_logger("Lets-encrypt", getenv("LOG_LEVEL", "INFO")) +db = Database( + logger, + sqlalchemy_string=getenv("DATABASE_URI", None), +) status = 0 try: @@ -33,11 +37,11 @@ try: with open("/usr/share/bunkerweb/INTEGRATION", "r") as f: bw_integration = f.read().strip() token = getenv("CERTBOT_TOKEN") - + logger.info(f"Certificates renewal for {getenv('RENEWED_DOMAINS')} successful") # Cluster case - if bw_integration in ("Swarm", "Kubernetes", "Autoconf"): + if bw_integration in ("Docker", "Swarm", "Kubernetes", "Autoconf"): # Create tarball of /data/cache/letsencrypt tgz = BytesIO() with tar_open(mode="w:gz", fileobj=tgz) as tf: @@ -45,11 +49,9 @@ try: tgz.seek(0, 0) files = {"archive.tar.gz": tgz} - for variable, value in environ.items(): - if not variable.startswith("CLUSTER_INSTANCE_"): - continue - endpoint = value.split(" ")[0] - host = value.split(" ")[1] + for instance in db.get_instances(): + endpoint = f"http://{instance['hostname']}:{instance['port']}" + host = instance["server_name"] api = API(endpoint, host=host) sent, err, status, resp = api.request( "POST", "/lets-encrypt/certificates", files=files @@ -85,53 +87,13 @@ try: logger.info( f"Successfully sent API request to {api.get_endpoint()}/reload" ) - - # Docker or Linux case - elif bw_integration == "Docker": - docker_client = DockerClient( - base_url=getenv("DOCKER_HOST", "unix:///var/run/docker.sock") + # Linux case + else: + proc = run( + ["nginx", "-s", "reload"], + stdin=DEVNULL, + stderr=STDOUT, ) - - apis = [] - for instance in docker_client.containers.list( - filters={"label": "bunkerweb.INSTANCE"} - ): - api = None - - for var in instance.attrs["Config"]["Env"]: - if var.startswith("API_HTTP_PORT="): - api = API( - f"http://{instance.name}:{var.replace('API_HTTP_PORT=', '', 1)}" - ) - break - - if api: - apis.append(api) - else: - apis.append( - API(f"http://{instance.name}:{getenv('API_HTTP_PORT', '5000')}") - ) - - for api in apis: - sent, err, status, resp = api.request("POST", "/reload") - if not sent: - status = 1 - logger.error( - f"Can't send API request to {api.get_endpoint()}/reload : {err}" - ) - else: - if status != 200: - status = 1 - logger.error( - f"Error while sending API request to {api.get_endpoint()}/reload : status = {resp['status']}, msg = {resp['msg']}" - ) - else: - logger.info( - f"Successfully sent API request to {api.get_endpoint()}/reload" - ) - elif bw_integration == "Linux": - cmd = "/usr/sbin/nginx -s reload" - proc = run(cmd.split(" "), stdin=DEVNULL, stderr=STDOUT) if proc.returncode != 0: status = 1 logger.error("Error while reloading nginx") diff --git a/src/common/core/letsencrypt/jobs/certbot-new.py b/src/common/core/letsencrypt/jobs/certbot-new.py index 35b638798..26202490c 100755 --- a/src/common/core/letsencrypt/jobs/certbot-new.py +++ b/src/common/core/letsencrypt/jobs/certbot-new.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -from os import environ, getenv +from os import environ, getcwd, getenv from os.path import exists from subprocess import DEVNULL, STDOUT, run from sys import exit as sys_exit, path as sys_path @@ -8,17 +8,42 @@ from traceback import format_exc sys_path.append("/usr/share/bunkerweb/deps/python") sys_path.append("/usr/share/bunkerweb/utils") +sys_path.append("/usr/share/bunkerweb/db") +from Database import Database from logger import setup_logger +logger = setup_logger("LETS-ENCRYPT", getenv("LOG_LEVEL", "INFO")) +db = Database( + logger, + sqlalchemy_string=getenv("DATABASE_URI", None), +) +status = 0 + def certbot_new(domains, email): - cmd = f"/usr/share/bunkerweb/deps/python/bin/certbot certonly --manual --preferred-challenges=http --manual-auth-hook /usr/share/bunkerweb/core/letsencrypt/jobs/certbot-auth.py --manual-cleanup-hook /usr/share/bunkerweb/core/letsencrypt/jobs/certbot-cleanup.py -n -d {domains} --email {email} --agree-tos" - if getenv("USE_LETS_ENCRYPT_STAGING") == "yes": - cmd += " --staging" environ["PYTHONPATH"] = "/usr/share/bunkerweb/deps/python" proc = run( - cmd.split(" "), + [ + "/usr/share/bunkerweb/deps/python/bin/certbot certonly", + "--manual", + "--preferred-challenges=http", + "--manual-auth-hook", + f"{getcwd()}/certbot-auth.py", + "--manual-cleanup-hook", + f"{getcwd()}/certbot-cleanup.py", + "-n", + "-d", + domains, + "--email", + email, + "--agree-tos", + "--logs-dir", + "/var/tmp/bunkerweb", + "--work-dir", + "/var/lib/bunkerweb", + ] + + (["--staging"] if getenv("USE_LETS_ENCRYPT_STAGING", "no") == "yes" else []), stdin=DEVNULL, stderr=STDOUT, env=environ, @@ -26,34 +51,37 @@ def certbot_new(domains, email): return proc.returncode -logger = setup_logger("LETS-ENCRYPT", getenv("LOG_LEVEL", "INFO")) -status = 0 - try: - # Multisite case - if getenv("MULTISITE") == "yes": - for first_server in getenv("SERVER_NAME").split(" "): + if getenv("MULTISITE", "no") == "yes": + for first_server in getenv("SERVER_NAME", "").split(" "): if ( - getenv(f"{first_server}_AUTO_LETS_ENCRYPT", getenv("AUTO_LETS_ENCRYPT")) + not first_server + or getenv( + f"{first_server}_AUTO_LETS_ENCRYPT", + getenv("AUTO_LETS_ENCRYPT", "no"), + ) != "yes" ): continue - if first_server == "": - continue - real_server_name = getenv(f"{first_server}_SERVER_NAME", first_server) - domains = real_server_name.replace(" ", ",") + + domains = getenv(f"{first_server}_SERVER_NAME", first_server).replace( + " ", "," + ) + if exists(f"/etc/letsencrypt/live/{first_server}/cert.pem"): logger.info( f"Certificates already exists for domain(s) {domains}", ) continue + real_email = getenv( f"{first_server}_EMAIL_LETS_ENCRYPT", getenv("EMAIL_LETS_ENCRYPT", f"contact@{first_server}"), ) - if real_email == "": + if not real_email: real_email = f"contact@{first_server}" + logger.info( f"Asking certificates for domains : {domains} (email = {real_email}) ...", ) @@ -67,16 +95,32 @@ try: f"Certificate generation succeeded for domain(s) : {domains}" ) + if exists(f"/etc/letsencrypt/live/{first_server}/cert.pem"): + with open(f"/etc/letsencrypt/live/{first_server}/cert.pem") as f: + cert = f.read() + + # Update db + err = db.update_job_cache( + "letsencrypt", + first_server, + "cert.pem", + cert, + ) + if err: + logger.warning(f"Couldn't update db cache: {err}") + # Singlesite case - elif getenv("AUTO_LETS_ENCRYPT") == "yes" and getenv("SERVER_NAME") != "": - first_server = getenv("SERVER_NAME").split(" ")[0] - domains = getenv("SERVER_NAME").replace(" ", ",") + elif getenv("AUTO_LETS_ENCRYPT", "no") == "yes" and getenv("SERVER_NAME", ""): + first_server = getenv("SERVER_NAME", "").split(" ")[0] + domains = getenv("SERVER_NAME", "").replace(" ", ",") + if exists(f"/etc/letsencrypt/live/{first_server}/cert.pem"): logger.info(f"Certificates already exists for domain(s) {domains}") else: real_email = getenv("EMAIL_LETS_ENCRYPT", f"contact@{first_server}") - if real_email == "": + if not real_email: real_email = f"contact@{first_server}" + logger.info( f"Asking certificates for domain(s) : {domains} (email = {real_email}) ...", ) @@ -88,7 +132,19 @@ try: f"Certificate generation succeeded for domain(s) : {domains}" ) + if exists(f"/etc/letsencrypt/live/{first_server}/cert.pem"): + with open(f"/etc/letsencrypt/live/{first_server}/cert.pem") as f: + cert = f.read() + # Update db + err = db.update_job_cache( + "letsencrypt", + first_server, + "cert.pem", + cert, + ) + if err: + logger.warning(f"Couldn't update db cache: {err}") except: status = 1 logger.error(f"Exception while running certbot-new.py :\n{format_exc()}") diff --git a/src/common/core/letsencrypt/jobs/certbot-renew.py b/src/common/core/letsencrypt/jobs/certbot-renew.py index 9e7951f1e..cf464c3b8 100755 --- a/src/common/core/letsencrypt/jobs/certbot-renew.py +++ b/src/common/core/letsencrypt/jobs/certbot-renew.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -from os import environ, getenv +from os import environ, getcwd, getenv from os.path import exists from subprocess import DEVNULL, STDOUT, run from sys import exit as sys_exit, path as sys_path @@ -13,10 +13,16 @@ from logger import setup_logger def renew(domain): - cmd = f"/usr/share/bunkerweb/deps/python/bin/certbot renew --cert-name {domain} --deploy-hook /usr/share/bunkerweb/core/letsencrypt/jobs/certbot-deploy.py" environ["PYTHONPATH"] = "/usr/share/bunkerweb/deps/python" proc = run( - cmd.split(" "), + [ + "/usr/share/bunkerweb/deps/python/bin/certbot", + "renew", + "--cert-name", + domain, + "--deploy-hook", + f"{getcwd()}/certbot-deploy.py", + ], stdin=DEVNULL, stderr=STDOUT, env=environ, @@ -30,23 +36,25 @@ status = 0 try: if getenv("MULTISITE") == "yes": for first_server in getenv("SERVER_NAME").split(" "): - if first_server == "": - continue if ( - getenv(f"{first_server}_AUTO_LETS_ENCRYPT", getenv("AUTO_LETS_ENCRYPT")) + not first_server + or getenv( + f"{first_server}_AUTO_LETS_ENCRYPT", + getenv("AUTO_LETS_ENCRYPT", "no"), + ) != "yes" + or not exists(f"/etc/letsencrypt/live/{first_server}/cert.pem") ): continue - if not exists(f"/etc/letsencrypt/live/{first_server}/cert.pem"): - continue + ret = renew(first_server) if ret != 0: status = 2 logger.error( f"Certificates renewal for {first_server} failed", ) - elif getenv("AUTO_LETS_ENCRYPT") == "yes" and getenv("SERVER_NAME") != "": - first_server = getenv("SERVER_NAME").split(" ")[0] + elif getenv("AUTO_LETS_ENCRYPT", "no") == "yes" and not getenv("SERVER_NAME", ""): + first_server = getenv("SERVER_NAME", "").split(" ")[0] if exists(f"/etc/letsencrypt/live/{first_server}/cert.pem"): ret = renew(first_server) if ret != 0: diff --git a/src/common/db/Database.py b/src/common/db/Database.py index 8959d8a70..0e614f38b 100644 --- a/src/common/db/Database.py +++ b/src/common/db/Database.py @@ -2,7 +2,12 @@ from contextlib import contextmanager from copy import deepcopy from datetime import datetime from hashlib import sha256 -from logging import INFO, WARNING, Logger, getLogger +from logging import ( + NOTSET, + Logger, + _levelToName, + _nameToLevel, +) import oracledb from os import _exit, getenv, listdir, makedirs from os.path import dirname, exists @@ -24,6 +29,8 @@ from traceback import format_exc from model import ( Base, + Instances, + Logs, Plugins, Settings, Global_values, @@ -55,10 +62,6 @@ class Database: self.__sql_session = None self.__sql_engine = None - getLogger("sqlalchemy.engine").setLevel( - logger.level if logger.level != INFO else WARNING - ) - if not sqlalchemy_string: sqlalchemy_string = getenv( "DATABASE_URI", "sqlite:////var/lib/bunkerweb/db.sqlite3" @@ -77,7 +80,6 @@ class Database: sqlalchemy_string, encoding="utf-8", future=True, - logging_name="sqlalchemy.engine", ) except ArgumentError: self.__logger.error(f"Invalid database URI: {sqlalchemy_string}") @@ -1238,7 +1240,6 @@ class Database: { "service_id": cache.service_id, "file_name": cache.file_name, - "data": cache.data, "last_update": cache.last_update.strftime( "%Y/%m/%d, %I:%M:%S %p" ), @@ -1247,7 +1248,6 @@ class Database: .with_entities( Jobs_cache.service_id, Jobs_cache.file_name, - Jobs_cache.data, Jobs_cache.last_update, ) .filter_by(job_name=job.name) @@ -1266,3 +1266,104 @@ class Database: .all() ) } + + def get_job_cache_file(self, job_name: str, file_name: str) -> Optional[bytes]: + """Get job cache file.""" + with self.__db_session() as session: + return ( + session.query(Jobs_cache) + .with_entities(Jobs_cache.data) + .filter_by(job_name=job_name, file_name=file_name) + .first() + ) + + def save_log( + self, + log: str, + level: Tuple[str, int], + component: str, + ) -> str: + """Save log.""" + with self.__db_session() as session: + session.add( + Logs( + id=int(datetime.now().timestamp()), + message=log, + level=str(_levelToName[_nameToLevel.get(level, NOTSET)]) + if isinstance(level, str) + else _levelToName.get(level, "NOTSET"), + component=component, + ) + ) + + try: + session.commit() + except BaseException: + return format_exc() + + return "" + + def add_instance(self, hostname: str, port: int, server_name: str) -> str: + """Add instance.""" + with self.__db_session() as session: + db_instance = ( + session.query(Instances) + .with_entities(Instances.hostname) + .filter_by(hostname=hostname) + .first() + ) + + if db_instance is not None: + return "An instance with the same hostname already exists." + + session.add( + Instances(hostname=hostname, port=int(port), server_name=server_name) + ) + + try: + session.commit() + except BaseException: + return f"An error occurred while adding the instance {hostname} (port: {port}, server name: {server_name}).\n{format_exc()}" + + return "" + + def update_instances(self, instances: List[Dict[str, Any]]) -> str: + """Update instances.""" + to_put = [] + with self.__db_session() as session: + session.query(Instances).delete() + + for instance in instances: + to_put.append( + Instances( + hostname=instance["hostname"], + port=instance["env"].get("API_HTTP_PORT", 5000), + server_name=instance["env"].get("API_SERVER_NAME", "bwapi"), + ) + ) + + try: + session.add_all(to_put) + session.commit() + except BaseException: + return format_exc() + + return "" + + def get_instances(self) -> List[Dict[str, Any]]: + """Get instances.""" + with self.__db_session() as session: + return [ + { + "hostname": instance.hostname, + "port": instance.port, + "server_name": instance.server_name, + } + for instance in ( + session.query(Instances) + .with_entities( + Instances.hostname, Instances.port, Instances.server_name + ) + .all() + ) + ] diff --git a/src/common/db/model.py b/src/common/db/model.py index d07841560..0dc46d247 100644 --- a/src/common/db/model.py +++ b/src/common/db/model.py @@ -10,7 +10,6 @@ from sqlalchemy import ( PrimaryKeyConstraint, SmallInteger, String, - text, TIMESTAMP, ) from sqlalchemy.orm import declarative_base, relationship @@ -30,7 +29,15 @@ CUSTOM_CONFIGS_TYPES_ENUM = Enum( "stream_http", name="custom_configs_types_enum", ) -LOG_LEVELS_ENUM = Enum("DEBUG", "INFO", "WARNING", "ERROR", name="log_levels_enum") +LOG_LEVELS_ENUM = Enum( + "CRITICAL", + "ERROR", + "WARNING", + "INFO", + "DEBUG", + "NOTSET", + name="log_levels_enum", +) INTEGRATIONS_ENUM = Enum( "Linux", "Docker", @@ -265,6 +272,14 @@ class Logs(Base): component = Column(String(255), nullable=False) +class Instances(Base): + __tablename__ = "instances" + + hostname = Column(String(255), primary_key=True) + port = Column(Integer, nullable=False) + server_name = Column(String(255), nullable=False) + + class Metadata(Base): __tablename__ = "metadata" diff --git a/src/common/gen/main.py b/src/common/gen/main.py index 08909931a..ef397d3e4 100644 --- a/src/common/gen/main.py +++ b/src/common/gen/main.py @@ -174,8 +174,7 @@ if __name__ == "__main__": retries += 1 sleep(5) - cmd = "/usr/sbin/nginx -s reload" - proc = run(cmd.split(" "), stdin=DEVNULL, stderr=STDOUT) + proc = run(["nginx", "-s", "reload"], stdin=DEVNULL, stderr=STDOUT) if proc.returncode != 0: status = 1 logger.error("Error while reloading nginx") diff --git a/src/common/gen/save_config.py b/src/common/gen/save_config.py index f9096f7a8..6ead30945 100644 --- a/src/common/gen/save_config.py +++ b/src/common/gen/save_config.py @@ -369,6 +369,25 @@ if __name__ == "__main__": sys_exit(1) else: logger.info("Config successfully saved to database") + + if apis: + for api in apis: + endpoint_data = api.get_endpoint().replace("http://", "").split(":") + err = db.add_instance( + endpoint_data[0], endpoint_data[1], api.get_host() + ) + + if err: + logger.warning(err) + else: + err = db.add_instance( + "localhost", + config_files.get("API_HTTP_PORT", 5000), + config_files.get("API_SERVER_NAME", "bwapi"), + ) + + if err: + logger.warning(err) except SystemExit as e: sys_exit(e) except: diff --git a/src/common/helpers/entrypoint.sh b/src/common/helpers/entrypoint.sh index c0f6b84b6..695ff6e69 100644 --- a/src/common/helpers/entrypoint.sh +++ b/src/common/helpers/entrypoint.sh @@ -11,7 +11,7 @@ log "ENTRYPOINT" "ℹ️" "Starting BunkerWeb v$(cat /usr/share/bunkerweb/VERSIO function trap_exit() { log "ENTRYPOINT" "ℹ️" "Catched stop operation" log "ENTRYPOINT" "ℹ️" "Stopping nginx ..." - /usr/sbin/nginx -s stop + nginx -s stop } trap "trap_exit" TERM INT QUIT diff --git a/src/common/utils/logger.py b/src/common/utils/logger.py index 2c1d55086..f54319dd4 100644 --- a/src/common/utils/logger.py +++ b/src/common/utils/logger.py @@ -1,38 +1,89 @@ -import logging +from logging import ( + CRITICAL, + DEBUG, + ERROR, + INFO, + WARNING, + Logger, + _levelToName, + _nameToLevel, + addLevelName, + basicConfig, + getLogger, + setLoggerClass, +) +from os import getenv +from threading import Lock -logging.basicConfig( + +class BWLogger(Logger): + def __init__(self, name, level=INFO): + self.name = name + self.db_lock = Lock() + return super(BWLogger, self).__init__(name, level) + + def _log( + self, + level, + msg, + args, + exc_info=None, + extra=None, + stack_info=False, + stacklevel=1, + *, + store_db: bool = False, + db=None, + ): + if store_db is True and db is not None: + with self.db_lock: + err = db.save_log(msg, level, self.name) + + if err: + self.error(f"Failed to save log to database: {err}") + + return super(BWLogger, self)._log( + level, msg, args, exc_info, extra, stack_info, stacklevel + ) + + +setLoggerClass(BWLogger) + +default_level = _nameToLevel.get(getenv("LOG_LEVEL", "INFO").upper(), INFO) +basicConfig( format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="[%Y-%m-%d %H:%M:%S]", - level=logging.INFO, + level=default_level, +) + +getLogger("sqlalchemy.orm.mapper.Mapper").setLevel( + default_level if default_level != INFO else WARNING +) +getLogger("sqlalchemy.orm.relationships.RelationshipProperty").setLevel( + default_level if default_level != INFO else WARNING +) +getLogger("sqlalchemy.orm.strategies.LazyLoader").setLevel( + default_level if default_level != INFO else WARNING +) +getLogger("sqlalchemy.pool.impl.QueuePool").setLevel( + default_level if default_level != INFO else WARNING +) +getLogger("sqlalchemy.engine.Engine").setLevel( + default_level if default_level != INFO else WARNING ) # Edit the default levels of the logging module -logging.addLevelName(logging.CRITICAL, "🚨") -logging.addLevelName(logging.DEBUG, "🐛") -logging.addLevelName(logging.ERROR, "❌") -logging.addLevelName(logging.INFO, "ℹ️ ") -logging.addLevelName(logging.WARNING, "⚠️ ") +addLevelName(CRITICAL, "🚨") +addLevelName(DEBUG, "🐛") +addLevelName(ERROR, "❌") +addLevelName(INFO, "ℹ️ ") +addLevelName(WARNING, "⚠️ ") -def setup_logger(title: str, level=logging.INFO) -> logging.Logger: +def setup_logger(title: str, level=INFO) -> Logger: """Set up local logger""" title = title.upper() - logger = logging.getLogger(title) - - if level not in ( - logging.DEBUG, - logging.INFO, - logging.WARNING, - logging.ERROR, - logging.CRITICAL, - "DEBUG", - "INFO", - "WARNING", - "ERROR", - "CRITICAL", - ): - level = logging.INFO - - logger.setLevel(level) + logger = getLogger(title) + logger.setLevel(_nameToLevel.get(level, _levelToName.get(level, INFO))) return logger diff --git a/src/scheduler/Dockerfile b/src/scheduler/Dockerfile index 7568ec7b3..3066d7f89 100644 --- a/src/scheduler/Dockerfile +++ b/src/scheduler/Dockerfile @@ -10,7 +10,7 @@ RUN mkdir -p /usr/share/bunkerweb/deps && \ rm -rf /tmp/req # Install python requirements -RUN apk add --no-cache --virtual .build-deps g++ gcc libffi-dev && \ +RUN apk add --no-cache --virtual .build-deps g++ gcc musl-dev jpeg-dev zlib-dev libffi-dev cairo-dev pango-dev gdk-pixbuf-dev && \ pip install --no-cache-dir --upgrade pip && \ pip install wheel && \ mkdir -p /usr/share/bunkerweb/deps/python && \ @@ -51,7 +51,8 @@ RUN apk add --no-cache bash libgcc libstdc++ openssl && \ chown -R root:scheduler /usr/share/bunkerweb /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb /var/tmp/bunkerweb && \ for dir in $(echo "/usr/share/bunkerweb /etc/bunkerweb") ; do find ${dir} -type f -exec chmod 0740 {} \; ; done && \ for dir in $(echo "/usr/share/bunkerweb /etc/bunkerweb") ; do find ${dir} -type d -exec chmod 0750 {} \; ; done && \ - chmod 770 /var/cache/bunkerweb /var/lib/bunkerweb /var/tmp/bunkerweb && \ + chmod -R 770 /var/cache/bunkerweb /var/lib/bunkerweb /var/tmp/bunkerweb && \ + find /usr/share/bunkerweb/core/*/jobs/* -type f -exec chmod 750 {} \; && \ chmod 750 /usr/share/bunkerweb/gen/*.py /usr/share/bunkerweb/scheduler/main.py /usr/share/bunkerweb/scheduler/entrypoint.sh /usr/share/bunkerweb/helpers/*.sh /usr/share/bunkerweb/deps/python/bin/* && \ mkdir /etc/nginx && \ chown -R scheduler:scheduler /etc/nginx && \ diff --git a/src/scheduler/JobScheduler.py b/src/scheduler/JobScheduler.py index ccbcd8cf9..db3c1db8d 100644 --- a/src/scheduler/JobScheduler.py +++ b/src/scheduler/JobScheduler.py @@ -80,7 +80,7 @@ class JobScheduler(ApiCaller): if self.__integration == "Linux": self.__logger.info("Reloading nginx ...") proc = run( - ["/usr/sbin/nginx", "-s", "reload"], + ["nginx", "-s", "reload"], stdin=DEVNULL, stderr=PIPE, env=self.__env, @@ -111,6 +111,8 @@ class JobScheduler(ApiCaller): stdin=DEVNULL, stderr=STDOUT, env=self.__env, + user=101, + group=101, ) except BaseException: with self.__thread_lock: diff --git a/src/scheduler/main.py b/src/scheduler/main.py index e1c9f129e..e2d8e53ec 100644 --- a/src/scheduler/main.py +++ b/src/scheduler/main.py @@ -152,7 +152,6 @@ if __name__ == "__main__": logger, sqlalchemy_string=getenv("DATABASE_URI", None), ) - custom_configs = db.get_custom_configs() # END Define db because otherwhise it will be undefined for Linux logger.info("Scheduler started ...") @@ -192,11 +191,11 @@ if __name__ == "__main__": "Kubernetes", "Autoconf", ): - ret = db.set_autoconf_load(False) - if ret: + err = db.set_autoconf_load(False) + if err: success = False logger.error( - f"Can't set autoconf loaded metadata to false in database: {ret}", + f"Can't set autoconf loaded metadata to false in database: {err}", ) while not db.is_autoconf_loaded(): @@ -209,8 +208,16 @@ if __name__ == "__main__": or db.get_config() != dotenv_values("/var/tmp/bunkerweb/variables.env") ): # run the config saver - cmd = f"python /usr/share/bunkerweb/gen/save_config.py --settings /usr/share/bunkerweb/settings.json" - proc = subprocess_run(cmd.split(" "), stdin=DEVNULL, stderr=STDOUT) + proc = subprocess_run( + [ + "python", + "/usr/share/bunkerweb/gen/save_config.py", + "--settings", + "/usr/share/bunkerweb/settings.json", + ], + stdin=DEVNULL, + stderr=STDOUT, + ) if proc.returncode != 0: logger.error( "Config saver failed, configuration will not work as expected...", @@ -261,10 +268,10 @@ if __name__ == "__main__": if custom_confs: old_configs = db.get_custom_configs() - ret = db.save_custom_configs(custom_confs, "manual") - if ret: + err = db.save_custom_configs(custom_confs, "manual") + if err: logger.error( - f"Couldn't save some manually created custom configs to database: {ret}", + f"Couldn't save some manually created custom configs to database: {err}", ) custom_configs = db.get_custom_configs() @@ -273,7 +280,7 @@ if __name__ == "__main__": generate_custom_configs(custom_configs, integration, api_caller) logger.info("Executing scheduler ...") - + generate = not exists( "/var/tmp/bunkerweb/variables.env" ) or env != dotenv_values("/var/tmp/bunkerweb/variables.env") @@ -300,8 +307,21 @@ if __name__ == "__main__": if generate is True: # run the generator - cmd = f"python /usr/share/bunkerweb/gen/main.py --settings /usr/share/bunkerweb/settings.json --templates /usr/share/bunkerweb/confs --output /etc/nginx{f' --variables {args.variables}' if args.variables else ''}" - proc = subprocess_run(cmd.split(" "), stdin=DEVNULL, stderr=STDOUT) + proc = subprocess_run( + [ + "python3", + "/usr/share/bunkerweb/gen/main.py", + "--settings", + "/usr/share/bunkerweb/settings.json", + "--templates", + "/usr/share/bunkerweb/confs", + "--output", + "/etc/nginx", + ] + + (["--variables", args.variables] if args.variables else []), + stdin=DEVNULL, + stderr=STDOUT, + ) if proc.returncode != 0: logger.error( @@ -351,13 +371,12 @@ if __name__ == "__main__": logger.info("Reloading nginx ...") # Reloading the nginx server. # Had to use this instead of the nginx reload command because it was not working - proc = subprocess_run(["nginx", "-s", "reload"], stdin=DEVNULL, stderr=STDOUT) - # proc = run( - # ["/usr/sbin/nginx", "-s", "reload"], - # stdin=DEVNULL, - # stderr=PIPE, - # env=deepcopy(env), - # ) + proc = subprocess_run( + ["nginx", "-s", "reload"], + stdin=DEVNULL, + stderr=STDOUT, + env=deepcopy(env), + ) if proc.returncode == 0: logger.info("Successfuly reloaded nginx") else: diff --git a/src/ui/Dockerfile b/src/ui/Dockerfile index 40e2c88f6..e1a5ae428 100755 --- a/src/ui/Dockerfile +++ b/src/ui/Dockerfile @@ -10,7 +10,7 @@ RUN mkdir -p /usr/share/bunkerweb/deps && \ rm -rf /tmp/req # Install python requirements -RUN apk add --no-cache --virtual .build-deps g++ gcc && \ +RUN apk add --no-cache --virtual .build-deps g++ gcc musl-dev jpeg-dev zlib-dev libffi-dev cairo-dev pango-dev gdk-pixbuf-dev && \ pip install --no-cache-dir --upgrade pip && \ pip install wheel && \ mkdir -p /usr/share/bunkerweb/deps/python && \ diff --git a/src/ui/main.py b/src/ui/main.py index a95fed58e..a35dbb61a 100755 --- a/src/ui/main.py +++ b/src/ui/main.py @@ -1,3 +1,4 @@ +from io import BytesIO from bs4 import BeautifulSoup from copy import deepcopy from datetime import datetime, timedelta, timezone @@ -15,6 +16,7 @@ from flask import ( redirect, render_template, request, + send_file, url_for, ) from flask_login import LoginManager, login_required, login_user, logout_user @@ -49,12 +51,6 @@ from src.User import User from utils import ( check_settings, - env_to_summary_class, - form_plugin_gen, - form_service_gen, - form_service_gen_multiple, - form_service_gen_multiple_values, - gen_folders_tree_html, get_variables, path_to_dict, ) @@ -138,6 +134,8 @@ elif integration == "Kubernetes": kubernetes_client = kube_client.CoreV1Api() db = Database(logger) +with open("/usr/share/bunkerweb/VERSION", "r") as f: + bw_version = f.read().strip() try: app.config.update( @@ -164,14 +162,6 @@ except FileNotFoundError as e: sys_exit(1) # Declare functions for jinja2 -app.jinja_env.globals.update(env_to_summary_class=env_to_summary_class) -app.jinja_env.globals.update(form_plugin_gen=form_plugin_gen) -app.jinja_env.globals.update(form_service_gen=form_service_gen) -app.jinja_env.globals.update(form_service_gen_multiple=form_service_gen_multiple) -app.jinja_env.globals.update( - form_service_gen_multiple_values=form_service_gen_multiple_values -) -app.jinja_env.globals.update(gen_folders_tree_html=gen_folders_tree_html) app.jinja_env.globals.update(check_settings=check_settings) @@ -273,27 +263,30 @@ def home(): posts: a list of posts """ - r = get( - "https://raw.githubusercontent.com/bunkerity/bunkerweb/master/VERSION", - ) + try: + r = get( + "https://raw.githubusercontent.com/bunkerity/bunkerweb/master/VERSION", + ) + except BaseException: + r = None remote_version = None - if r.status_code == 200: + if r and r.status_code == 200: remote_version = r.text.strip() - with open("/usr/share/bunkerweb/VERSION", "r") as f: - version = f.read().strip() - headers = default_headers() headers.update({"User-Agent": "bunkerweb-ui"}) - r = get( - "https://www.bunkerity.com/wp-json/wp/v2/posts", - headers=headers, - ) + try: + r = get( + "https://www.bunkerity.com/wp-json/wp/v2/posts", + headers=headers, + ) + except BaseException: + r = None formatted_posts = None - if r.status_code == 200: + if r and r.status_code == 200: posts = r.json() formatted_posts = [] @@ -325,12 +318,13 @@ def home(): return render_template( "home.html", - check_version=not remote_version or version == remote_version, + check_version=not remote_version or bw_version == remote_version, remote_version=remote_version, - version=version, + version=bw_version, instances_number=instances_number, services_number=services_number, posts=formatted_posts, + plugins_errors=db.get_plugins_errors(), dark_mode=app.config["DARK_MODE"], ) @@ -1019,7 +1013,6 @@ def plugins(): return render_template( "plugins.html", - plugins=app.config["CONFIG"].get_plugins(), dark_mode=app.config["DARK_MODE"], ) @@ -1275,36 +1268,48 @@ def logs_linux(): @app.route("/logs/", methods=["GET"]) @login_required def logs_container(container_id): - last_update = request.args.get( - "last_update", - str(datetime.now().timestamp() - timedelta(days=1).total_seconds()), - ) + last_update = request.args.get("last_update", None) + from_date = request.args.get("from_date", None) + to_date = request.args.get("to_date", None) + + if from_date is not None: + last_update = from_date + + if any(arg and not arg.isdigit() for arg in [last_update, from_date, to_date]): + return ( + jsonify( + { + "status": "ko", + "message": "arguments must all be integers (timestamps)", + } + ), + 422, + ) + elif not last_update: + last_update = int( + datetime.now().timestamp() + - timedelta(days=1).total_seconds() # 1 day before + ) + else: + last_update = int(last_update) // 1000 + + to_date = int(to_date) // 1000 if to_date else None + logs = [] if docker_client: try: - if last_update and not last_update.isdigit(): - return ( - jsonify( - { - "status": "ko", - "message": "last_update must be an integer", - } - ), - 422, - ) - if getenv("SWARM_MODE", "no") == "no": docker_logs = docker_client.containers.get(container_id).logs( stdout=True, stderr=True, - since=datetime.fromtimestamp(int(last_update)), + since=datetime.fromtimestamp(last_update), timestamps=True, ) else: docker_logs = docker_client.services.get(container_id).logs( stdout=True, stderr=True, - since=datetime.fromtimestamp(int(last_update)), + since=datetime.fromtimestamp(last_update), timestamps=True, ) @@ -1324,7 +1329,7 @@ def logs_container(container_id): kubernetes_logs = kubernetes_client.read_namespaced_pod_log( container_id, getenv("KUBERNETES_NAMESPACE", "default"), - since_seconds=int(datetime.now().timestamp() - int(last_update)), + since_seconds=int(datetime.now().timestamp() - last_update), timestamps=True, ) tmp_logs = kubernetes_logs.split("\n")[0:-1] @@ -1339,10 +1344,16 @@ def logs_container(container_id): 404, ) - logger.warning(tmp_logs) - for log in tmp_logs: + splitted = log.split(" ") + timestamp = splitted[0] + + if to_date is not None and dateutil_parse(timestamp).timestamp() > to_date: + break + + log = " ".join(splitted[1:]) log_lower = log.lower() + logs.append( { "content": log, @@ -1371,11 +1382,47 @@ def logs_container(container_id): def jobs(): return render_template( "jobs.html", - jobs=db.get_jobs(), + jobs=dumps(db.get_jobs()), dark_mode=app.config["DARK_MODE"], ) +@app.route("/jobs/download", methods=["GET"]) +@login_required +def jobs_download(): + job_name = request.args.get("job_name", None) + file_name = request.args.get("file_name", None) + + if not job_name or not file_name: + return ( + jsonify( + { + "status": "ko", + "message": "job_name and file_name are required", + } + ), + 422, + ) + + cache_file = db.get_job_cache_file(job_name, file_name) + + if not cache_file: + return ( + jsonify( + { + "status": "ko", + "message": "file not found", + } + ), + 404, + ) + + with BytesIO(cache_file) as file: + file.seek(0) + + return send_file(file, as_attachment=True, attachment_filename=file_name) + + @app.route("/login", methods=["GET", "POST"]) def login(): fail = False @@ -1416,12 +1463,6 @@ def darkmode(): return jsonify({"status": "ok"}) -@app.route("/plugins_errors", methods=["GET"]) -@login_required -def plugins_errors(): - return jsonify({"status": "ok", "plugins_errors": db.get_plugins_errors()}) - - @app.route("/check_reloading") @login_required def check_reloading(): diff --git a/src/ui/src/Config.py b/src/ui/src/Config.py index 3f5cf1c99..b88cb7ec7 100644 --- a/src/ui/src/Config.py +++ b/src/ui/src/Config.py @@ -166,10 +166,10 @@ class Config: if proc.returncode != 0: raise Exception(f"Error from generator (return code = {proc.returncode})") - ret = self.__db.save_config(conf, "ui") - if ret: + err = self.__db.save_config(conf, "ui") + if err: self.__logger.error( - f"Can't save config in database: {ret}", + f"Can't save config in database: {err}", ) def get_plugins_settings(self) -> dict: diff --git a/src/ui/src/ConfigFiles.py b/src/ui/src/ConfigFiles.py index d47e9a87c..3456a009c 100644 --- a/src/ui/src/ConfigFiles.py +++ b/src/ui/src/ConfigFiles.py @@ -43,9 +43,9 @@ class ConfigFiles: } ) - ret = self.__db.save_custom_configs(custom_configs, "ui") - if ret: - self.__logger.error(f"Could not save custom configs: {ret}") + err = self.__db.save_custom_configs(custom_configs, "ui") + if err: + self.__logger.error(f"Could not save custom configs: {err}") return "Couldn't save custom configs to database" return "" diff --git a/src/ui/static/css/air-datepicker/air-datepicker.css b/src/ui/static/css/air-datepicker/air-datepicker.css deleted file mode 100644 index 6d6be2281..000000000 --- a/src/ui/static/css/air-datepicker/air-datepicker.css +++ /dev/null @@ -1,18 +0,0 @@ -.air-datepicker-cell.-day-.-other-month-,.air-datepicker-cell.-year-.-other-decade-{color:var(--adp-color-other-month)}.air-datepicker-cell.-day-.-other-month-:hover,.air-datepicker-cell.-year-.-other-decade-:hover{color:var(--adp-color-other-month-hover)}.-disabled-.-focus-.air-datepicker-cell.-day-.-other-month-,.-disabled-.-focus-.air-datepicker-cell.-year-.-other-decade-{color:var(--adp-color-other-month)}.-selected-.air-datepicker-cell.-day-.-other-month-,.-selected-.air-datepicker-cell.-year-.-other-decade-{color:#fff;background:var(--adp-background-color-selected-other-month)}.-selected-.-focus-.air-datepicker-cell.-day-.-other-month-,.-selected-.-focus-.air-datepicker-cell.-year-.-other-decade-{background:var(--adp-background-color-selected-other-month-focused)}.-in-range-.air-datepicker-cell.-day-.-other-month-,.-in-range-.air-datepicker-cell.-year-.-other-decade-{background-color:var(--adp-background-color-in-range);color:var(--adp-color)}.-in-range-.-focus-.air-datepicker-cell.-day-.-other-month-,.-in-range-.-focus-.air-datepicker-cell.-year-.-other-decade-{background-color:var(--adp-background-color-in-range-focused)}.air-datepicker-cell.-day-.-other-month-:empty,.air-datepicker-cell.-year-.-other-decade-:empty{background:none;border:none}.air-datepicker-cell{border-radius:var(--adp-cell-border-radius);box-sizing:border-box;cursor:pointer;display:flex;position:relative;align-items:center;justify-content:center;z-index:1}.air-datepicker-cell.-focus-{background:var(--adp-cell-background-color-hover)}.air-datepicker-cell.-current-{color:var(--adp-color-current-date)}.air-datepicker-cell.-current-.-focus-{color:var(--adp-color)}.air-datepicker-cell.-current-.-in-range-{color:var(--adp-color-current-date)}.air-datepicker-cell.-disabled-{cursor:default;color:var(--adp-color-disabled)}.air-datepicker-cell.-disabled-.-focus-{color:var(--adp-color-disabled)}.air-datepicker-cell.-disabled-.-in-range-{color:var(--adp-color-disabled-in-range)}.air-datepicker-cell.-disabled-.-current-.-focus-{color:var(--adp-color-disabled)}.air-datepicker-cell.-in-range-{background:var(--adp-cell-background-color-in-range);border-radius:0}.air-datepicker-cell.-in-range-:hover{background:var(--adp-cell-background-color-in-range-hover)}.air-datepicker-cell.-range-from-{border:1px solid var(--adp-cell-border-color-in-range);background-color:var(--adp-cell-background-color-in-range);border-radius:var(--adp-cell-border-radius) 0 0 var(--adp-cell-border-radius)}.air-datepicker-cell.-range-to-{border:1px solid var(--adp-cell-border-color-in-range);background-color:var(--adp-cell-background-color-in-range);border-radius:0 var(--adp-cell-border-radius) var(--adp-cell-border-radius) 0}.air-datepicker-cell.-range-to-.-range-from-{border-radius:var(--adp-cell-border-radius)}.air-datepicker-cell.-selected-{color:#fff;border:none;background:var(--adp-cell-background-color-selected)}.air-datepicker-cell.-selected-.-current-{color:#fff;background:var(--adp-cell-background-color-selected)}.air-datepicker-cell.-selected-.-focus-{background:var(--adp-cell-background-color-selected-hover)} - -.air-datepicker-body{transition:all var(--adp-transition-duration) var(--adp-transition-ease)}.air-datepicker-body.-hidden-{display:none}.air-datepicker-body--day-names{display:grid;grid-template-columns:repeat(7, var(--adp-day-cell-width));margin:8px 0 3px}.air-datepicker-body--day-name{color:var(--adp-day-name-color);display:flex;align-items:center;justify-content:center;flex:1;text-align:center;text-transform:uppercase;font-size:.8em}.air-datepicker-body--day-name.-clickable-{cursor:pointer}.air-datepicker-body--day-name.-clickable-:hover{color:var(--adp-day-name-color-hover)}.air-datepicker-body--cells{display:grid}.air-datepicker-body--cells.-days-{grid-template-columns:repeat(7, var(--adp-day-cell-width));grid-auto-rows:var(--adp-day-cell-height)}.air-datepicker-body--cells.-months-{grid-template-columns:repeat(3, 1fr);grid-auto-rows:var(--adp-month-cell-height)}.air-datepicker-body--cells.-years-{grid-template-columns:repeat(4, 1fr);grid-auto-rows:var(--adp-year-cell-height)} - -.air-datepicker-nav{display:flex;justify-content:space-between;border-bottom:1px solid var(--adp-border-color-inner);min-height:var(--adp-nav-height);padding:var(--adp-padding);box-sizing:content-box}.-only-timepicker- .air-datepicker-nav{display:none}.air-datepicker-nav--title,.air-datepicker-nav--action{display:flex;cursor:pointer;align-items:center;justify-content:center}.air-datepicker-nav--action{width:var(--adp-nav-action-size);border-radius:var(--adp-border-radius);-webkit-user-select:none;-moz-user-select:none;user-select:none}.air-datepicker-nav--action:hover{background:var(--adp-background-color-hover)}.air-datepicker-nav--action:active{background:var(--adp-background-color-active)}.air-datepicker-nav--action.-disabled-{visibility:hidden}.air-datepicker-nav--action svg{width:32px;height:32px}.air-datepicker-nav--action path{fill:none;stroke:var(--adp-nav-arrow-color);stroke-width:2px}.air-datepicker-nav--title{border-radius:var(--adp-border-radius);padding:0 8px}.air-datepicker-nav--title i{font-style:normal;color:var(--adp-nav-color-secondary);margin-left:.3em}.air-datepicker-nav--title:hover{background:var(--adp-background-color-hover)}.air-datepicker-nav--title:active{background:var(--adp-background-color-active)}.air-datepicker-nav--title.-disabled-{cursor:default;background:none} - -.air-datepicker-buttons{display:grid;grid-auto-columns:1fr;grid-auto-flow:column}.air-datepicker-button{display:inline-flex;color:var(--adp-btn-color);border-radius:var(--adp-btn-border-radius);cursor:pointer;height:var(--adp-btn-height);border:none;background:rgba(255,255,255,0)}.air-datepicker-button:hover{color:var(--adp-btn-color-hover);background:var(--adp-btn-background-color-hover)}.air-datepicker-button:focus{color:var(--adp-btn-color-hover);background:var(--adp-btn-background-color-hover);outline:none}.air-datepicker-button:active{background:var(--adp-btn-background-color-active)}.air-datepicker-button span{outline:none;display:flex;align-items:center;justify-content:center;width:100%;height:100%} - -.air-datepicker-time{display:grid;grid-template-columns:-webkit-max-content 1fr;grid-template-columns:max-content 1fr;grid-column-gap:12px;align-items:center;position:relative;padding:0 var(--adp-time-padding-inner)}.-only-timepicker- .air-datepicker-time{border-top:none}.air-datepicker-time--current{display:flex;align-items:center;flex:1;font-size:14px;text-align:center}.air-datepicker-time--current-colon{margin:0 2px 3px;line-height:1}.air-datepicker-time--current-hours,.air-datepicker-time--current-minutes{line-height:1;font-size:19px;font-family:"Century Gothic", CenturyGothic, AppleGothic, sans-serif;position:relative;z-index:1}.air-datepicker-time--current-hours:after,.air-datepicker-time--current-minutes:after{content:'';background:var(--adp-background-color-hover);border-radius:var(--adp-border-radius);position:absolute;left:-2px;top:-3px;right:-2px;bottom:-2px;z-index:-1;opacity:0}.air-datepicker-time--current-hours.-focus-:after,.air-datepicker-time--current-minutes.-focus-:after{opacity:1}.air-datepicker-time--current-ampm{text-transform:uppercase;align-self:flex-end;color:var(--adp-time-day-period-color);margin-left:6px;font-size:11px;margin-bottom:1px}.air-datepicker-time--row{display:flex;align-items:center;font-size:11px;height:17px;background:linear-gradient(to right, var(--adp-time-track-color), var(--adp-time-track-color)) left 50%/100% var(--adp-time-track-height) no-repeat}.air-datepicker-time--row:first-child{margin-bottom:4px}.air-datepicker-time--row input[type='range']{background:none;cursor:pointer;flex:1;height:100%;width:100%;padding:0;margin:0;-webkit-appearance:none}.air-datepicker-time--row input[type='range']::-webkit-slider-thumb{-webkit-appearance:none}.air-datepicker-time--row input[type='range']::-ms-tooltip{display:none}.air-datepicker-time--row input[type='range']:hover::-webkit-slider-thumb{border-color:var(--adp-time-track-color-hover)}.air-datepicker-time--row input[type='range']:hover::-moz-range-thumb{border-color:var(--adp-time-track-color-hover)}.air-datepicker-time--row input[type='range']:hover::-ms-thumb{border-color:var(--adp-time-track-color-hover)}.air-datepicker-time--row input[type='range']:focus{outline:none}.air-datepicker-time--row input[type='range']:focus::-webkit-slider-thumb{background:var(--adp-cell-background-color-selected);border-color:var(--adp-cell-background-color-selected)}.air-datepicker-time--row input[type='range']:focus::-moz-range-thumb{background:var(--adp-cell-background-color-selected);border-color:var(--adp-cell-background-color-selected)}.air-datepicker-time--row input[type='range']:focus::-ms-thumb{background:var(--adp-cell-background-color-selected);border-color:var(--adp-cell-background-color-selected)}.air-datepicker-time--row input[type='range']::-webkit-slider-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid var(--adp-time-track-color);background:#fff;cursor:pointer;-webkit-transition:background var(--adp-transition-duration);transition:background var(--adp-transition-duration)}.air-datepicker-time--row input[type='range']::-moz-range-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid var(--adp-time-track-color);background:#fff;cursor:pointer;-moz-transition:background var(--adp-transition-duration);transition:background var(--adp-transition-duration)}.air-datepicker-time--row input[type='range']::-ms-thumb{box-sizing:border-box;height:12px;width:12px;border-radius:3px;border:1px solid var(--adp-time-track-color);background:#fff;cursor:pointer;-ms-transition:background var(--adp-transition-duration);transition:background var(--adp-transition-duration)}.air-datepicker-time--row input[type='range']::-webkit-slider-thumb{margin-top:calc(var(--adp-time-thumb-size) / 2 * -1)}.air-datepicker-time--row input[type='range']::-webkit-slider-runnable-track{border:none;height:var(--adp-time-track-height);cursor:pointer;color:transparent;background:transparent}.air-datepicker-time--row input[type='range']::-moz-range-track{border:none;height:var(--adp-time-track-height);cursor:pointer;color:transparent;background:transparent}.air-datepicker-time--row input[type='range']::-ms-track{border:none;height:var(--adp-time-track-height);cursor:pointer;color:transparent;background:transparent}.air-datepicker-time--row input[type='range']::-ms-fill-lower{background:transparent}.air-datepicker-time--row input[type='range']::-ms-fill-upper{background:transparent} - -.air-datepicker{--adp-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--adp-font-size: 14px;--adp-width: 246px;--adp-z-index: 100;--adp-padding: 4px;--adp-grid-areas: - 'nav' - 'body' - 'timepicker' - 'buttons';--adp-transition-duration: .3s;--adp-transition-ease: ease-out;--adp-transition-offset: 8px;--adp-background-color: #fff;--adp-background-color-hover: #f0f0f0;--adp-background-color-active: #eaeaea;--adp-background-color-in-range: rgba(92, 196, 239, .1);--adp-background-color-in-range-focused: rgba(92, 196, 239, .2);--adp-background-color-selected-other-month-focused: #8ad5f4;--adp-background-color-selected-other-month: #a2ddf6;--adp-color: #4a4a4a;--adp-color-secondary: #9c9c9c;--adp-accent-color: #4eb5e6;--adp-color-current-date: var(--adp-accent-color);--adp-color-other-month: #dedede;--adp-color-disabled: #aeaeae;--adp-color-disabled-in-range: #939393;--adp-color-other-month-hover: #c5c5c5;--adp-border-color: #dbdbdb;--adp-border-color-inner: #efefef;--adp-border-radius: 4px;--adp-border-color-inline: #d7d7d7;--adp-nav-height: 32px;--adp-nav-arrow-color: var(--adp-color-secondary);--adp-nav-action-size: 32px;--adp-nav-color-secondary: var(--adp-color-secondary);--adp-day-name-color: #ff9a19;--adp-day-name-color-hover: #8ad5f4;--adp-day-cell-width: 1fr;--adp-day-cell-height: 32px;--adp-month-cell-height: 42px;--adp-year-cell-height: 56px;--adp-pointer-size: 10px;--adp-poiner-border-radius: 2px;--adp-pointer-offset: 14px;--adp-cell-border-radius: 4px;--adp-cell-background-color-hover: var(--adp-background-color-hover);--adp-cell-background-color-selected: #5cc4ef;--adp-cell-background-color-selected-hover: #45bced;--adp-cell-background-color-in-range: rgba(92, 196, 239, 0.1);--adp-cell-background-color-in-range-hover: rgba(92, 196, 239, 0.2);--adp-cell-border-color-in-range: var(--adp-cell-background-color-selected);--adp-btn-height: 32px;--adp-btn-color: var(--adp-accent-color);--adp-btn-color-hover: var(--adp-color);--adp-btn-border-radius: var(--adp-border-radius);--adp-btn-background-color-hover: var(--adp-background-color-hover);--adp-btn-background-color-active: var(--adp-background-color-active);--adp-time-track-height: 1px;--adp-time-track-color: #dedede;--adp-time-track-color-hover: #b1b1b1;--adp-time-thumb-size: 12px;--adp-time-padding-inner: 10px;--adp-time-day-period-color: var(--adp-color-secondary);--adp-mobile-font-size: 16px;--adp-mobile-nav-height: 40px;--adp-mobile-width: 320px;--adp-mobile-day-cell-height: 38px;--adp-mobile-month-cell-height: 48px;--adp-mobile-year-cell-height: 64px}.air-datepicker-overlay{--adp-overlay-background-color: rgba(0, 0, 0, .3);--adp-overlay-transition-duration: .3s;--adp-overlay-transition-ease: ease-out;--adp-overlay-z-index: 99} - -.air-datepicker{background:var(--adp-background-color);border:1px solid var(--adp-border-color);box-shadow:0 4px 12px rgba(0,0,0,0.15);border-radius:var(--adp-border-radius);box-sizing:content-box;display:grid;grid-template-columns:1fr;grid-template-rows:repeat(4, -webkit-max-content);grid-template-rows:repeat(4, max-content);grid-template-areas:var(--adp-grid-areas);font-family:var(--adp-font-family),sans-serif;font-size:var(--adp-font-size);color:var(--adp-color);width:var(--adp-width);position:absolute;transition:opacity var(--adp-transition-duration) var(--adp-transition-ease),transform var(--adp-transition-duration) var(--adp-transition-ease);z-index:var(--adp-z-index)}.air-datepicker:not(.-custom-position-){opacity:0}.air-datepicker.-from-top-{transform:translateY(calc(var(--adp-transition-offset) * -1))}.air-datepicker.-from-right-{transform:translateX(var(--adp-transition-offset))}.air-datepicker.-from-bottom-{transform:translateY(var(--adp-transition-offset))}.air-datepicker.-from-left-{transform:translateX(calc(var(--adp-transition-offset) * -1))}.air-datepicker.-active-:not(.-custom-position-){transform:translate(0, 0);opacity:1}.air-datepicker.-active-.-custom-position-{transition:none}.air-datepicker.-inline-{border-color:var(--adp-border-color-inline);box-shadow:none;position:static;left:auto;right:auto;opacity:1;transform:none}.air-datepicker.-inline- .air-datepicker--pointer{display:none}.air-datepicker.-is-mobile-{--adp-font-size: var(--adp-mobile-font-size);--adp-day-cell-height: var(--adp-mobile-day-cell-height);--adp-month-cell-height: var(--adp-mobile-month-cell-height);--adp-year-cell-height: var(--adp-mobile-year-cell-height);--adp-nav-height: var(--adp-mobile-nav-height);--adp-nav-action-size: var(--adp-mobile-nav-height);position:fixed;width:var(--adp-mobile-width);border:none}.air-datepicker.-is-mobile- *{-webkit-tap-highlight-color:transparent}.air-datepicker.-is-mobile- .air-datepicker--pointer{display:none}.air-datepicker.-is-mobile-:not(.-custom-position-){transform:translate(-50%, calc(-50% + var(--adp-transition-offset)))}.air-datepicker.-is-mobile-.-active-:not(.-custom-position-){transform:translate(-50%, -50%)}.air-datepicker.-custom-position-{transition:none}.air-datepicker-global-container{position:absolute;left:0;top:0}.air-datepicker--pointer{--pointer-half-size: calc(var(--adp-pointer-size) / 2);position:absolute;width:var(--adp-pointer-size);height:var(--adp-pointer-size);z-index:-1}.air-datepicker--pointer:after{content:'';position:absolute;background:#fff;border-top:1px solid var(--adp-border-color-inline);border-right:1px solid var(--adp-border-color-inline);border-top-right-radius:var(--adp-poiner-border-radius);width:var(--adp-pointer-size);height:var(--adp-pointer-size);box-sizing:border-box}.-top-left- .air-datepicker--pointer,.-top-center- .air-datepicker--pointer,.-top-right- .air-datepicker--pointer,[data-popper-placement^='top'] .air-datepicker--pointer{top:calc(100% - var(--pointer-half-size) + 1px)}.-top-left- .air-datepicker--pointer:after,.-top-center- .air-datepicker--pointer:after,.-top-right- .air-datepicker--pointer:after,[data-popper-placement^='top'] .air-datepicker--pointer:after{transform:rotate(135deg)}.-right-top- .air-datepicker--pointer,.-right-center- .air-datepicker--pointer,.-right-bottom- .air-datepicker--pointer,[data-popper-placement^='right'] .air-datepicker--pointer{right:calc(100% - var(--pointer-half-size) + 1px)}.-right-top- .air-datepicker--pointer:after,.-right-center- .air-datepicker--pointer:after,.-right-bottom- .air-datepicker--pointer:after,[data-popper-placement^='right'] .air-datepicker--pointer:after{transform:rotate(225deg)}.-bottom-left- .air-datepicker--pointer,.-bottom-center- .air-datepicker--pointer,.-bottom-right- .air-datepicker--pointer,[data-popper-placement^='bottom'] .air-datepicker--pointer{bottom:calc(100% - var(--pointer-half-size) + 1px)}.-bottom-left- .air-datepicker--pointer:after,.-bottom-center- .air-datepicker--pointer:after,.-bottom-right- .air-datepicker--pointer:after,[data-popper-placement^='bottom'] .air-datepicker--pointer:after{transform:rotate(315deg)}.-left-top- .air-datepicker--pointer,.-left-center- .air-datepicker--pointer,.-left-bottom- .air-datepicker--pointer,[data-popper-placement^='left'] .air-datepicker--pointer{left:calc(100% - var(--pointer-half-size) + 1px)}.-left-top- .air-datepicker--pointer:after,.-left-center- .air-datepicker--pointer:after,.-left-bottom- .air-datepicker--pointer:after,[data-popper-placement^='left'] .air-datepicker--pointer:after{transform:rotate(45deg)}.-top-left- .air-datepicker--pointer,.-bottom-left- .air-datepicker--pointer{left:var(--adp-pointer-offset)}.-top-right- .air-datepicker--pointer,.-bottom-right- .air-datepicker--pointer{right:var(--adp-pointer-offset)}.-top-center- .air-datepicker--pointer,.-bottom-center- .air-datepicker--pointer{left:calc(50% - var(--adp-pointer-size) / 2)}.-left-top- .air-datepicker--pointer,.-right-top- .air-datepicker--pointer{top:var(--adp-pointer-offset)}.-left-bottom- .air-datepicker--pointer,.-right-bottom- .air-datepicker--pointer{bottom:var(--adp-pointer-offset)}.-left-center- .air-datepicker--pointer,.-right-center- .air-datepicker--pointer{top:calc(50% - var(--adp-pointer-size) / 2)}.air-datepicker--navigation{grid-area:nav}.air-datepicker--content{box-sizing:content-box;padding:var(--adp-padding);grid-area:body}.-only-timepicker- .air-datepicker--content{display:none}.air-datepicker--time{grid-area:timepicker}.air-datepicker--buttons{grid-area:buttons}.air-datepicker--buttons,.air-datepicker--time{padding:var(--adp-padding);border-top:1px solid var(--adp-border-color-inner)}.air-datepicker-overlay{position:fixed;background:var(--adp-overlay-background-color);left:0;top:0;width:0;height:0;opacity:0;transition:opacity var(--adp-overlay-transition-duration) var(--adp-overlay-transition-ease),left 0s,height 0s,width 0s;transition-delay:0s,var(--adp-overlay-transition-duration),var(--adp-overlay-transition-duration),var(--adp-overlay-transition-duration);z-index:var(--adp-overlay-z-index)}.air-datepicker-overlay.-active-{opacity:1;width:100%;height:100%;transition:opacity var(--adp-overlay-transition-duration) var(--adp-overlay-transition-ease),height 0s,width 0s} - diff --git a/src/ui/static/css/dashboard.css b/src/ui/static/css/dashboard.css index fc3671cdf..58b6f4c44 100644 --- a/src/ui/static/css/dashboard.css +++ b/src/ui/static/css/dashboard.css @@ -807,6 +807,10 @@ h6 { z-index: 50; } +.-z-10 { + z-index: -10; +} + .order-2 { order: 2; } @@ -831,10 +835,6 @@ h6 { grid-column: span 2 / span 2; } -.col-span-4 { - grid-column: span 4 / span 4; -} - .col-span-9 { grid-column: span 9 / span 9; } @@ -912,11 +912,6 @@ h6 { margin-bottom: 0.25rem; } -.my-auto { - margin-top: auto; - margin-bottom: auto; -} - .my-4 { margin-top: 1rem; margin-bottom: 1rem; @@ -927,9 +922,9 @@ h6 { margin-right: 0.625rem; } -.mx-3 { - margin-left: 0.75rem; - margin-right: 0.75rem; +.mx-4 { + margin-left: 1rem; + margin-right: 1rem; } .my-3 { @@ -937,14 +932,19 @@ h6 { margin-bottom: 0.75rem; } +.mx-3 { + margin-left: 0.75rem; + margin-right: 0.75rem; +} + .my-5 { margin-top: 1.25rem; margin-bottom: 1.25rem; } -.mx-4 { - margin-left: 1rem; - margin-right: 1rem; +.my-6 { + margin-top: 1.5rem; + margin-bottom: 1.5rem; } .mb-1 { @@ -1019,10 +1019,18 @@ h6 { margin-top: 0.25rem; } +.ml-6 { + margin-left: 1.5rem; +} + .mb-4 { margin-bottom: 1rem; } +.mt-2 { + margin-top: 0.5rem; +} + .mt-0 { margin-top: 0px; } @@ -1047,14 +1055,6 @@ h6 { margin-top: 1.5rem; } -.mt-2 { - margin-top: 0.5rem; -} - -.mb-auto { - margin-bottom: auto; -} - .mr-6 { margin-right: 1.5rem; } @@ -1071,14 +1071,14 @@ h6 { margin-left: -1.75rem; } -.ml-6 { - margin-left: 1.5rem; -} - .mb-5 { margin-bottom: 1.25rem; } +.mb-8 { + margin-bottom: 2rem; +} + .box-content { box-sizing: content-box; } @@ -1195,6 +1195,18 @@ h6 { max-height: 25rem; } +.max-h-60 { + max-height: 15rem; +} + +.max-h-16 { + max-height: 4rem; +} + +.max-h-80 { + max-height: 20rem; +} + .max-h-90 { max-height: 22.5rem; } @@ -1203,6 +1215,14 @@ h6 { max-height: 2rem; } +.max-h-30 { + max-height: 7.5rem; +} + +.max-h-135 { + max-height: 33.75rem; +} + .min-h-20 { min-height: 5rem; } @@ -1223,8 +1243,12 @@ h6 { min-height: 13rem; } -.min-h-75-screen { - min-height: 75vh; +.min-h-\[55vh\] { + min-height: 55vh; +} + +.min-h-12 { + min-height: 3rem; } .min-h-75 { @@ -1235,6 +1259,18 @@ h6 { min-height: 85vh; } +.min-h-screen { + min-height: 100vh; +} + +.min-h-90 { + min-height: 22.5rem; +} + +.min-h-80 { + min-height: 20rem; +} + .w-full { width: 100%; } @@ -1307,6 +1343,26 @@ h6 { min-width: 0px; } +.min-w-\[900\] { + min-width: 900; +} + +.min-w-\[900px\] { + min-width: 900px; +} + +.min-w-\[800px\] { + min-width: 800px; +} + +.min-w-\[700px\] { + min-width: 700px; +} + +.min-w-\[750px\] { + min-width: 750px; +} + .max-w-screen-sm { max-width: 576px; } @@ -1319,6 +1375,10 @@ h6 { max-width: 10rem; } +.max-w-120 { + max-width: 30rem; +} + .max-w-64 { max-width: 16rem; } @@ -1335,6 +1395,22 @@ h6 { max-width: 300px; } +.max-w-60 { + max-width: 15rem; +} + +.max-w-\[460px\] { + max-width: 460px; +} + +.max-w-\[40px\] { + max-width: 40px; +} + +.max-w-\[400px\] { + max-width: 400px; +} + .flex-auto { flex: 1 1 auto; } @@ -1487,6 +1563,10 @@ h6 { resize: both; } +.scroll-m-4 { + scroll-margin: 1rem; +} + .list-none { list-style-type: none; } @@ -1509,10 +1589,6 @@ h6 { grid-template-columns: repeat(2, minmax(0, 1fr)); } -.flex-row { - flex-direction: row; -} - .flex-col { flex-direction: column; } @@ -1570,11 +1646,6 @@ h6 { row-gap: 0.5rem; } -.gap-x-1 { - -moz-column-gap: 0.25rem; - column-gap: 0.25rem; -} - .overflow-auto { overflow: auto; } @@ -1583,6 +1654,14 @@ h6 { overflow: hidden; } +.overflow-scroll { + overflow: scroll; +} + +.overflow-x-auto { + overflow-x: auto; +} + .overflow-y-auto { overflow-y: auto; } @@ -1591,6 +1670,14 @@ h6 { overflow-x: hidden; } +.overflow-x-scroll { + overflow-x: scroll; +} + +.overflow-y-scroll { + overflow-y: scroll; +} + .whitespace-nowrap { white-space: nowrap; } @@ -1816,6 +1903,10 @@ h6 { --tw-bg-opacity: 0; } +.bg-gradient-to-tl { + background-image: linear-gradient(to top left, var(--tw-gradient-stops)); +} + .bg-gradient-to-r { background-image: linear-gradient(to right, var(--tw-gradient-stops)); } @@ -1824,10 +1915,6 @@ h6 { background-image: none; } -.bg-gradient-to-tl { - background-image: linear-gradient(to top left, var(--tw-gradient-stops)); -} - .from-transparent { --tw-gradient-from: transparent; --tw-gradient-to: rgb(0 0 0 / 0); @@ -1951,6 +2038,10 @@ h6 { fill: #047857; } +.fill-amber-500 { + fill: #f59e0b; +} + .fill-slate-800 { fill: #3a416f; } @@ -1988,6 +2079,10 @@ h6 { padding: 1.5rem; } +.p-12 { + padding: 3rem; +} + .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -2073,6 +2168,16 @@ h6 { padding-bottom: 1.25rem; } +.px-12 { + padding-left: 3rem; + padding-right: 3rem; +} + +.py-16 { + padding-top: 4rem; + padding-bottom: 4rem; +} + .pb-0 { padding-bottom: 0px; } @@ -2109,10 +2214,6 @@ h6 { padding-bottom: 0.5rem; } -.pt-5 { - padding-top: 1.25rem; -} - .pl-6 { padding-left: 1.5rem; } @@ -2149,6 +2250,10 @@ h6 { padding-left: 1.75rem; } +.pt-5 { + padding-top: 1.25rem; +} + .text-left { text-align: left; } @@ -2717,6 +2822,10 @@ h6 { background-color: rgb(251 177 64 / 0.8); } +.hover\:bg-primary\/80:hover { + background-color: rgb(8 85 119 / 0.8); +} + .hover\:bg-primary\/30:hover { background-color: rgb(8 85 119 / 0.3); } @@ -2730,10 +2839,6 @@ h6 { background-color: rgb(248 249 250 / var(--tw-bg-opacity)); } -.hover\:bg-primary\/80:hover { - background-color: rgb(8 85 119 / 0.8); -} - .hover\:opacity-80:hover { opacity: 0.8; } @@ -3065,10 +3170,23 @@ h6 { grid-column: span 1 / span 1; } + .sm\:col-span-2 { + grid-column: span 2 / span 2; + } + + .sm\:col-span-8 { + grid-column: span 8 / span 8; + } + .sm\:col-start-5 { grid-column-start: 5; } + .sm\:my-0 { + margin-top: 0px; + margin-bottom: 0px; + } + .sm\:mx-6 { margin-left: 1.5rem; margin-right: 1.5rem; @@ -3087,6 +3205,10 @@ h6 { margin-right: 4rem; } + .sm\:block { + display: block; + } + .sm\:hidden { display: none; } @@ -3107,6 +3229,22 @@ h6 { max-height: 7rem; } + .sm\:max-h-0 { + max-height: 0px; + } + + .sm\:max-h-120 { + max-height: 30rem; + } + + .sm\:max-h-135 { + max-height: 33.75rem; + } + + .sm\:max-h-125 { + max-height: 31.25rem; + } + .sm\:w-80 { width: 20rem; } @@ -3170,6 +3308,18 @@ h6 { grid-column: span 6 / span 6; } + .md\:col-span-5 { + grid-column: span 5 / span 5; + } + + .md\:col-span-7 { + grid-column: span 7 / span 7; + } + + .md\:col-span-1 { + grid-column: span 1 / span 1; + } + .md\:my-0 { margin-top: 0px; margin-bottom: 0px; @@ -3209,10 +3359,18 @@ h6 { display: none; } + .md\:max-h-160 { + max-height: 40rem; + } + .md\:min-h-75-screen { min-height: 75vh; } + .md\:min-h-50-screen { + min-height: 50vh; + } + .md\:w-1\/2 { width: 50%; } @@ -3221,6 +3379,11 @@ h6 { justify-content: flex-end; } + .md\:bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + } + .md\:py-4 { padding-top: 1rem; padding-bottom: 1rem; @@ -3248,6 +3411,10 @@ h6 { } @media (min-width: 992px) { + .lg\:relative { + position: relative; + } + .lg\:order-1 { order: 1; } @@ -3268,16 +3435,16 @@ h6 { grid-column: span 12 / span 12; } - .lg\:col-span-9 { - grid-column: span 9 / span 9; + .lg\:col-span-8 { + grid-column: span 8 / span 8; } .lg\:col-span-3 { grid-column: span 3 / span 3; } - .lg\:col-span-8 { - grid-column: span 8 / span 8; + .lg\:col-span-1 { + grid-column: span 1 / span 1; } .lg\:mx-8 { @@ -3298,6 +3465,18 @@ h6 { margin-bottom: 0px; } + .lg\:block { + display: block; + } + + .lg\:flex { + display: flex; + } + + .lg\:hidden { + display: none; + } + .lg\:h-9 { height: 2.25rem; } @@ -3342,14 +3521,25 @@ h6 { justify-content: space-between; } - .lg\:justify-items-start { - justify-items: start; - } - .lg\:gap-6 { gap: 1.5rem; } + .lg\:bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + } + + .lg\:bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(235 239 244 / var(--tw-bg-opacity)); + } + + .lg\:bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(248 249 250 / var(--tw-bg-opacity)); + } + .lg\:text-left { text-align: left; } @@ -3452,4 +3642,13 @@ h6 { .\33xl\:col-span-4 { grid-column: span 4 / span 4; } + + .\33xl\:col-span-2 { + grid-column: span 2 / span 2; + } +} + +.\[\&\>\*\]\:bg-primary>* { + --tw-bg-opacity: 1; + background-color: rgb(8 85 119 / var(--tw-bg-opacity)); } diff --git a/src/ui/static/css/datepicker-foundation.css b/src/ui/static/css/datepicker-foundation.css new file mode 100644 index 000000000..eb16026cf --- /dev/null +++ b/src/ui/static/css/datepicker-foundation.css @@ -0,0 +1,275 @@ +.datepicker { + display: none; +} + +.datepicker.active { + display: block; +} + +.datepicker-dropdown { + position: absolute; + top: 0; + left: 0; + z-index: 10; + padding-top: 4px; +} + +.datepicker-dropdown.datepicker-orient-top { + padding-top: 0; + padding-bottom: 4px; +} + +.datepicker-picker { + display: inline-block; + border-radius: 0; + background-color: #fefefe; +} + +.datepicker-dropdown .datepicker-picker { + box-shadow: 0 0 0 1px #cacaca; +} + +.datepicker-picker span { + display: block; + flex: 1; + border: 0; + border-radius: 0; + cursor: default; + text-align: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.datepicker-main { + padding: 2px; +} + +.datepicker-footer { + box-shadow: inset 0 1px 1px rgba(10, 10, 10, 0.1); + background-color: #e6e6e6; +} + +.datepicker-grid, +.datepicker-view .days-of-week, +.datepicker-view, +.datepicker-controls { + display: flex; +} + +.datepicker-grid { + flex-wrap: wrap; +} + +.datepicker-view .days .datepicker-cell, +.datepicker-view .dow { + flex-basis: 14.2857142857%; +} + +.datepicker-view.datepicker-grid .datepicker-cell { + flex-basis: 25%; +} + +.datepicker-cell, +.datepicker-view .week { + height: 2.25rem; + line-height: 2.25rem; +} + +.datepicker-title { + box-shadow: inset 0 -1px 1px rgba(10, 10, 10, 0.1); + background-color: #e6e6e6; + padding: 0.375rem 0.75rem; + text-align: center; + font-weight: bold; +} + +.datepicker-header .datepicker-controls { + padding: 2px 2px 0; +} + +.datepicker-controls .button { + margin: 0; + background-color: #fefefe; + color: #0a0a0a; +} + +.datepicker-controls .button:hover, +.datepicker-controls .button:focus { + background-color: #d8d8d8; +} + +.datepicker-controls .button:hover[disabled], +.datepicker-controls .button:focus[disabled] { + opacity: 0.25; + background-color: #fefefe; + color: #0a0a0a; +} + +.datepicker-header .datepicker-controls .button { + border-color: transparent; + font-weight: bold; +} + +.datepicker-footer .datepicker-controls .button { + margin: calc(0.375rem - 1px) 0.375rem; + border-radius: 0; + width: 100%; + font-size: 0.75rem; +} + +.datepicker-controls .view-switch { + flex: auto; +} + +.datepicker-controls .prev-btn, +.datepicker-controls .next-btn { + padding-right: 0.375rem; + padding-left: 0.375rem; + width: 2.25rem; +} + +.datepicker-controls .prev-btn.disabled, +.datepicker-controls .next-btn.disabled { + visibility: hidden; +} + +.datepicker-view .dow { + height: 1.5rem; + line-height: 1.5rem; + font-size: 0.875rem; + font-weight: bold; +} + +.datepicker-view .week { + width: 2.25rem; + color: #8a8a8a; + font-size: 0.75rem; +} + +@media (max-width: 22.5rem) { + .datepicker-view .week { + width: 1.96875rem; + } +} + +.datepicker-grid { + width: 15.75rem; +} + +@media (max-width: 22.5rem) { + .calendar-weeks + .days .datepicker-grid { + width: 13.78125rem; + } +} + +.datepicker-cell:not(.disabled):hover { + background-color: #f8f8f8; + cursor: pointer; +} + +.datepicker-cell.focused:not(.selected) { + background-color: #f1f1f1; +} + +.datepicker-cell.selected, +.datepicker-cell.selected:hover { + background-color: #1779ba; + color: #fefefe; + font-weight: semibold; +} + +.datepicker-cell.disabled { + color: #e6e6e6; +} + +.datepicker-cell.prev:not(.disabled), +.datepicker-cell.next:not(.disabled) { + color: #cacaca; +} + +.datepicker-cell.prev.selected, +.datepicker-cell.next.selected { + color: #e5e5e5; +} + +.datepicker-cell.highlighted:not(.selected):not(.range):not(.today) { + border-radius: 0; + background-color: #f7f7f7; +} + +.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover { + background-color: #f1f1f1; +} + +.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused { + background-color: #f1f1f1; +} + +.datepicker-cell.today:not(.selected) { + background-color: #d7ecfa; +} + +.datepicker-cell.today:not(.selected):not(.disabled) { + color: #8a8a8a; +} + +.datepicker-cell.today.focused:not(.selected) { + background-color: #cbe7f9; +} + +.datepicker-cell.range-end:not(.selected), +.datepicker-cell.range-start:not(.selected) { + background-color: #767676; + color: #fefefe; +} + +.datepicker-cell.range-end.focused:not(.selected), +.datepicker-cell.range-start.focused:not(.selected) { + background-color: #707070; +} + +.datepicker-cell.range-start { + border-radius: 0 0 0 0; +} + +.datepicker-cell.range-end { + border-radius: 0 0 0 0; +} + +.datepicker-cell.range { + border-radius: 0; + background-color: #e6e6e6; +} + +.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover { + background-color: #e0e0e0; +} + +.datepicker-cell.range.disabled { + color: #cdcdcd; +} + +.datepicker-cell.range.focused { + background-color: #d9d9d9; +} + +.datepicker-cell.range.today { + background-color: #b3dbf6; +} + +.datepicker-view.datepicker-grid .datepicker-cell { + height: 4.5rem; + line-height: 4.5rem; +} + +.datepicker-input.in-edit { + border-color: #a4a4a4; +} + +.datepicker-input.in-edit:focus, +.datepicker-input.in-edit:active { + box-shadow: 0 0 0.25em 0.25em rgba(164, 164, 164, 0.2); +} \ No newline at end of file diff --git a/src/ui/static/css/datepicker-foundation.min.css b/src/ui/static/css/datepicker-foundation.min.css new file mode 100644 index 000000000..8465be876 --- /dev/null +++ b/src/ui/static/css/datepicker-foundation.min.css @@ -0,0 +1 @@ +.datepicker{display:none}.datepicker.active{display:block}.datepicker-dropdown{left:0;padding-top:4px;position:absolute;top:0;z-index:10}.datepicker-dropdown.datepicker-orient-top{padding-bottom:4px;padding-top:0}.datepicker-picker{background-color:#fefefe;border-radius:0;display:inline-block}.datepicker-dropdown .datepicker-picker{box-shadow:0 0 0 1px #cacaca}.datepicker-picker span{-webkit-touch-callout:none;border:0;border-radius:0;cursor:default;display:block;flex:1;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.datepicker-main{padding:2px}.datepicker-footer{background-color:#e6e6e6;box-shadow:inset 0 1px 1px hsla(0,0%,4%,.1)}.datepicker-controls,.datepicker-grid,.datepicker-view,.datepicker-view .days-of-week{display:flex}.datepicker-grid{flex-wrap:wrap}.datepicker-view .days .datepicker-cell,.datepicker-view .dow{flex-basis:14.2857142857%}.datepicker-view.datepicker-grid .datepicker-cell{flex-basis:25%}.datepicker-cell,.datepicker-view .week{height:2.25rem;line-height:2.25rem}.datepicker-title{background-color:#e6e6e6;box-shadow:inset 0 -1px 1px hsla(0,0%,4%,.1);font-weight:700;padding:.375rem .75rem;text-align:center}.datepicker-header .datepicker-controls{padding:2px 2px 0}.datepicker-controls .button{background-color:#fefefe;color:#0a0a0a;margin:0}.datepicker-controls .button:focus,.datepicker-controls .button:hover{background-color:#d8d8d8}.datepicker-controls .button:focus[disabled],.datepicker-controls .button:hover[disabled]{background-color:#fefefe;color:#0a0a0a;opacity:.25}.datepicker-header .datepicker-controls .button{border-color:transparent;font-weight:700}.datepicker-footer .datepicker-controls .button{border-radius:0;font-size:.75rem;margin:calc(.375rem - 1px) .375rem;width:100%}.datepicker-controls .view-switch{flex:auto}.datepicker-controls .next-btn,.datepicker-controls .prev-btn{padding-left:.375rem;padding-right:.375rem;width:2.25rem}.datepicker-controls .next-btn.disabled,.datepicker-controls .prev-btn.disabled{visibility:hidden}.datepicker-view .dow{font-size:.875rem;font-weight:700;height:1.5rem;line-height:1.5rem}.datepicker-view .week{color:#8a8a8a;font-size:.75rem;width:2.25rem}@media (max-width:22.5rem){.datepicker-view .week{width:1.96875rem}}.datepicker-grid{width:15.75rem}@media (max-width:22.5rem){.calendar-weeks+.days .datepicker-grid{width:13.78125rem}}.datepicker-cell:not(.disabled):hover{background-color:#f8f8f8;cursor:pointer}.datepicker-cell.focused:not(.selected){background-color:#f1f1f1}.datepicker-cell.selected,.datepicker-cell.selected:hover{background-color:#1779ba;color:#fefefe;font-weight:semibold}.datepicker-cell.disabled{color:#e6e6e6}.datepicker-cell.next:not(.disabled),.datepicker-cell.prev:not(.disabled){color:#cacaca}.datepicker-cell.next.selected,.datepicker-cell.prev.selected{color:#e5e5e5}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today){background-color:#f7f7f7;border-radius:0}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused,.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover{background-color:#f1f1f1}.datepicker-cell.today:not(.selected){background-color:#d7ecfa}.datepicker-cell.today:not(.selected):not(.disabled){color:#8a8a8a}.datepicker-cell.today.focused:not(.selected){background-color:#cbe7f9}.datepicker-cell.range-end:not(.selected),.datepicker-cell.range-start:not(.selected){background-color:#767676;color:#fefefe}.datepicker-cell.range-end.focused:not(.selected),.datepicker-cell.range-start.focused:not(.selected){background-color:#707070}.datepicker-cell.range-end,.datepicker-cell.range-start{border-radius:0 0 0 0}.datepicker-cell.range{background-color:#e6e6e6;border-radius:0}.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover{background-color:#e0e0e0}.datepicker-cell.range.disabled{color:#cdcdcd}.datepicker-cell.range.focused{background-color:#d9d9d9}.datepicker-cell.range.today{background-color:#b3dbf6}.datepicker-view.datepicker-grid .datepicker-cell{height:4.5rem;line-height:4.5rem}.datepicker-input.in-edit{border-color:#a4a4a4}.datepicker-input.in-edit:active,.datepicker-input.in-edit:focus{box-shadow:0 0 .25em .25em hsla(0,0%,64%,.2)} \ No newline at end of file diff --git a/src/ui/static/css/datepicker.css b/src/ui/static/css/datepicker.css new file mode 100644 index 000000000..e51ff9c14 --- /dev/null +++ b/src/ui/static/css/datepicker.css @@ -0,0 +1,318 @@ +.datepicker { + display: none; +} + +.datepicker.active { + display: block; +} + +.datepicker-dropdown { + position: absolute; + top: 0; + left: 0; + z-index: 20; + padding-top: 4px; +} + +.datepicker-dropdown.datepicker-orient-top { + padding-top: 0; + padding-bottom: 4px; +} + +.datepicker-picker { + display: inline-block; + border-radius: 4px; + background-color: white; +} + +.datepicker-dropdown .datepicker-picker { + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); +} + +.datepicker-picker span { + display: block; + flex: 1; + border: 0; + border-radius: 4px; + cursor: default; + text-align: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.datepicker-main { + padding: 2px; +} + +.datepicker-footer { + box-shadow: inset 0 1px 1px rgba(10, 10, 10, 0.1); + background-color: whitesmoke; +} + +.datepicker-grid, +.datepicker-view .days-of-week, +.datepicker-view, +.datepicker-controls { + display: flex; +} + +.datepicker-grid { + flex-wrap: wrap; +} + +.datepicker-view .days .datepicker-cell, +.datepicker-view .dow { + flex-basis: 14.2857142857%; +} + +.datepicker-view.datepicker-grid .datepicker-cell { + flex-basis: 25%; +} + +.datepicker-cell, +.datepicker-view .week { + height: 2.25rem; + line-height: 2.25rem; +} + +.datepicker-title { + box-shadow: inset 0 -1px 1px rgba(10, 10, 10, 0.1); + background-color: whitesmoke; + padding: 0.375rem 0.75rem; + text-align: center; + font-weight: 700; +} + +.datepicker-header .datepicker-controls { + padding: 2px 2px 0; +} + +.datepicker-controls .button { + display: inline-flex; + position: relative; + align-items: center; + justify-content: center; + margin: 0; + border: 1px solid #dbdbdb; + border-radius: 4px; + box-shadow: none; + background-color: white; + cursor: pointer; + padding: calc(0.375em - 1px) 0.75em; + height: 2.25em; + vertical-align: top; + text-align: center; + line-height: 1.5; + white-space: nowrap; + color: #363636; + font-size: 1rem; +} + +.datepicker-controls .button:focus, +.datepicker-controls .button:active { + outline: none; +} + +.datepicker-controls .button:hover { + border-color: #b5b5b5; + color: #363636; +} + +.datepicker-controls .button:focus { + border-color: #3273dc; + color: #363636; +} + +.datepicker-controls .button:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); +} + +.datepicker-controls .button:active { + border-color: #4a4a4a; + color: #363636; +} + +.datepicker-controls .button[disabled] { + cursor: not-allowed; +} + +.datepicker-header .datepicker-controls .button { + border-color: transparent; + font-weight: bold; +} + +.datepicker-header .datepicker-controls .button:hover { + background-color: #f9f9f9; +} + +.datepicker-header .datepicker-controls .button:focus:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); +} + +.datepicker-header .datepicker-controls .button:active { + background-color: #f2f2f2; +} + +.datepicker-header .datepicker-controls .button[disabled] { + box-shadow: none; +} + +.datepicker-footer .datepicker-controls .button { + margin: calc(0.375rem - 1px) 0.375rem; + border-radius: 2px; + width: 100%; + font-size: 0.75rem; +} + +.datepicker-controls .view-switch { + flex: auto; +} + +.datepicker-controls .prev-btn, +.datepicker-controls .next-btn { + padding-right: 0.375rem; + padding-left: 0.375rem; + width: 2.25rem; +} + +.datepicker-controls .prev-btn.disabled, +.datepicker-controls .next-btn.disabled { + visibility: hidden; +} + +.datepicker-view .dow { + height: 1.5rem; + line-height: 1.5rem; + font-size: 0.875rem; + font-weight: 700; +} + +.datepicker-view .week { + width: 2.25rem; + color: #b5b5b5; + font-size: 0.75rem; +} + +@media (max-width: 22.5rem) { + .datepicker-view .week { + width: 1.96875rem; + } +} + +.datepicker-grid { + width: 15.75rem; +} + +@media (max-width: 22.5rem) { + .calendar-weeks + .days .datepicker-grid { + width: 13.78125rem; + } +} + +.datepicker-cell:not(.disabled):hover { + background-color: #f9f9f9; + cursor: pointer; +} + +.datepicker-cell.focused:not(.selected) { + background-color: #e8e8e8; +} + +.datepicker-cell.selected, +.datepicker-cell.selected:hover { + background-color: #3273dc; + color: #fff; + font-weight: 600; +} + +.datepicker-cell.disabled { + color: #dbdbdb; +} + +.datepicker-cell.prev:not(.disabled), +.datepicker-cell.next:not(.disabled) { + color: #7a7a7a; +} + +.datepicker-cell.prev.selected, +.datepicker-cell.next.selected { + color: #e6e6e6; +} + +.datepicker-cell.highlighted:not(.selected):not(.range):not(.today) { + border-radius: 0; + background-color: whitesmoke; +} + +.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover { + background-color: #eeeeee; +} + +.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused { + background-color: #e8e8e8; +} + +.datepicker-cell.today:not(.selected) { + background-color: #00d1b2; +} + +.datepicker-cell.today:not(.selected):not(.disabled) { + color: #fff; +} + +.datepicker-cell.today.focused:not(.selected) { + background-color: #00c4a7; +} + +.datepicker-cell.range-end:not(.selected), +.datepicker-cell.range-start:not(.selected) { + background-color: #b5b5b5; + color: #fff; +} + +.datepicker-cell.range-end.focused:not(.selected), +.datepicker-cell.range-start.focused:not(.selected) { + background-color: #afafaf; +} + +.datepicker-cell.range-start { + border-radius: 4px 0 0 4px; +} + +.datepicker-cell.range-end { + border-radius: 0 4px 4px 0; +} + +.datepicker-cell.range { + border-radius: 0; + background-color: #dbdbdb; +} + +.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover { + background-color: #d5d5d5; +} + +.datepicker-cell.range.disabled { + color: #c2c2c2; +} + +.datepicker-cell.range.focused { + background-color: #cfcfcf; +} + +.datepicker-view.datepicker-grid .datepicker-cell { + height: 4.5rem; + line-height: 4.5rem; +} + +.datepicker-input.in-edit { + border-color: #2366d1; +} + +.datepicker-input.in-edit:focus, +.datepicker-input.in-edit:active { + box-shadow: 0 0 0.25em 0.25em rgba(35, 102, 209, 0.2); +} \ No newline at end of file diff --git a/src/ui/static/css/datepicker.min.css b/src/ui/static/css/datepicker.min.css new file mode 100644 index 000000000..c2cfa6802 --- /dev/null +++ b/src/ui/static/css/datepicker.min.css @@ -0,0 +1 @@ +.datepicker{display:none}.datepicker.active{display:block}.datepicker-dropdown{left:0;padding-top:4px;position:absolute;top:0;z-index:20}.datepicker-dropdown.datepicker-orient-top{padding-bottom:4px;padding-top:0}.datepicker-picker{background-color:#fff;border-radius:4px;display:inline-block}.datepicker-dropdown .datepicker-picker{box-shadow:0 2px 3px hsla(0,0%,4%,.1),0 0 0 1px hsla(0,0%,4%,.1)}.datepicker-picker span{-webkit-touch-callout:none;border:0;border-radius:4px;cursor:default;display:block;flex:1;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.datepicker-main{padding:2px}.datepicker-footer{background-color:#f5f5f5;box-shadow:inset 0 1px 1px hsla(0,0%,4%,.1)}.datepicker-controls,.datepicker-grid,.datepicker-view,.datepicker-view .days-of-week{display:flex}.datepicker-grid{flex-wrap:wrap}.datepicker-view .days .datepicker-cell,.datepicker-view .dow{flex-basis:14.2857142857%}.datepicker-view.datepicker-grid .datepicker-cell{flex-basis:25%}.datepicker-cell,.datepicker-view .week{height:2.25rem;line-height:2.25rem}.datepicker-title{background-color:#f5f5f5;box-shadow:inset 0 -1px 1px hsla(0,0%,4%,.1);font-weight:700;padding:.375rem .75rem;text-align:center}.datepicker-header .datepicker-controls{padding:2px 2px 0}.datepicker-controls .button{align-items:center;background-color:#fff;border:1px solid #dbdbdb;border-radius:4px;box-shadow:none;color:#363636;cursor:pointer;display:inline-flex;font-size:1rem;height:2.25em;justify-content:center;line-height:1.5;margin:0;padding:calc(.375em - 1px) .75em;position:relative;text-align:center;vertical-align:top;white-space:nowrap}.datepicker-controls .button:active,.datepicker-controls .button:focus{outline:none}.datepicker-controls .button:hover{border-color:#b5b5b5;color:#363636}.datepicker-controls .button:focus{border-color:#3273dc;color:#363636}.datepicker-controls .button:focus:not(:active){box-shadow:0 0 0 .125em rgba(50,115,220,.25)}.datepicker-controls .button:active{border-color:#4a4a4a;color:#363636}.datepicker-controls .button[disabled]{cursor:not-allowed}.datepicker-header .datepicker-controls .button{border-color:transparent;font-weight:700}.datepicker-header .datepicker-controls .button:hover{background-color:#f9f9f9}.datepicker-header .datepicker-controls .button:focus:not(:active){box-shadow:0 0 0 .125em hsla(0,0%,100%,.25)}.datepicker-header .datepicker-controls .button:active{background-color:#f2f2f2}.datepicker-header .datepicker-controls .button[disabled]{box-shadow:none}.datepicker-footer .datepicker-controls .button{border-radius:2px;font-size:.75rem;margin:calc(.375rem - 1px) .375rem;width:100%}.datepicker-controls .view-switch{flex:auto}.datepicker-controls .next-btn,.datepicker-controls .prev-btn{padding-left:.375rem;padding-right:.375rem;width:2.25rem}.datepicker-controls .next-btn.disabled,.datepicker-controls .prev-btn.disabled{visibility:hidden}.datepicker-view .dow{font-size:.875rem;font-weight:700;height:1.5rem;line-height:1.5rem}.datepicker-view .week{color:#b5b5b5;font-size:.75rem;width:2.25rem}@media (max-width:22.5rem){.datepicker-view .week{width:1.96875rem}}.datepicker-grid{width:15.75rem}@media (max-width:22.5rem){.calendar-weeks+.days .datepicker-grid{width:13.78125rem}}.datepicker-cell:not(.disabled):hover{background-color:#f9f9f9;cursor:pointer}.datepicker-cell.focused:not(.selected){background-color:#e8e8e8}.datepicker-cell.selected,.datepicker-cell.selected:hover{background-color:#3273dc;color:#fff;font-weight:600}.datepicker-cell.disabled{color:#dbdbdb}.datepicker-cell.next:not(.disabled),.datepicker-cell.prev:not(.disabled){color:#7a7a7a}.datepicker-cell.next.selected,.datepicker-cell.prev.selected{color:#e6e6e6}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today){background-color:#f5f5f5;border-radius:0}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover{background-color:#eee}.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused{background-color:#e8e8e8}.datepicker-cell.today:not(.selected){background-color:#00d1b2}.datepicker-cell.today:not(.selected):not(.disabled){color:#fff}.datepicker-cell.today.focused:not(.selected){background-color:#00c4a7}.datepicker-cell.range-end:not(.selected),.datepicker-cell.range-start:not(.selected){background-color:#b5b5b5;color:#fff}.datepicker-cell.range-end.focused:not(.selected),.datepicker-cell.range-start.focused:not(.selected){background-color:#afafaf}.datepicker-cell.range-start{border-radius:4px 0 0 4px}.datepicker-cell.range-end{border-radius:0 4px 4px 0}.datepicker-cell.range{background-color:#dbdbdb;border-radius:0}.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover{background-color:#d5d5d5}.datepicker-cell.range.disabled{color:#c2c2c2}.datepicker-cell.range.focused{background-color:#cfcfcf}.datepicker-view.datepicker-grid .datepicker-cell{height:4.5rem;line-height:4.5rem}.datepicker-input.in-edit{border-color:#2366d1}.datepicker-input.in-edit:active,.datepicker-input.in-edit:focus{box-shadow:0 0 .25em .25em rgba(35,102,209,.2)} \ No newline at end of file diff --git a/src/ui/static/css/dropzone/basic.css b/src/ui/static/css/dropzone/basic.css deleted file mode 100644 index f8be93ce1..000000000 --- a/src/ui/static/css/dropzone/basic.css +++ /dev/null @@ -1 +0,0 @@ -.dropzone,.dropzone *{box-sizing:border-box}.dropzone{position:relative}.dropzone .dz-preview{position:relative;display:inline-block;width:120px;margin:.5em}.dropzone .dz-preview .dz-progress{display:block;height:15px;border:1px solid #aaa}.dropzone .dz-preview .dz-progress .dz-upload{display:block;height:100%;width:0;background:green}.dropzone .dz-preview .dz-error-message{color:red;display:none}.dropzone .dz-preview.dz-error .dz-error-message,.dropzone .dz-preview.dz-error .dz-error-mark{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{display:block}.dropzone .dz-preview .dz-error-mark,.dropzone .dz-preview .dz-success-mark{position:absolute;display:none;left:30px;top:30px;width:54px;height:58px;left:50%;margin-left:-27px}/*# sourceMappingURL=basic.css.map */ diff --git a/src/ui/static/css/dropzone/dropzone.css b/src/ui/static/css/dropzone/dropzone.css index 569ac4484..60f2be9e1 100644 --- a/src/ui/static/css/dropzone/dropzone.css +++ b/src/ui/static/css/dropzone/dropzone.css @@ -1 +1,274 @@ -@keyframes passing-through{0%{opacity:0;transform:translateY(40px)}30%,70%{opacity:1;transform:translateY(0px)}100%{opacity:0;transform:translateY(-40px)}}@keyframes slide-in{0%{opacity:0;transform:translateY(40px)}30%{opacity:1;transform:translateY(0px)}}@keyframes pulse{0%{transform:scale(1)}10%{transform:scale(1.1)}20%{transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:1px solid rgba(0,0,0,.8);border-radius:5px;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:.5}.dropzone .dz-message{text-align:center;margin:3em 0}.dropzone .dz-message .dz-button{background:none;color:inherit;border:none;padding:0;font:inherit;cursor:pointer;outline:inherit}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:#fff}.dropzone .dz-preview.dz-image-preview .dz-details{transition:opacity .2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,.8);background-color:rgba(255,255,255,.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,.4);padding:0 .4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{transform:scale(1.05, 1.05);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px;background:rgba(0,0,0,.8);border-radius:50%}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px;fill:#fff}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;transition:all .2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;transition:opacity .4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:20px;top:50%;margin-top:-10px;left:15%;right:15%;border:3px solid rgba(0,0,0,.8);background:rgba(0,0,0,.8);border-radius:10px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#fff;display:block;position:relative;height:100%;width:0;transition:width 300ms ease-in-out;border-radius:17px}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;transition:opacity .3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#b10606;padding:.5em 1em;color:#fff}.dropzone .dz-preview .dz-error-message:after{content:"";position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #b10606}/*# sourceMappingURL=dropzone.css.map */ +/*# sourceMappingURL=basic.css.map */ +@keyframes passing-through { + 0% { + opacity: 0; + transform: translateY(40px); + } + 30%, + 70% { + opacity: 1; + transform: translateY(0px); + } + 100% { + opacity: 0; + transform: translateY(-40px); + } +} +@keyframes slide-in { + 0% { + opacity: 0; + transform: translateY(40px); + } + 30% { + opacity: 1; + transform: translateY(0px); + } +} +@keyframes pulse { + 0% { + transform: scale(1); + } + 10% { + transform: scale(1.1); + } + 20% { + transform: scale(1); + } +} +.dropzone, +.dropzone * { + box-sizing: border-box; +} +.dropzone { + min-height: 100px; + border: 1px solid rgba(0, 0, 0, 0.8); + border-radius: 5px; + padding: 0; +} +.dropzone.dz-clickable { + cursor: pointer; +} +.dropzone.dz-clickable * { + cursor: default; +} +.dropzone.dz-clickable .dz-message, +.dropzone.dz-clickable .dz-message * { + cursor: pointer; +} +.dropzone.dz-started .dz-message { + display: none; +} +.dropzone.dz-drag-hover { + border-style: solid; +} +.dropzone.dz-drag-hover .dz-message { + opacity: 0.5; +} +.dropzone .dz-message { + text-align: center; + margin: 0; + display: flex; + justify-content: center; + align-items: center; +} +.dropzone .dz-message .dz-button { + background: none; + color: inherit; + border: none; + padding: 0; + font: inherit; + cursor: pointer; + outline: inherit; +} +.dropzone .dz-preview { + position: relative; + display: inline-block; + vertical-align: top; + margin: 12px; + min-height: 100px; +} +.dropzone .dz-preview:hover { + z-index: 1000; +} +.dropzone .dz-preview:hover .dz-details { + opacity: 1; +} +.dropzone .dz-preview.dz-file-preview .dz-image { + border-radius: 20px; + background: #999; + background: linear-gradient(to bottom, #eee, #ddd); +} +.dropzone .dz-preview.dz-file-preview .dz-details { + opacity: 1; +} +.dropzone .dz-preview.dz-image-preview { + background: #fff; +} +.dropzone .dz-preview.dz-image-preview .dz-details { + transition: opacity 0.2s linear; +} +.dropzone .dz-preview .dz-remove { + font-size: 14px; + text-align: center; + display: block; + cursor: pointer; + border: none; +} +.dropzone .dz-preview .dz-remove:hover { + text-decoration: underline; +} +.dropzone .dz-preview:hover .dz-details { + opacity: 1; +} +.dropzone .dz-preview .dz-details { + z-index: 20; + position: absolute; + top: 0; + left: 0; + opacity: 0; + font-size: 13px; + min-width: 100%; + max-width: 100%; + padding: 2em 1em; + text-align: center; + color: rgba(0, 0, 0, 0.9); + line-height: 150%; +} +.dropzone .dz-preview .dz-details .dz-size { + margin-bottom: 1em; + font-size: 16px; +} +.dropzone .dz-preview .dz-details .dz-filename { + white-space: nowrap; +} +.dropzone .dz-preview .dz-details .dz-filename:hover span { + border: 1px solid rgba(200, 200, 200, 0.8); + background-color: rgba(255, 255, 255, 0.8); +} +.dropzone .dz-preview .dz-details .dz-filename:not(:hover) { + overflow: hidden; + text-overflow: ellipsis; +} +.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span { + border: 1px solid transparent; +} +.dropzone .dz-preview .dz-details .dz-filename span, +.dropzone .dz-preview .dz-details .dz-size span { + background-color: rgba(255, 255, 255, 0.4); + padding: 0 0.4em; + border-radius: 3px; +} +.dropzone .dz-preview:hover .dz-image img { + transform: scale(1.05, 1.05); + filter: blur(8px); +} +.dropzone .dz-preview .dz-image { + border-radius: 20px; + overflow: hidden; + width: 120px; + height: 120px; + position: relative; + display: block; + z-index: 10; +} +.dropzone .dz-preview .dz-image img { + display: block; +} +.dropzone .dz-preview.dz-success .dz-success-mark { + animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); +} +.dropzone .dz-preview.dz-error .dz-error-mark { + opacity: 1; + animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); +} +.dropzone .dz-preview .dz-success-mark, +.dropzone .dz-preview .dz-error-mark { + pointer-events: none; + opacity: 0; + z-index: 500; + position: absolute; + display: block; + top: 50%; + left: 50%; + margin-left: -27px; + margin-top: -27px; + background: rgba(0, 0, 0, 0.8); + border-radius: 50%; +} +.dropzone .dz-preview .dz-success-mark svg, +.dropzone .dz-preview .dz-error-mark svg { + display: block; + width: 54px; + height: 54px; + fill: #fff; +} +.dropzone .dz-preview.dz-processing .dz-progress { + opacity: 1; + transition: all 0.2s linear; +} +.dropzone .dz-preview.dz-complete .dz-progress { + opacity: 0; + transition: opacity 0.4s ease-in; +} +.dropzone .dz-preview:not(.dz-processing) .dz-progress { + animation: pulse 6s ease infinite; +} +.dropzone .dz-preview .dz-progress { + opacity: 1; + z-index: 1000; + pointer-events: none; + position: absolute; + height: 20px; + top: 50%; + margin-top: -10px; + left: 15%; + right: 15%; + border: 3px solid rgba(0, 0, 0, 0.8); + background: rgba(0, 0, 0, 0.8); + border-radius: 10px; + overflow: hidden; +} +.dropzone .dz-preview .dz-progress .dz-upload { + background: #fff; + display: block; + position: relative; + height: 100%; + width: 0; + transition: width 300ms ease-in-out; + border-radius: 17px; +} +.dropzone .dz-preview.dz-error .dz-error-message { + display: block; +} +.dropzone .dz-preview.dz-error:hover .dz-error-message { + opacity: 1; + pointer-events: auto; +} +.dropzone .dz-preview .dz-error-message { + pointer-events: none; + z-index: 1000; + position: absolute; + display: block; + display: none; + opacity: 0; + transition: opacity 0.3s ease; + border-radius: 8px; + font-size: 13px; + top: 130px; + left: -10px; + width: 140px; + background: #b10606; + padding: 0.5em 1em; + color: #fff; +} +.dropzone .dz-preview .dz-error-message:after { + content: ""; + position: absolute; + top: -6px; + left: 64px; + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #b10606; +} /*# sourceMappingURL=dropzone.css.map */ diff --git a/src/ui/static/js/air-datepicker/air-datepicker.d.ts b/src/ui/static/js/air-datepicker/air-datepicker.d.ts deleted file mode 100644 index 0f4a9122a..000000000 --- a/src/ui/static/js/air-datepicker/air-datepicker.d.ts +++ /dev/null @@ -1,146 +0,0 @@ -declare type AirDatepickerSelector = string | HTMLElement; - -export declare type AirDatepickerLocale = { - days: string[], - daysShort: string[], - daysMin: string[], - months: string[], - monthsShort: string[], - today: string, - clear: string, - dateFormat: string, - timeFormat: string, - firstDay: 0 | 1 | 2 | 3 | 4 | 5 | 6, -} - -export declare type AirDatepickerButton = { - content: string | ((dp: AirDatepicker) => string), - tagName?: keyof HTMLElementTagNameMap, - className?: string, - attrs?: Record, - onClick?: (dp: AirDatepicker) => void -} - -export declare type AirDatepickerButtonPresets = 'clear' | 'today'; - -export declare type AirDatepickerPosition = 'left' | 'left top' | 'left bottom' | 'top' | 'top left' | 'top right' | 'right' | 'right top' | 'right bottom' | 'bottom' | 'bottom left' | 'bottom right'; -export declare type AirDatepickerViews = 'days' | 'months' | 'years'; -export declare type AirDatepickerViewsSingle = 'day' | 'month' | 'year'; -export declare type AirDatepickerDate = string | number | Date; -export declare type AirDatepickerNavEntry = string | ((dp: AirDatepicker) => string); -export declare type AirDatepickerDecade = [number, number]; -export declare type AirDatepickerPositionCallback = ( - { - $datepicker, - $target, - $pointer, - isViewChange, - done - }: { - $datepicker: HTMLDivElement, - $target: HTMLInputElement, - $pointer: HTMLElement, - isViewChange: boolean, - done: () => void - }) => void | (() => void) - -export declare type AirDatepickerOptions = { - classes: string - inline: boolean, - locale: Partial, - startDate: AirDatepickerDate, - firstDay: number, - isMobile: boolean, - visible: boolean, - weekends: [number, number], - dateFormat: string | ((d: Date) => string), - altField: AirDatepickerSelector, - altFieldDateFormat: string, - toggleSelected: boolean, - keyboardNav: boolean, - selectedDates: AirDatepickerDate[] | false, - container: AirDatepickerSelector, - position: AirDatepickerPosition | AirDatepickerPositionCallback, - offset: number, - view: AirDatepickerViews, - minView: AirDatepickerViews, - showOtherMonths: boolean, - selectOtherMonths: boolean, - moveToOtherMonthsOnSelect: boolean, - showOtherYears: boolean, - selectOtherYears: boolean, - moveToOtherYearsOnSelect: boolean, - minDate: AirDatepickerDate | false, - maxDate: AirDatepickerDate | false, - disableNavWhenOutOfRange: true, - multipleDates: number | true | false, - multipleDatesSeparator: string, - range: boolean, - dynamicRange: boolean, - buttons: AirDatepickerButtonPresets | AirDatepickerButton | (AirDatepickerButtonPresets| AirDatepickerButton)[] | false, - monthsField: keyof AirDatepickerLocale, - showEvent: string, - autoClose: boolean, - prevHtml: string, - nextHtml: string, - navTitles: { - days?: AirDatepickerNavEntry, - months?: AirDatepickerNavEntry, - years?: AirDatepickerNavEntry - }, - timepicker: boolean, - onlyTimepicker: boolean, - dateTimeSeparator: string, - timeFormat: string, - minHours: number, - maxHours: number, - minMinutes: number, - maxMinutes: number, - hoursStep: number, - minutesStep: number, - - onSelect: ({date, formattedDate, datepicker}: {date: Date | Date[], formattedDate: string | string[], datepicker: AirDatepicker}) => void, - onChangeViewDate: ({month, year, decade}: {month: number, year: number, decade: AirDatepickerDecade}) => void, - onChangeView: (view: AirDatepickerViews) => void, - onRenderCell: (params: {date: Date, cellType: AirDatepickerViewsSingle, datepicker: AirDatepicker}) => ({ - disabled?: boolean, - classes?: string, - html?: string - attrs?: Record - } | void), - onShow: (isAnimationComplete: boolean) => void, - onHide: (isAnimationComplete: boolean) => void, - onClickDayName: ({dayIndex, datepicker}: {dayIndex: number, datepicker: AirDatepicker}) => void -} - - -declare class AirDatepicker { - constructor(el: string | E, opts? : Partial) - static version: string - show: () => void - hide: () => void - next: () => void - prev: () => void - selectDate: (date: AirDatepickerDate | AirDatepickerDate[], opts?: {updateTime?: boolean, silent?: boolean}) => void - unselectDate: (date: AirDatepickerDate) => void - clear: () => void - formatDate: (date: AirDatepickerDate, format: string) => string - destroy: () => void - update: (newOpts: Partial) => void - setCurrentView: (newView: AirDatepickerViews) => void - setViewDate: (newViewDate: AirDatepickerDate) => void - setFocusDate: (date: AirDatepickerDate | false, opts?: {viewDateTransition?: boolean}) => void - up: (date?: AirDatepickerDate) => void - down: (date?: AirDatepickerDate) => void - - $el: E - $datepicker: HTMLDivElement - viewDate: Date - currentView: AirDatepickerViews - selectedDates: Date[] - focusDate: Date | false - visible: boolean -} - - -export default AirDatepicker; diff --git a/src/ui/static/js/air-datepicker/air-datepicker.js b/src/ui/static/js/air-datepicker/air-datepicker.js deleted file mode 100644 index da4885f2d..000000000 --- a/src/ui/static/js/air-datepicker/air-datepicker.js +++ /dev/null @@ -1,2350 +0,0 @@ -const { default: AirDatepicker } = require("air-datepicker"); - -!(function (e, t) { - "object" == typeof exports && "object" == typeof module - ? (module.exports = t()) - : "function" == typeof define && define.amd - ? define([], t) - : "object" == typeof exports - ? (exports.AirDatepicker = t()) - : (e.AirDatepicker = t()); -})(this, function () { - return (function () { - "use strict"; - var e = { - d: function (t, i) { - for (var s in i) - e.o(i, s) && - !e.o(t, s) && - Object.defineProperty(t, s, { enumerable: !0, get: i[s] }); - }, - o: function (e, t) { - return Object.prototype.hasOwnProperty.call(e, t); - }, - }, - t = {}; - e.d(t, { - default: function () { - return j; - }, - }); - var i = { - days: "days", - months: "months", - years: "years", - day: "day", - month: "month", - year: "year", - eventChangeViewDate: "changeViewDate", - eventChangeCurrentView: "changeCurrentView", - eventChangeFocusDate: "changeFocusDate", - eventChangeSelectedDate: "changeSelectedDate", - eventChangeTime: "changeTime", - eventChangeLastSelectedDate: "changeLastSelectedDate", - actionSelectDate: "selectDate", - actionUnselectDate: "unselectDate", - cssClassWeekend: "-weekend-", - }, - s = { - classes: "", - inline: !1, - locale: { - days: [ - "Воскресенье", - "Понедельник", - "Вторник", - "Среда", - "Четверг", - "Пятница", - "Суббота", - ], - daysShort: ["Вос", "Пон", "Вто", "Сре", "Чет", "Пят", "Суб"], - daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], - months: [ - "Январь", - "Февраль", - "Март", - "Апрель", - "Май", - "Июнь", - "Июль", - "Август", - "Сентябрь", - "Октябрь", - "Ноябрь", - "Декабрь", - ], - monthsShort: [ - "Янв", - "Фев", - "Мар", - "Апр", - "Май", - "Июн", - "Июл", - "Авг", - "Сен", - "Окт", - "Ноя", - "Дек", - ], - today: "Сегодня", - clear: "Очистить", - dateFormat: "dd.MM.yyyy", - timeFormat: "HH:mm", - firstDay: 1, - }, - startDate: new Date(), - firstDay: "", - weekends: [6, 0], - dateFormat: "", - altField: "", - altFieldDateFormat: "T", - toggleSelected: !0, - keyboardNav: !0, - selectedDates: !1, - container: "", - isMobile: !1, - visible: !1, - position: "bottom left", - offset: 12, - view: i.days, - minView: i.days, - showOtherMonths: !0, - selectOtherMonths: !0, - moveToOtherMonthsOnSelect: !0, - showOtherYears: !0, - selectOtherYears: !0, - moveToOtherYearsOnSelect: !0, - minDate: "", - maxDate: "", - disableNavWhenOutOfRange: !0, - multipleDates: !1, - multipleDatesSeparator: ", ", - range: !1, - dynamicRange: !0, - buttons: !1, - monthsField: "monthsShort", - showEvent: "focus", - autoClose: !1, - prevHtml: '', - nextHtml: '', - navTitles: { - days: "MMMM, yyyy", - months: "yyyy", - years: "yyyy1 - yyyy2", - }, - timepicker: !1, - onlyTimepicker: !1, - dateTimeSeparator: " ", - timeFormat: "", - minHours: 0, - maxHours: 24, - minMinutes: 0, - maxMinutes: 59, - hoursStep: 1, - minutesStep: 1, - onSelect: !1, - onChangeViewDate: !1, - onChangeView: !1, - onRenderCell: !1, - onShow: !1, - onHide: !1, - onClickDayName: !1, - }; - function a(e) { - let t = - arguments.length > 1 && void 0 !== arguments[1] - ? arguments[1] - : document; - return "string" == typeof e ? t.querySelector(e) : e; - } - function n() { - let { - tagName: e = "div", - className: t = "", - innerHtml: i = "", - id: s = "", - attrs: a = {}, - } = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, - n = document.createElement(e); - return ( - t && n.classList.add(...t.split(" ")), - s && (n.id = s), - i && (n.innerHTML = i), - a && r(n, a), - n - ); - } - function r(e, t) { - for (let [i, s] of Object.entries(t)) - void 0 !== s && e.setAttribute(i, s); - return e; - } - function h(e) { - return new Date(e.getFullYear(), e.getMonth() + 1, 0).getDate(); - } - function o(e) { - let t = e.getHours(), - i = t % 12 == 0 ? 12 : t % 12; - return { - year: e.getFullYear(), - month: e.getMonth(), - fullMonth: - e.getMonth() + 1 < 10 ? "0" + (e.getMonth() + 1) : e.getMonth() + 1, - date: e.getDate(), - fullDate: e.getDate() < 10 ? "0" + e.getDate() : e.getDate(), - day: e.getDay(), - hours: t, - fullHours: l(t), - hours12: i, - fullHours12: l(i), - minutes: e.getMinutes(), - fullMinutes: - e.getMinutes() < 10 ? "0" + e.getMinutes() : e.getMinutes(), - }; - } - function l(e) { - return e < 10 ? "0" + e : e; - } - function d(e) { - let t = 10 * Math.floor(e.getFullYear() / 10); - return [t, t + 9]; - } - function c() { - let e = []; - for (var t = arguments.length, i = new Array(t), s = 0; s < t; s++) - i[s] = arguments[s]; - return ( - i.forEach((t) => { - if ("object" == typeof t) for (let i in t) t[i] && e.push(i); - else t && e.push(t); - }), - e.join(" ") - ); - } - function u(e, t) { - let s = - arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : i.days; - if (!e || !t) return !1; - let a = o(e), - n = o(t), - r = { - [i.days]: - a.date === n.date && a.month === n.month && a.year === n.year, - [i.months]: a.month === n.month && a.year === n.year, - [i.years]: a.year === n.year, - }; - return r[s]; - } - function p(e, t, i) { - let s = g(e, !1).getTime(), - a = g(t, !1).getTime(); - return i ? s >= a : s > a; - } - function m(e, t) { - return !p(e, t, !0); - } - function g(e) { - let t = - !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1], - i = new Date(e.getTime()); - return "boolean" != typeof t || t || D(i), i; - } - function D(e) { - return e.setHours(0, 0, 0, 0), e; - } - function v(e, t, i) { - e.length - ? e.forEach((e) => { - e.addEventListener(t, i); - }) - : e.addEventListener(t, i); - } - function y(e, t) { - return ( - !(!e || e === document || e instanceof DocumentFragment) && - (e.matches(t) ? e : y(e.parentNode, t)) - ); - } - function f(e, t, i) { - return e > i ? i : e < t ? t : e; - } - function w(e) { - for ( - var t = arguments.length, i = new Array(t > 1 ? t - 1 : 0), s = 1; - s < t; - s++ - ) - i[s - 1] = arguments[s]; - return ( - i - .filter((e) => e) - .forEach((t) => { - for (let [i, s] of Object.entries(t)) - if (void 0 !== s && "[object Object]" === s.toString()) { - let t = void 0 !== e[i] ? e[i].toString() : void 0, - a = s.toString(), - n = Array.isArray(s) ? [] : {}; - (e[i] = e[i] ? (t !== a ? n : e[i]) : n), w(e[i], s); - } else e[i] = s; - }), - e - ); - } - function b(e) { - let t = e; - return ( - e instanceof Date || (t = new Date(e)), - isNaN(t.getTime()) && - (console.log( - 'Unable to convert value "'.concat(e, '" to Date object') - ), - (t = !1)), - t - ); - } - function k(e) { - let t = "\\s|\\.|-|/|\\\\|,|\\$|\\!|\\?|:|;"; - return new RegExp("(^|>|" + t + ")(" + e + ")($|<|" + t + ")", "g"); - } - function C(e, t, i) { - return ( - t in e - ? Object.defineProperty(e, t, { - value: i, - enumerable: !0, - configurable: !0, - writable: !0, - }) - : (e[t] = i), - e - ); - } - class _ { - constructor() { - let { - type: e, - date: t, - dp: i, - opts: s, - body: a, - } = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; - C(this, "focus", () => { - this.$cell.classList.add("-focus-"), (this.focused = !0); - }), - C(this, "removeFocus", () => { - this.$cell.classList.remove("-focus-"), (this.focused = !1); - }), - C(this, "select", () => { - this.$cell.classList.add("-selected-"), (this.selected = !0); - }), - C(this, "removeSelect", () => { - this.$cell.classList.remove( - "-selected-", - "-range-from-", - "-range-to-" - ), - (this.selected = !1); - }), - C(this, "onChangeSelectedDate", () => { - this.isDisabled || - (this._handleSelectedStatus(), - this.opts.range && this._handleRangeStatus()); - }), - C(this, "onChangeFocusDate", (e) => { - if (!e) return void (this.focused && this.removeFocus()); - let t = u(e, this.date, this.type); - t ? this.focus() : !t && this.focused && this.removeFocus(), - this.opts.range && this._handleRangeStatus(); - }), - C( - this, - "render", - () => ( - (this.$cell.innerHTML = this._getHtml()), - (this.$cell.adpCell = this), - this.$cell - ) - ), - (this.type = e), - (this.singleType = this.type.slice(0, -1)), - (this.date = t), - (this.dp = i), - (this.opts = s), - (this.body = a), - (this.customData = !1), - this.init(); - } - init() { - let { range: e, onRenderCell: t } = this.opts; - t && - (this.customData = t({ - date: this.date, - cellType: this.singleType, - datepicker: this.dp, - })), - this._createElement(), - this._bindDatepickerEvents(), - this._handleInitialFocusStatus(), - this.dp.hasSelectedDates && - (this._handleSelectedStatus(), e && this._handleRangeStatus()); - } - _bindDatepickerEvents() { - this.dp.on(i.eventChangeSelectedDate, this.onChangeSelectedDate), - this.dp.on(i.eventChangeFocusDate, this.onChangeFocusDate); - } - unbindDatepickerEvents() { - this.dp.off(i.eventChangeSelectedDate, this.onChangeSelectedDate), - this.dp.off(i.eventChangeFocusDate, this.onChangeFocusDate); - } - _createElement() { - var e; - let { year: t, month: i, date: s } = o(this.date), - a = - (null === (e = this.customData) || void 0 === e - ? void 0 - : e.attrs) || {}; - this.$cell = n({ - className: this._getClassName(), - attrs: { "data-year": t, "data-month": i, "data-date": s, ...a }, - }); - } - _getClassName() { - var e, t; - let s = new Date(), - { selectOtherMonths: a, selectOtherYears: n } = this.opts, - { minDate: r, maxDate: h } = this.dp, - { day: l } = o(this.date), - d = this._isOutOfMinMaxRange(), - p = - null === (e = this.customData) || void 0 === e - ? void 0 - : e.disabled, - m = c("air-datepicker-cell", "-".concat(this.singleType, "-"), { - "-current-": u(s, this.date, this.type), - "-min-date-": r && u(r, this.date, this.type), - "-max-date-": h && u(h, this.date, this.type), - }), - g = ""; - switch (this.type) { - case i.days: - g = c({ - "-weekend-": this.dp.isWeekend(l), - "-other-month-": this.isOtherMonth, - "-disabled-": (this.isOtherMonth && !a) || d || p, - }); - break; - case i.months: - g = c({ "-disabled-": d || p }); - break; - case i.years: - g = c({ - "-other-decade-": this.isOtherDecade, - "-disabled-": d || (this.isOtherDecade && !n) || p, - }); - } - return c( - m, - g, - null === (t = this.customData) || void 0 === t ? void 0 : t.classes - ); - } - _getHtml() { - var e; - let { year: t, month: s, date: a } = o(this.date), - { showOtherMonths: n, showOtherYears: r } = this.opts; - if (null !== (e = this.customData) && void 0 !== e && e.html) - return this.customData.html; - switch (this.type) { - case i.days: - return !n && this.isOtherMonth ? "" : a; - case i.months: - return this.dp.locale[this.opts.monthsField][s]; - case i.years: - return !r && this.isOtherDecade ? "" : t; - } - } - _isOutOfMinMaxRange() { - let { minDate: e, maxDate: t } = this.dp, - { type: s, date: a } = this, - { month: n, year: r, date: h } = o(a), - l = s === i.days, - d = s === i.years, - c = !!e && new Date(r, d ? e.getMonth() : n, l ? h : e.getDate()), - u = !!t && new Date(r, d ? t.getMonth() : n, l ? h : t.getDate()); - return e && t ? m(c, e) || p(u, t) : e ? m(c, e) : t ? p(u, t) : void 0; - } - destroy() { - this.unbindDatepickerEvents(); - } - _handleRangeStatus() { - let { rangeDateFrom: e, rangeDateTo: t } = this.dp, - i = c({ - "-in-range-": - e && t && ((s = this.date), (a = e), (n = t), p(s, a) && m(s, n)), - "-range-from-": e && u(this.date, e, this.type), - "-range-to-": t && u(this.date, t, this.type), - }); - var s, a, n; - this.$cell.classList.remove("-range-from-", "-range-to-", "-in-range-"), - i && this.$cell.classList.add(...i.split(" ")); - } - _handleSelectedStatus() { - let e = this.dp._checkIfDateIsSelected(this.date, this.type); - e ? this.select() : !e && this.selected && this.removeSelect(); - } - _handleInitialFocusStatus() { - u(this.dp.focusDate, this.date, this.type) && this.focus(); - } - get isDisabled() { - return this.$cell.matches(".-disabled-"); - } - get isOtherMonth() { - return this.dp.isOtherMonth(this.date); - } - get isOtherDecade() { - return this.dp.isOtherDecade(this.date); - } - } - function M(e, t, i) { - return ( - t in e - ? Object.defineProperty(e, t, { - value: i, - enumerable: !0, - configurable: !0, - writable: !0, - }) - : (e[t] = i), - e - ); - } - let $ = { - [i.days]: - '
' + - '
'), - [i.months]: '
' - ), - [i.years]: '
' - ), - }; - const S = ".air-datepicker-cell"; - class T { - constructor(e) { - let { dp: t, type: s, opts: a } = e; - M(this, "handleClick", (e) => { - let t = e.target.closest(S).adpCell; - if (t.isDisabled) return; - if (!this.dp.isMinViewReached) return void this.dp.down(); - let i = this.dp._checkIfDateIsSelected(t.date, t.type); - i - ? this.dp._handleAlreadySelectedDates(i, t.date) - : this.dp.selectDate(t.date); - }), - M(this, "handleDayNameClick", (e) => { - let t = e.target.getAttribute("data-day-index"); - this.opts.onClickDayName({ - dayIndex: Number(t), - datepicker: this.dp, - }); - }), - M(this, "onChangeCurrentView", (e) => { - e !== this.type ? this.hide() : (this.show(), this.render()); - }), - M(this, "onMouseOverCell", (e) => { - let t = y(e.target, S); - this.dp.setFocusDate(!!t && t.adpCell.date); - }), - M(this, "onMouseOutCell", () => { - this.dp.setFocusDate(!1); - }), - M(this, "onClickBody", (e) => { - let { onClickDayName: t } = this.opts, - i = e.target; - i.closest(S) && this.handleClick(e), - t && - i.closest(".air-datepicker-body--day-name") && - this.handleDayNameClick(e); - }), - M(this, "onMouseDown", (e) => { - this.pressed = !0; - let t = y(e.target, S), - i = t && t.adpCell; - u(i.date, this.dp.rangeDateFrom) && (this.rangeFromFocused = !0), - u(i.date, this.dp.rangeDateTo) && (this.rangeToFocused = !0); - }), - M(this, "onMouseMove", (e) => { - if (!this.pressed || !this.dp.isMinViewReached) return; - e.preventDefault(); - let t = y(e.target, S), - i = t && t.adpCell, - { selectedDates: s, rangeDateTo: a, rangeDateFrom: n } = this.dp; - if (!i || i.isDisabled) return; - let { date: r } = i; - if (2 === s.length) { - if (this.rangeFromFocused && !p(r, a)) { - let { hours: e, minutes: t } = o(n); - r.setHours(e), - r.setMinutes(t), - (this.dp.rangeDateFrom = r), - this.dp.replaceDate(n, r); - } - if (this.rangeToFocused && !m(r, n)) { - let { hours: e, minutes: t } = o(a); - r.setHours(e), - r.setMinutes(t), - (this.dp.rangeDateTo = r), - this.dp.replaceDate(a, r); - } - } - }), - M(this, "onMouseUp", () => { - (this.pressed = !1), - (this.rangeFromFocused = !1), - (this.rangeToFocused = !1); - }), - M(this, "onChangeViewDate", (e, t) => { - if (!this.isVisible) return; - let s = d(e), - a = d(t); - switch (this.dp.currentView) { - case i.days: - if (u(e, t, i.months)) return; - break; - case i.months: - if (u(e, t, i.years)) return; - break; - case i.years: - if (s[0] === a[0] && s[1] === a[1]) return; - } - this.render(); - }), - M(this, "render", () => { - this.destroyCells(), - this._generateCells(), - this.cells.forEach((e) => { - this.$cells.appendChild(e.render()); - }); - }), - (this.dp = t), - (this.type = s), - (this.opts = a), - (this.cells = []), - (this.$el = ""), - (this.pressed = !1), - (this.isVisible = !0), - this.init(); - } - init() { - this._buildBaseHtml(), - this.type === i.days && this.renderDayNames(), - this.render(), - this._bindEvents(), - this._bindDatepickerEvents(); - } - _bindEvents() { - let { range: e, dynamicRange: t } = this.opts; - v(this.$el, "mouseover", this.onMouseOverCell), - v(this.$el, "mouseout", this.onMouseOutCell), - v(this.$el, "click", this.onClickBody), - e && - t && - (v(this.$el, "mousedown", this.onMouseDown), - v(this.$el, "mousemove", this.onMouseMove), - v(window.document, "mouseup", this.onMouseUp)); - } - _bindDatepickerEvents() { - this.dp.on(i.eventChangeViewDate, this.onChangeViewDate), - this.dp.on(i.eventChangeCurrentView, this.onChangeCurrentView); - } - _buildBaseHtml() { - (this.$el = n({ - className: "air-datepicker-body -".concat(this.type, "-"), - innerHtml: $[this.type], - })), - (this.$names = a(".air-datepicker-body--day-names", this.$el)), - (this.$cells = a(".air-datepicker-body--cells", this.$el)); - } - _getDayNamesHtml() { - let e = - arguments.length > 0 && void 0 !== arguments[0] - ? arguments[0] - : this.dp.locale.firstDay, - t = "", - s = this.dp.isWeekend, - { onClickDayName: a } = this.opts, - n = e, - r = 0; - for (; r < 7; ) { - let e = n % 7, - h = c("air-datepicker-body--day-name", { - [i.cssClassWeekend]: s(e), - "-clickable-": !!a, - }), - o = this.dp.locale.daysMin[e]; - (t += '
") - .concat(o, "
")), - r++, - n++; - } - return t; - } - _getDaysCells() { - let { - viewDate: e, - locale: { firstDay: t }, - } = this.dp, - i = h(e), - { year: s, month: a } = o(e), - n = new Date(s, a, 1), - r = new Date(s, a, i), - l = n.getDay() - t, - d = 6 - r.getDay() + t; - (l = l < 0 ? l + 7 : l), (d = d > 6 ? d - 7 : d); - let c = (function (e, t) { - let { year: i, month: s, date: a } = o(e); - return new Date(i, s, a - t); - })(n, l), - u = i + l + d, - p = c.getDate(), - { year: m, month: g } = o(c), - D = 0; - for (; D < u; ) { - let e = new Date(m, g, p + D); - this._generateCell(e), D++; - } - } - _generateCell(e) { - let { type: t, dp: i, opts: s } = this, - a = new _({ type: t, dp: i, opts: s, date: e, body: this }); - return this.cells.push(a), a; - } - _generateDayCells() { - this._getDaysCells(); - } - _generateMonthCells() { - let { year: e } = this.dp.parsedViewDate, - t = 0; - for (; t < 12; ) - this.cells.push(this._generateCell(new Date(e, t))), t++; - } - _generateYearCells() { - let e = d(this.dp.viewDate), - t = e[0] - 1, - i = e[1] + 1, - s = t; - for (; s <= i; ) - this.cells.push(this._generateCell(new Date(s, 0))), s++; - } - renderDayNames() { - this.$names.innerHTML = this._getDayNamesHtml(); - } - _generateCells() { - switch (this.type) { - case i.days: - this._generateDayCells(); - break; - case i.months: - this._generateMonthCells(); - break; - case i.years: - this._generateYearCells(); - } - } - show() { - (this.isVisible = !0), this.$el.classList.remove("-hidden-"); - } - hide() { - (this.isVisible = !1), this.$el.classList.add("-hidden-"); - } - destroyCells() { - this.cells.forEach((e) => e.destroy()), - (this.cells = []), - (this.$cells.innerHTML = ""); - } - destroy() { - this.destroyCells(), - this.dp.off(i.eventChangeViewDate, this.onChangeViewDate), - this.dp.off(i.eventChangeCurrentView, this.onChangeCurrentView); - } - } - function F(e, t, i) { - return ( - t in e - ? Object.defineProperty(e, t, { - value: i, - enumerable: !0, - configurable: !0, - writable: !0, - }) - : (e[t] = i), - e - ); - } - class V { - constructor(e) { - let { dp: t, opts: i } = e; - F(this, "onClickNav", (e) => { - let t = y(e.target, ".air-datepicker-nav--action"); - if (!t) return; - let i = t.dataset.action; - this.dp[i](); - }), - F(this, "onChangeViewDate", () => { - this.render(), this._resetNavStatus(), this.handleNavStatus(); - }), - F(this, "onChangeCurrentView", () => { - this.render(), this._resetNavStatus(), this.handleNavStatus(); - }), - F(this, "onClickNavTitle", () => { - this.dp.isFinalView || this.dp.up(); - }), - F(this, "update", () => { - let { prevHtml: e, nextHtml: t } = this.opts; - (this.$prev.innerHTML = e), - (this.$next.innerHTML = t), - this._resetNavStatus(), - this.render(), - this.handleNavStatus(); - }), - F(this, "renderDelay", () => { - setTimeout(this.render); - }), - F(this, "render", () => { - (this.$title.innerHTML = this._getTitle()), - (function (e, t) { - for (let i in t) - t[i] ? e.classList.add(i) : e.classList.remove(i); - })(this.$title, { "-disabled-": this.dp.isFinalView }); - }), - (this.dp = t), - (this.opts = i), - this.init(); - } - init() { - this._createElement(), - this._buildBaseHtml(), - this._defineDOM(), - this.render(), - this.handleNavStatus(), - this._bindEvents(), - this._bindDatepickerEvents(); - } - _defineDOM() { - (this.$title = a(".air-datepicker-nav--title", this.$el)), - (this.$prev = a('[data-action="prev"]', this.$el)), - (this.$next = a('[data-action="next"]', this.$el)); - } - _bindEvents() { - this.$el.addEventListener("click", this.onClickNav), - this.$title.addEventListener("click", this.onClickNavTitle); - } - _bindDatepickerEvents() { - this.dp.on(i.eventChangeViewDate, this.onChangeViewDate), - this.dp.on(i.eventChangeCurrentView, this.onChangeCurrentView), - this.isNavIsFunction && - (this.dp.on(i.eventChangeSelectedDate, this.renderDelay), - this.dp.opts.timepicker && - this.dp.on(i.eventChangeTime, this.render)); - } - destroy() { - this.dp.off(i.eventChangeViewDate, this.onChangeViewDate), - this.dp.off(i.eventChangeCurrentView, this.onChangeCurrentView), - this.isNavIsFunction && - (this.dp.off(i.eventChangeSelectedDate, this.renderDelay), - this.dp.opts.timepicker && - this.dp.off(i.eventChangeTime, this.render)); - } - _createElement() { - this.$el = n({ tagName: "nav", className: "air-datepicker-nav" }); - } - _getTitle() { - let { dp: e, opts: t } = this, - i = t.navTitles[e.currentView]; - return "function" == typeof i ? i(e) : e.formatDate(e.viewDate, i); - } - handleNavStatus() { - let { disableNavWhenOutOfRange: e } = this.opts, - { minDate: t, maxDate: s } = this.dp; - if ((!t && !s) || !e) return; - let { year: a, month: n } = this.dp.parsedViewDate, - r = !!t && o(t), - h = !!s && o(s); - switch (this.dp.currentView) { - case i.days: - t && r.month >= n && r.year >= a && this._disableNav("prev"), - s && h.month <= n && h.year <= a && this._disableNav("next"); - break; - case i.months: - t && r.year >= a && this._disableNav("prev"), - s && h.year <= a && this._disableNav("next"); - break; - case i.years: { - let e = d(this.dp.viewDate); - t && r.year >= e[0] && this._disableNav("prev"), - s && h.year <= e[1] && this._disableNav("next"); - break; - } - } - } - _disableNav(e) { - a('[data-action="' + e + '"]', this.$el).classList.add("-disabled-"); - } - _resetNavStatus() { - !(function (e) { - for ( - var t = arguments.length, i = new Array(t > 1 ? t - 1 : 0), s = 1; - s < t; - s++ - ) - i[s - 1] = arguments[s]; - e.length - ? e.forEach((e) => { - e.classList.remove(...i); - }) - : e.classList.remove(...i); - })( - this.$el.querySelectorAll(".air-datepicker-nav--action"), - "-disabled-" - ); - } - _buildBaseHtml() { - let { prevHtml: e, nextHtml: t } = this.opts; - this.$el.innerHTML = - '
'.concat( - e, - "
" - ) + - '
' + - '
'.concat( - t, - "
" - ); - } - get isNavIsFunction() { - let { navTitles: e } = this.opts; - return Object.keys(e).find((t) => "function" == typeof e[t]); - } - } - var x = { - today: { - content: (e) => e.locale.today, - onClick: (e) => e.setViewDate(new Date()), - }, - clear: { content: (e) => e.locale.clear, onClick: (e) => e.clear() }, - }; - class H { - constructor(e) { - let { dp: t, opts: i } = e; - (this.dp = t), (this.opts = i), this.init(); - } - init() { - this.createElement(), this.render(); - } - createElement() { - this.$el = n({ className: "air-datepicker-buttons" }); - } - destroy() { - this.$el.parentNode.removeChild(this.$el); - } - clearHtml() { - return (this.$el.innerHTML = ""), this; - } - generateButtons() { - let { buttons: e } = this.opts; - Array.isArray(e) || (e = [e]), - e.forEach((e) => { - let t = e; - "string" == typeof e && x[e] && (t = x[e]); - let i = this.createButton(t); - t.onClick && this.attachEventToButton(i, t.onClick), - this.$el.appendChild(i); - }); - } - attachEventToButton(e, t) { - e.addEventListener("click", () => { - t(this.dp); - }); - } - createButton(e) { - let { - content: t, - className: i, - tagName: s = "button", - attrs: a = {}, - } = e, - r = "function" == typeof t ? t(this.dp) : t; - return n({ - tagName: s, - innerHtml: "".concat(r, ""), - className: c("air-datepicker-button", i), - attrs: a, - }); - } - render() { - this.generateButtons(); - } - } - function L(e, t, i) { - return ( - t in e - ? Object.defineProperty(e, t, { - value: i, - enumerable: !0, - configurable: !0, - writable: !0, - }) - : (e[t] = i), - e - ); - } - class O { - constructor() { - let { opts: e, dp: t } = - arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; - L(this, "toggleTimepickerIsActive", (e) => { - this.dp.timepickerIsActive = e; - }), - L(this, "onChangeSelectedDate", (e) => { - let { date: t, updateTime: i = !1 } = e; - t && - (this.setMinMaxTime(t), - this.setCurrentTime(!!i && t), - this.addTimeToDate(t)); - }), - L(this, "onChangeLastSelectedDate", (e) => { - e && (this.setTime(e), this.render()); - }), - L(this, "onChangeInputRange", (e) => { - let t = e.target; - (this[t.getAttribute("name")] = t.value), - this.updateText(), - this.dp.trigger(i.eventChangeTime, { - hours: this.hours, - minutes: this.minutes, - }); - }), - L(this, "onMouseEnterLeave", (e) => { - let t = e.target.getAttribute("name"), - i = this.$minutesText; - "hours" === t && (i = this.$hoursText), - i.classList.toggle("-focus-"); - }), - L(this, "onFocus", () => { - this.toggleTimepickerIsActive(!0); - }), - L(this, "onBlur", () => { - this.toggleTimepickerIsActive(!1); - }), - (this.opts = e), - (this.dp = t); - let { timeFormat: s } = this.dp.locale; - s && (s.match(k("h")) || s.match(k("hh"))) && (this.ampm = !0), - this.init(); - } - init() { - this.setTime(this.dp.lastSelectedDate || this.dp.viewDate), - this.createElement(), - this.buildHtml(), - this.defineDOM(), - this.render(), - this.bindDatepickerEvents(), - this.bindDOMEvents(); - } - bindDatepickerEvents() { - this.dp.on(i.eventChangeSelectedDate, this.onChangeSelectedDate), - this.dp.on( - i.eventChangeLastSelectedDate, - this.onChangeLastSelectedDate - ); - } - bindDOMEvents() { - let e = "input"; - navigator.userAgent.match(/trident/gi) && (e = "change"), - v(this.$ranges, e, this.onChangeInputRange), - v(this.$ranges, "mouseenter", this.onMouseEnterLeave), - v(this.$ranges, "mouseleave", this.onMouseEnterLeave), - v(this.$ranges, "focus", this.onFocus), - v(this.$ranges, "mousedown", this.onFocus), - v(this.$ranges, "blur", this.onBlur); - } - createElement() { - this.$el = n({ - className: c("air-datepicker-time", { "-am-pm-": this.dp.ampm }), - }); - } - destroy() { - this.dp.off(i.eventChangeSelectedDate, this.onChangeSelectedDate), - this.dp.off( - i.eventChangeLastSelectedDate, - this.onChangeLastSelectedDate - ), - this.$el.parentNode.removeChild(this.$el); - } - buildHtml() { - let { - ampm: e, - hours: t, - displayHours: i, - minutes: s, - minHours: a, - minMinutes: n, - maxHours: r, - maxMinutes: h, - dayPeriod: o, - opts: { hoursStep: d, minutesStep: c }, - } = this; - this.$el.innerHTML = - '
' + - ' '.concat( - l(i), - "" - ) + - ' :' + - ' '.concat( - l(s), - "" - ) + - " ".concat( - e - ? "".concat( - o, - "" - ) - : "" - ) + - '
' + - ' ') + - '
' + - ' ') + - "
"; - } - defineDOM() { - let e = (e) => a(e, this.$el); - (this.$ranges = this.$el.querySelectorAll('[type="range"]')), - (this.$hours = e('[name="hours"]')), - (this.$minutes = e('[name="minutes"]')), - (this.$hoursText = e(".air-datepicker-time--current-hours")), - (this.$minutesText = e(".air-datepicker-time--current-minutes")), - (this.$ampm = e(".air-datepicker-time--current-ampm")); - } - setTime(e) { - this.setMinMaxTime(e), this.setCurrentTime(e); - } - addTimeToDate(e) { - e && (e.setHours(this.hours), e.setMinutes(this.minutes)); - } - setMinMaxTime(e) { - if ((this.setMinMaxTimeFromOptions(), e)) { - let { minDate: t, maxDate: i } = this.dp; - t && u(e, t) && this.setMinTimeFromMinDate(t), - i && u(e, i) && this.setMaxTimeFromMaxDate(i); - } - } - setCurrentTime(e) { - let { hours: t, minutes: i } = e ? o(e) : this; - (this.hours = f(t, this.minHours, this.maxHours)), - (this.minutes = f(i, this.minMinutes, this.maxMinutes)); - } - setMinMaxTimeFromOptions() { - let { - minHours: e, - minMinutes: t, - maxHours: i, - maxMinutes: s, - } = this.opts; - (this.minHours = f(e, 0, 23)), - (this.minMinutes = f(t, 0, 59)), - (this.maxHours = f(i, 0, 23)), - (this.maxMinutes = f(s, 0, 59)); - } - setMinTimeFromMinDate(e) { - let { lastSelectedDate: t } = this.dp; - (this.minHours = e.getHours()), - t && t.getHours() > e.getHours() - ? (this.minMinutes = this.opts.minMinutes) - : (this.minMinutes = e.getMinutes()); - } - setMaxTimeFromMaxDate(e) { - let { lastSelectedDate: t } = this.dp; - (this.maxHours = e.getHours()), - t && t.getHours() < e.getHours() - ? (this.maxMinutes = this.opts.maxMinutes) - : (this.maxMinutes = e.getMinutes()); - } - getDayPeriod(e, t) { - let i = e, - s = Number(e); - e instanceof Date && ((i = o(e)), (s = Number(i.hours))); - let a = "am"; - if (t || this.ampm) { - switch (!0) { - case 12 === s: - case s > 11: - a = "pm"; - } - s = s % 12 == 0 ? 12 : s % 12; - } - return { hours: s, dayPeriod: a }; - } - updateSliders() { - (r(this.$hours, { min: this.minHours, max: this.maxHours }).value = - this.hours), - (r(this.$minutes, { - min: this.minMinutes, - max: this.maxMinutes, - }).value = this.minutes); - } - updateText() { - (this.$hoursText.innerHTML = l(this.displayHours)), - (this.$minutesText.innerHTML = l(this.minutes)), - this.ampm && (this.$ampm.innerHTML = this.dayPeriod); - } - set hours(e) { - this._hours = e; - let { hours: t, dayPeriod: i } = this.getDayPeriod(e); - (this.displayHours = t), (this.dayPeriod = i); - } - get hours() { - return this._hours; - } - render() { - this.updateSliders(), this.updateText(); - } - } - function E(e, t, i) { - return ( - t in e - ? Object.defineProperty(e, t, { - value: i, - enumerable: !0, - configurable: !0, - writable: !0, - }) - : (e[t] = i), - e - ); - } - class A { - constructor(e) { - let { dp: t, opts: i } = e; - E(this, "pressedKeys", new Set()), - E( - this, - "hotKeys", - new Map([ - [ - [ - ["Control", "ArrowRight"], - ["Control", "ArrowUp"], - ], - (e) => e.month++, - ], - [ - [ - ["Control", "ArrowLeft"], - ["Control", "ArrowDown"], - ], - (e) => e.month--, - ], - [ - [ - ["Shift", "ArrowRight"], - ["Shift", "ArrowUp"], - ], - (e) => e.year++, - ], - [ - [ - ["Shift", "ArrowLeft"], - ["Shift", "ArrowDown"], - ], - (e) => e.year--, - ], - [ - [ - ["Alt", "ArrowRight"], - ["Alt", "ArrowUp"], - ], - (e) => (e.year += 10), - ], - [ - [ - ["Alt", "ArrowLeft"], - ["Alt", "ArrowDown"], - ], - (e) => (e.year -= 10), - ], - [["Control", "Shift", "ArrowUp"], (e, t) => t.up()], - ]) - ), - E(this, "handleHotKey", (e) => { - let t = this.hotKeys.get(e), - i = o(this.getInitialFocusDate()); - t(i, this.dp); - let { year: s, month: a, date: n } = i, - r = h(new Date(s, a)); - r < n && (n = r); - let l = this.dp.getClampedDate(new Date(s, a, n)); - this.dp.setFocusDate(l, { viewDateTransition: !0 }); - }), - E(this, "isHotKeyPressed", () => { - let e = !1, - t = this.pressedKeys.size, - i = (e) => this.pressedKeys.has(e); - for (let [s] of this.hotKeys) { - if (e) break; - if (Array.isArray(s[0])) - s.forEach((a) => { - e || t !== a.length || (e = a.every(i) && s); - }); - else { - if (t !== s.length) continue; - e = s.every(i) && s; - } - } - return e; - }), - E(this, "isArrow", (e) => e >= 37 && e <= 40), - E(this, "onKeyDown", (e) => { - let { key: t, which: i } = e, - { - dp: s, - dp: { focusDate: a }, - opts: n, - } = this; - this.registerKey(t); - let r = this.isHotKeyPressed(); - if (r) return e.preventDefault(), void this.handleHotKey(r); - if (this.isArrow(i)) - return e.preventDefault(), void this.focusNextCell(t); - if ("Enter" === t) { - if (s.currentView !== n.minView) return void s.down(); - if (a) { - let e = s._checkIfDateIsSelected(a); - return void (e - ? s._handleAlreadySelectedDates(e, a) - : s.selectDate(a)); - } - } - "Escape" === t && this.dp.hide(); - }), - E(this, "onKeyUp", (e) => { - this.removeKey(e.key); - }), - (this.dp = t), - (this.opts = i), - this.init(); - } - init() { - this.bindKeyboardEvents(); - } - bindKeyboardEvents() { - let { $el: e } = this.dp; - e.addEventListener("keydown", this.onKeyDown), - e.addEventListener("keyup", this.onKeyUp); - } - destroy() { - let { $el: e } = this.dp; - e.removeEventListener("keydown", this.onKeyDown), - e.removeEventListener("keyup", this.onKeyUp), - (this.hotKeys = null), - (this.pressedKeys = null); - } - getInitialFocusDate() { - let { - focusDate: e, - currentView: t, - selectedDates: s, - parsedViewDate: { year: a, month: n }, - } = this.dp, - r = e || s[s.length - 1]; - if (!r) - switch (t) { - case i.days: - r = new Date(a, n, new Date().getDate()); - break; - case i.months: - r = new Date(a, n, 1); - break; - case i.years: - r = new Date(a, 0, 1); - } - return r; - } - focusNextCell(e) { - let t = this.getInitialFocusDate(), - { currentView: s } = this.dp, - { days: a, months: n, years: r } = i, - h = o(t), - l = h.year, - d = h.month, - c = h.date; - switch (e) { - case "ArrowLeft": - s === a && (c -= 1), s === n && (d -= 1), s === r && (l -= 1); - break; - case "ArrowUp": - s === a && (c -= 7), s === n && (d -= 3), s === r && (l -= 4); - break; - case "ArrowRight": - s === a && (c += 1), s === n && (d += 1), s === r && (l += 1); - break; - case "ArrowDown": - s === a && (c += 7), s === n && (d += 3), s === r && (l += 4); - } - let u = this.dp.getClampedDate(new Date(l, d, c)); - this.dp.setFocusDate(u, { viewDateTransition: !0 }); - } - registerKey(e) { - this.pressedKeys.add(e); - } - removeKey(e) { - this.pressedKeys.delete(e); - } - } - let N = { - on(e, t) { - this.__events || (this.__events = {}), - this.__events[e] - ? this.__events[e].push(t) - : (this.__events[e] = [t]); - }, - off(e, t) { - this.__events && - this.__events[e] && - (this.__events[e] = this.__events[e].filter((e) => e !== t)); - }, - removeAllEvents() { - this.__events = {}; - }, - trigger(e) { - for ( - var t = arguments.length, i = new Array(t > 1 ? t - 1 : 0), s = 1; - s < t; - s++ - ) - i[s - 1] = arguments[s]; - this.__events && - this.__events[e] && - this.__events[e].forEach((e) => { - e(...i); - }); - }, - }; - function I(e, t, i) { - return ( - t in e - ? Object.defineProperty(e, t, { - value: i, - enumerable: !0, - configurable: !0, - writable: !0, - }) - : (e[t] = i), - e - ); - } - let R = "", - P = "", - B = "", - K = !1; - class j { - constructor(e, t) { - var r = this; - if ( - (I(this, "viewIndexes", [i.days, i.months, i.years]), - I(this, "next", () => { - let { year: e, month: t } = this.parsedViewDate; - switch (this.currentView) { - case i.days: - this.setViewDate(new Date(e, t + 1, 1)); - break; - case i.months: - this.setViewDate(new Date(e + 1, t, 1)); - break; - case i.years: - this.setViewDate(new Date(e + 10, 0, 1)); - } - }), - I(this, "prev", () => { - let { year: e, month: t } = this.parsedViewDate; - switch (this.currentView) { - case i.days: - this.setViewDate(new Date(e, t - 1, 1)); - break; - case i.months: - this.setViewDate(new Date(e - 1, t, 1)); - break; - case i.years: - this.setViewDate(new Date(e - 10, 0, 1)); - } - }), - I(this, "_finishHide", () => { - (this.hideAnimation = !1), - this._destroyComponents(), - this.$container.removeChild(this.$datepicker); - }), - I(this, "setPosition", function (e) { - let t = - arguments.length > 1 && void 0 !== arguments[1] && arguments[1]; - if ("function" == typeof (e = e || r.opts.position)) - return void (r.customHide = e({ - $datepicker: r.$datepicker, - $target: r.$el, - $pointer: r.$pointer, - isViewChange: t, - done: r._finishHide, - })); - let i, - s, - { isMobile: a } = r.opts, - n = r.$el.getBoundingClientRect(), - h = r.$el.getBoundingClientRect(), - o = r.$datepicker.offsetParent, - l = r.$el.offsetParent, - d = r.$datepicker.getBoundingClientRect(), - c = e.split(" "), - u = window.scrollY, - p = window.scrollX, - m = r.opts.offset, - g = c[0], - D = c[1]; - if (a) r.$datepicker.style.cssText = "left: 50%; top: 50%"; - else { - if ( - (o === l && - o !== document.body && - ((h = { - top: r.$el.offsetTop, - left: r.$el.offsetLeft, - width: n.width, - height: r.$el.offsetHeight, - }), - (u = 0), - (p = 0)), - o !== l && o !== document.body) - ) { - let e = o.getBoundingClientRect(); - (h = { - top: n.top - e.top, - left: n.left - e.left, - width: n.width, - height: n.height, - }), - (u = 0), - (p = 0); - } - switch (g) { - case "top": - i = h.top - d.height - m; - break; - case "right": - s = h.left + h.width + m; - break; - case "bottom": - i = h.top + h.height + m; - break; - case "left": - s = h.left - d.width - m; - } - switch (D) { - case "top": - i = h.top; - break; - case "right": - s = h.left + h.width - d.width; - break; - case "bottom": - i = h.top + h.height - d.height; - break; - case "left": - s = h.left; - break; - case "center": - /left|right/.test(g) - ? (i = h.top + h.height / 2 - d.height / 2) - : (s = h.left + h.width / 2 - d.width / 2); - } - r.$datepicker.style.cssText = "left: " - .concat(s + p, "px; top: ") - .concat(i + u, "px"); - } - }), - I(this, "_setInputValue", () => { - let { - opts: e, - $altField: t, - locale: { dateFormat: i }, - } = this, - { altFieldDateFormat: s, altField: a } = e; - a && t && (t.value = this._getInputValue(s)), - (this.$el.value = this._getInputValue(i)); - }), - I(this, "_getInputValue", (e) => { - let { selectedDates: t, opts: i } = this, - { multipleDates: s, multipleDatesSeparator: a } = i; - if (!t.length) return ""; - let n = "function" == typeof e, - r = n ? e(s ? t : t[0]) : t.map((t) => this.formatDate(t, e)); - return (r = n ? r : r.join(a)), r; - }), - I(this, "_checkIfDateIsSelected", function (e) { - let t = - arguments.length > 1 && void 0 !== arguments[1] - ? arguments[1] - : i.days, - s = !1; - return ( - r.selectedDates.some((i) => { - let a = u(e, i, t); - return (s = a && i), a; - }), - s - ); - }), - I(this, "_scheduleCallAfterTransition", (e) => { - this._cancelScheduledCall(), - e && e(!1), - (this._onTransitionEnd = () => { - e && e(!0); - }), - this.$datepicker.addEventListener( - "transitionend", - this._onTransitionEnd, - { once: !0 } - ); - }), - I(this, "_cancelScheduledCall", () => { - this.$datepicker.removeEventListener( - "transitionend", - this._onTransitionEnd - ); - }), - I(this, "setViewDate", (e) => { - if (!((e = b(e)) instanceof Date)) return; - if (u(e, this.viewDate)) return; - let t = this.viewDate; - this.viewDate = e; - let { onChangeViewDate: s } = this.opts; - if (s) { - let { month: e, year: t } = this.parsedViewDate; - s({ month: e, year: t, decade: this.curDecade }); - } - this.trigger(i.eventChangeViewDate, e, t); - }), - I(this, "setFocusDate", function (e) { - let t = - arguments.length > 1 && void 0 !== arguments[1] - ? arguments[1] - : {}; - (!e || (e = b(e)) instanceof Date) && - ((r.focusDate = e), - r.opts.range && e && r._handleRangeOnFocus(), - r.trigger(i.eventChangeFocusDate, e, t)); - }), - I(this, "setCurrentView", (e) => { - if (this.viewIndexes.includes(e)) { - if ( - ((this.currentView = e), - this.elIsInput && this.visible && this.setPosition(void 0, !0), - this.trigger(i.eventChangeCurrentView, e), - !this.views[e]) - ) { - let t = (this.views[e] = new T({ - dp: this, - opts: this.opts, - type: e, - })); - this.shouldUpdateDOM && this.$content.appendChild(t.$el); - } - this.opts.onChangeView && this.opts.onChangeView(e); - } - }), - I(this, "_updateLastSelectedDate", (e) => { - (this.lastSelectedDate = e), - this.trigger(i.eventChangeLastSelectedDate, e); - }), - I(this, "destroy", () => { - let { showEvent: e, isMobile: t } = this.opts, - i = this.$datepicker.parentNode; - i && i.removeChild(this.$datepicker), - this.$el.removeEventListener(e, this._onFocus), - this.$el.removeEventListener("blur", this._onBlur), - window.removeEventListener("resize", this._onResize), - t && this._removeMobileAttributes(), - this.keyboardNav && this.keyboardNav.destroy(), - (this.views = null), - (this.nav = null), - (this.$datepicker = null), - (this.opts = null), - (this.$customContainer = null), - (this.viewDate = null), - (this.focusDate = null), - (this.selectedDates = null), - (this.rangeDateFrom = null), - (this.rangeDateTo = null); - }), - I(this, "update", (e) => { - let t = w({}, this.opts); - w(this.opts, e); - let { - timepicker: s, - buttons: a, - range: n, - selectedDates: r, - isMobile: h, - } = this.opts, - o = this.visible || this.treatAsInline; - this._createMinMaxDates(), - this._limitViewDateByMaxMinDates(), - this._handleLocale(), - !t.selectedDates && r && this.selectDate(r), - e.view && this.setCurrentView(e.view), - this._setInputValue(), - t.range && !n - ? ((this.rangeDateTo = !1), (this.rangeDateFrom = !1)) - : !t.range && - n && - this.selectedDates.length && - ((this.rangeDateFrom = this.selectedDates[0]), - (this.rangeDateTo = this.selectedDates[1])), - t.timepicker && !s - ? (o && this.timepicker.destroy(), - (this.timepicker = !1), - this.$timepicker.parentNode.removeChild(this.$timepicker)) - : !t.timepicker && s && this._addTimepicker(), - !t.buttons && a - ? this._addButtons() - : t.buttons && !a - ? (this.buttons.destroy(), - this.$buttons.parentNode.removeChild(this.$buttons)) - : o && t.buttons && a && this.buttons.clearHtml().render(), - !t.isMobile && h - ? (this.treatAsInline || B || this._createMobileOverlay(), - this._addMobileAttributes(), - this.visible && this._showMobileOverlay()) - : t.isMobile && - !h && - (this._removeMobileAttributes(), - this.visible && - (B.classList.remove("-active-"), - "function" != typeof this.opts.position && - this.setPosition())), - o && - (this.nav.update(), - this.views[this.currentView].render(), - this.currentView === i.days && - this.views[this.currentView].renderDayNames()); - }), - I(this, "isOtherMonth", (e) => { - let { month: t } = o(e); - return t !== this.parsedViewDate.month; - }), - I(this, "isOtherYear", (e) => { - let { year: t } = o(e); - return t !== this.parsedViewDate.year; - }), - I(this, "isOtherDecade", (e) => { - let { year: t } = o(e), - [i, s] = d(this.viewDate); - return t < i || t > s; - }), - I(this, "_onChangeSelectedDate", (e) => { - let { silent: t } = e; - setTimeout(() => { - this._setInputValue(), - this.opts.onSelect && !t && this._triggerOnSelect(); - }); - }), - I(this, "_onChangeFocusedDate", function (e) { - let { viewDateTransition: t } = - arguments.length > 1 && void 0 !== arguments[1] - ? arguments[1] - : {}; - if (!e) return; - let i = !1; - t && - (i = r.isOtherMonth(e) || r.isOtherYear(e) || r.isOtherDecade(e)), - i && r.setViewDate(e); - }), - I(this, "_onChangeTime", (e) => { - let { hours: t, minutes: i } = e, - s = new Date(), - { - lastSelectedDate: a, - opts: { onSelect: n }, - } = this, - r = a; - a || (r = s); - let h = this.getCell(r, this.currentViewSingular), - o = h && h.adpCell; - (o && o.isDisabled) || - (r.setHours(t), - r.setMinutes(i), - a - ? (this._setInputValue(), n && this._triggerOnSelect()) - : this.selectDate(r)); - }), - I(this, "_onFocus", (e) => { - this.visible || this.show(); - }), - I(this, "_onBlur", (e) => { - this.inFocus || !this.visible || this.opts.isMobile || this.hide(); - }), - I(this, "_onMouseDown", (e) => { - this.inFocus = !0; - }), - I(this, "_onMouseUp", (e) => { - (this.inFocus = !1), this.$el.focus(); - }), - I(this, "_onResize", () => { - this.visible && - "function" != typeof this.opts.position && - this.setPosition(); - }), - I(this, "_onClickOverlay", () => { - this.visible && this.hide(); - }), - I(this, "isWeekend", (e) => this.opts.weekends.includes(e)), - I(this, "getClampedDate", (e) => { - let { minDate: t, maxDate: i } = this, - s = e; - return i && p(e, i) ? (s = i) : t && m(e, t) && (s = t), s; - }), - (this.$el = a(e)), - !this.$el) - ) - return; - (this.$datepicker = n({ className: "air-datepicker" })), - (this.opts = w({}, s, t)), - (this.$customContainer = - !!this.opts.container && a(this.opts.container)), - (this.$altField = a(this.opts.altField || !1)), - R || (R = a("body")); - let { view: h, startDate: l } = this.opts; - l || (this.opts.startDate = new Date()), - "INPUT" === this.$el.nodeName && (this.elIsInput = !0), - (this.inited = !1), - (this.visible = !1), - (this.viewDate = b(this.opts.startDate)), - (this.focusDate = !1), - (this.initialReadonly = this.$el.getAttribute("readonly")), - (this.customHide = !1), - (this.currentView = h), - (this.selectedDates = []), - (this.views = {}), - (this.keys = []), - (this.rangeDateFrom = ""), - (this.rangeDateTo = ""), - (this.timepickerIsActive = !1), - (this.treatAsInline = this.opts.inline || !this.elIsInput), - this.init(); - } - init() { - let { - opts: e, - treatAsInline: t, - opts: { - inline: i, - isMobile: s, - selectedDates: a, - keyboardNav: r, - onlyTimepicker: h, - }, - } = this; - var o; - K || - i || - !this.elIsInput || - ((K = !0), - (P = n({ className: (o = j.defaultContainerId), id: o })), - R.appendChild(P)), - !s || B || t || this._createMobileOverlay(), - this._handleLocale(), - this._bindSubEvents(), - this._createMinMaxDates(), - this._limitViewDateByMaxMinDates(), - this.elIsInput && - (i || this._bindEvents(), - r && !h && (this.keyboardNav = new A({ dp: this, opts: e }))), - a && this.selectDate(a, { silent: !0 }), - this.opts.visible && !t && this.show(), - s && !t && this.$el.setAttribute("readonly", !0), - t && this._createComponents(); - } - _createMobileOverlay() { - (B = n({ className: "air-datepicker-overlay" })), P.appendChild(B); - } - _createComponents() { - let { - opts: e, - treatAsInline: t, - opts: { - inline: i, - buttons: s, - timepicker: a, - position: n, - classes: r, - onlyTimepicker: h, - isMobile: o, - }, - } = this; - this._buildBaseHtml(), - this.elIsInput && (i || this._setPositionClasses(n)), - (!i && this.elIsInput) || this.$datepicker.classList.add("-inline-"), - r && this.$datepicker.classList.add(...r.split(" ")), - h && this.$datepicker.classList.add("-only-timepicker-"), - o && !t && this._addMobileAttributes(), - (this.views[this.currentView] = new T({ - dp: this, - type: this.currentView, - opts: e, - })), - (this.nav = new V({ dp: this, opts: e })), - a && this._addTimepicker(), - s && this._addButtons(), - this.$content.appendChild(this.views[this.currentView].$el), - this.$nav.appendChild(this.nav.$el); - } - _destroyComponents() { - for (let e in this.views) this.views[e].destroy(); - (this.views = {}), - this.nav.destroy(), - this.timepicker && this.timepicker.destroy(); - } - _addMobileAttributes() { - B.addEventListener("click", this._onClickOverlay), - this.$datepicker.classList.add("-is-mobile-"), - this.$el.setAttribute("readonly", !0); - } - _removeMobileAttributes() { - B.removeEventListener("click", this._onClickOverlay), - this.$datepicker.classList.remove("-is-mobile-"), - this.initialReadonly || - "" === this.initialReadonly || - this.$el.removeAttribute("readonly"); - } - _createMinMaxDates() { - let { minDate: e, maxDate: t } = this.opts; - (this.minDate = !!e && b(e)), (this.maxDate = !!t && b(t)); - } - _addTimepicker() { - (this.$timepicker = n({ className: "air-datepicker--time" })), - this.$datepicker.appendChild(this.$timepicker), - (this.timepicker = new O({ dp: this, opts: this.opts })), - this.$timepicker.appendChild(this.timepicker.$el); - } - _addButtons() { - (this.$buttons = n({ className: "air-datepicker--buttons" })), - this.$datepicker.appendChild(this.$buttons), - (this.buttons = new H({ dp: this, opts: this.opts })), - this.$buttons.appendChild(this.buttons.$el); - } - _bindSubEvents() { - this.on(i.eventChangeSelectedDate, this._onChangeSelectedDate), - this.on(i.eventChangeFocusDate, this._onChangeFocusedDate), - this.on(i.eventChangeTime, this._onChangeTime); - } - _buildBaseHtml() { - let { inline: e } = this.opts; - var t, i; - this.elIsInput - ? e - ? ((t = this.$datepicker), - (i = this.$el).parentNode.insertBefore(t, i.nextSibling)) - : this.$container.appendChild(this.$datepicker) - : this.$el.appendChild(this.$datepicker), - (this.$datepicker.innerHTML = - '
'), - (this.$content = a(".air-datepicker--content", this.$datepicker)), - (this.$pointer = a(".air-datepicker--pointer", this.$datepicker)), - (this.$nav = a(".air-datepicker--navigation", this.$datepicker)); - } - _handleLocale() { - let { - locale: e, - dateFormat: t, - firstDay: i, - timepicker: s, - onlyTimepicker: a, - timeFormat: n, - dateTimeSeparator: r, - } = this.opts; - var h; - (this.locale = ((h = e), JSON.parse(JSON.stringify(h)))), - t && (this.locale.dateFormat = t), - void 0 !== n && "" !== n && (this.locale.timeFormat = n); - let { timeFormat: o } = this.locale; - if ( - ("" !== i && (this.locale.firstDay = i), s && "function" != typeof t) - ) { - let e = o ? r : ""; - this.locale.dateFormat = [this.locale.dateFormat, o || ""].join(e); - } - a && - "function" != typeof t && - (this.locale.dateFormat = this.locale.timeFormat); - } - _setPositionClasses(e) { - if ("function" == typeof e) - return void this.$datepicker.classList.add("-custom-position-"); - let t = (e = e.split(" "))[0], - i = e[1], - s = "air-datepicker -" - .concat(t, "-") - .concat(i, "- -from-") - .concat(t, "-"); - this.$datepicker.classList.add(...s.split(" ")); - } - _bindEvents() { - this.$el.addEventListener(this.opts.showEvent, this._onFocus), - this.$el.addEventListener("blur", this._onBlur), - this.$datepicker.addEventListener("mousedown", this._onMouseDown), - this.$datepicker.addEventListener("mouseup", this._onMouseUp), - window.addEventListener("resize", this._onResize); - } - _limitViewDateByMaxMinDates() { - let { viewDate: e, minDate: t, maxDate: i } = this; - i && p(e, i) && this.setViewDate(i), - t && m(e, t) && this.setViewDate(t); - } - formatDate() { - let e = - arguments.length > 0 && void 0 !== arguments[0] - ? arguments[0] - : this.viewDate, - t = arguments.length > 1 ? arguments[1] : void 0; - if (((e = b(e)), !(e instanceof Date))) return; - let i = t, - s = this.locale, - a = o(e), - n = d(e), - r = j.replacer, - h = "am"; - this.opts.timepicker && - this.timepicker && - (h = this.timepicker.getDayPeriod(e).dayPeriod); - let l = { - T: e.getTime(), - m: a.minutes, - mm: a.fullMinutes, - h: a.hours12, - hh: a.fullHours12, - H: a.hours, - HH: a.fullHours, - aa: h, - AA: h.toUpperCase(), - E: s.daysShort[a.day], - EEEE: s.days[a.day], - d: a.date, - dd: a.fullDate, - M: a.month + 1, - MM: a.fullMonth, - MMM: s.monthsShort[a.month], - MMMM: s.months[a.month], - yy: a.year.toString().slice(-2), - yyyy: a.year, - yyyy1: n[0], - yyyy2: n[1], - }; - for (let [e, t] of Object.entries(l)) i = r(i, k(e), t); - return i; - } - down(e) { - this._handleUpDownActions(e, "down"); - } - up(e) { - this._handleUpDownActions(e, "up"); - } - selectDate(e) { - let t, - s = - arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, - { currentView: a, parsedViewDate: n, selectedDates: r } = this, - { updateTime: h } = s, - { - moveToOtherMonthsOnSelect: o, - moveToOtherYearsOnSelect: l, - multipleDates: d, - range: c, - autoClose: u, - } = this.opts, - m = r.length; - if (Array.isArray(e)) - return ( - e.forEach((e) => { - this.selectDate(e, s); - }), - new Promise((e) => { - setTimeout(e); - }) - ); - if ((e = b(e)) instanceof Date) { - if ( - (a === i.days && - e.getMonth() !== n.month && - o && - (t = new Date(e.getFullYear(), e.getMonth(), 1)), - a === i.years && - e.getFullYear() !== n.year && - l && - (t = new Date(e.getFullYear(), 0, 1)), - t && this.setViewDate(t), - d && !c) - ) { - if (m === d) return; - this._checkIfDateIsSelected(e) || r.push(e); - } else if (c) - switch (m) { - case 1: - r.push(e), - this.rangeDateTo || (this.rangeDateTo = e), - p(this.rangeDateFrom, this.rangeDateTo) && - ((this.rangeDateTo = this.rangeDateFrom), - (this.rangeDateFrom = e)), - (this.selectedDates = [this.rangeDateFrom, this.rangeDateTo]); - break; - case 2: - (this.selectedDates = [e]), - (this.rangeDateFrom = e), - (this.rangeDateTo = ""); - break; - default: - (this.selectedDates = [e]), (this.rangeDateFrom = e); - } - else this.selectedDates = [e]; - return ( - this.trigger(i.eventChangeSelectedDate, { - action: i.actionSelectDate, - silent: null == s ? void 0 : s.silent, - date: e, - updateTime: h, - }), - this._updateLastSelectedDate(e), - u && - !this.timepickerIsActive && - this.visible && - (d || c ? c && 1 === m && this.hide() : this.hide()), - new Promise((e) => { - setTimeout(e); - }) - ); - } - } - unselectDate(e) { - let t = this.selectedDates, - s = this; - if ((e = b(e)) instanceof Date) - return t.some((a, n) => { - if (u(a, e)) - return ( - t.splice(n, 1), - s.selectedDates.length - ? s._updateLastSelectedDate( - s.selectedDates[s.selectedDates.length - 1] - ) - : ((s.rangeDateFrom = ""), - (s.rangeDateTo = ""), - s._updateLastSelectedDate(!1)), - this.trigger(i.eventChangeSelectedDate, { - action: i.actionUnselectDate, - date: e, - }), - !0 - ); - }); - } - replaceDate(e, t) { - let s = this.selectedDates.find((t) => u(t, e, this.currentView)), - a = this.selectedDates.indexOf(s); - a < 0 || - u(this.selectedDates[a], t, this.currentView) || - ((this.selectedDates[a] = t), - this.trigger(i.eventChangeSelectedDate, { - action: i.actionSelectDate, - date: t, - updateTime: !0, - }), - this._updateLastSelectedDate(t)); - } - clear() { - let e = - arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; - return ( - (this.selectedDates = []), - (this.rangeDateFrom = !1), - (this.rangeDateTo = !1), - this.trigger(i.eventChangeSelectedDate, { - action: i.actionUnselectDate, - silent: e.silent, - }), - new Promise((e) => { - setTimeout(e); - }) - ); - } - show() { - let { onShow: e, isMobile: t } = this.opts; - this._cancelScheduledCall(), - this.visible || this.hideAnimation || this._createComponents(), - this.setPosition(this.opts.position), - this.$datepicker.classList.add("-active-"), - (this.visible = !0), - e && this._scheduleCallAfterTransition(e), - t && this._showMobileOverlay(); - } - hide() { - let { onHide: e, isMobile: t } = this.opts, - i = this._hasTransition(); - (this.visible = !1), - (this.hideAnimation = !0), - this.$datepicker.classList.remove("-active-"), - this.customHide && this.customHide(), - this.elIsInput && this.$el.blur(), - this._scheduleCallAfterTransition((t) => { - !this.customHide && ((t && i) || (!t && !i)) && this._finishHide(), - e && e(t); - }), - t && B.classList.remove("-active-"); - } - _triggerOnSelect() { - let e = [], - t = [], - { - selectedDates: i, - locale: s, - opts: { onSelect: a, multipleDates: n, range: r }, - } = this, - h = n || r, - o = "function" == typeof s.dateFormat; - i.length && - ((e = i.map(g)), - (t = o - ? n - ? s.dateFormat(e) - : e.map((e) => s.dateFormat(e)) - : e.map((e) => this.formatDate(e, s.dateFormat)))), - a({ - date: h ? e : e[0], - formattedDate: h ? t : t[0], - datepicker: this, - }); - } - _handleAlreadySelectedDates(e, t) { - let { range: i, toggleSelected: s } = this.opts; - i - ? s - ? this.unselectDate(t) - : 2 !== this.selectedDates.length && this.selectDate(t) - : s && this.unselectDate(t), - s || this._updateLastSelectedDate(e); - } - _handleUpDownActions(e, t) { - if (!((e = b(e || this.focusDate || this.viewDate)) instanceof Date)) - return; - let i = "up" === t ? this.viewIndex + 1 : this.viewIndex - 1; - i > 2 && (i = 2), - i < 0 && (i = 0), - this.setViewDate(new Date(e.getFullYear(), e.getMonth(), 1)), - this.setCurrentView(this.viewIndexes[i]); - } - _handleRangeOnFocus() { - 1 === this.selectedDates.length && - (p(this.selectedDates[0], this.focusDate) - ? ((this.rangeDateTo = this.selectedDates[0]), - (this.rangeDateFrom = this.focusDate)) - : ((this.rangeDateTo = this.focusDate), - (this.rangeDateFrom = this.selectedDates[0]))); - } - getCell(e) { - let t = - arguments.length > 1 && void 0 !== arguments[1] - ? arguments[1] - : i.day; - if (!((e = b(e)) instanceof Date)) return; - let { year: s, month: a, date: n } = o(e), - r = '[data-year="'.concat(s, '"]'), - h = '[data-month="'.concat(a, '"]'), - l = '[data-date="'.concat(n, '"]'), - d = { - [i.day]: "".concat(r).concat(h).concat(l), - [i.month]: "".concat(r).concat(h), - [i.year]: "".concat(r), - }; - return this.views[this.currentView].$el.querySelector(d[t]); - } - _showMobileOverlay() { - B.classList.add("-active-"); - } - _hasTransition() { - return ( - window - .getComputedStyle(this.$datepicker) - .getPropertyValue("transition-duration") - .split(", ") - .reduce((e, t) => parseFloat(t) + e, 0) > 0 - ); - } - get shouldUpdateDOM() { - return this.visible || this.treatAsInline; - } - get parsedViewDate() { - return o(this.viewDate); - } - get currentViewSingular() { - return this.currentView.slice(0, -1); - } - get curDecade() { - return d(this.viewDate); - } - get viewIndex() { - return this.viewIndexes.indexOf(this.currentView); - } - get isFinalView() { - return this.currentView === i.years; - } - get hasSelectedDates() { - return this.selectedDates.length > 0; - } - get isMinViewReached() { - return ( - this.currentView === this.opts.minView || this.currentView === i.days - ); - } - get $container() { - return this.$customContainer || P; - } - static replacer(e, t, i) { - return e.replace(t, function (e, t, s, a) { - return t + i + a; - }); - } - } - var U; - const datepicker = new AirDatepicker("input[fetchdatetimepicker]"); - return ( - I(j, "defaults", s), - I(j, "version", "3.3.1"), - I(j, "defaultContainerId", "air-datepicker-global-container"), - (U = j.prototype), - Object.assign(U, N), - t.default - ); - })(); -}); diff --git a/src/ui/static/js/air-datepicker/index.es.js b/src/ui/static/js/air-datepicker/index.es.js deleted file mode 100644 index 4074f38eb..000000000 --- a/src/ui/static/js/air-datepicker/index.es.js +++ /dev/null @@ -1,2 +0,0 @@ -import AirDatepicker from "air-datepicker"; -export default AirDatepicker; diff --git a/src/ui/static/js/air-datepicker/locale/ar.d.ts b/src/ui/static/js/air-datepicker/locale/ar.d.ts deleted file mode 100644 index 5b79468ec..000000000 --- a/src/ui/static/js/air-datepicker/locale/ar.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/ar' { - import {AirDatepickerLocale} from 'air-datepicker'; - const ar: AirDatepickerLocale; - - export default ar; -} diff --git a/src/ui/static/js/air-datepicker/locale/ar.js b/src/ui/static/js/air-datepicker/locale/ar.js deleted file mode 100644 index 828683a7b..000000000 --- a/src/ui/static/js/air-datepicker/locale/ar.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['الأحد', 'الأثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعه', 'السبت'], - daysShort: ['الأحد', 'الأثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعه', 'السبت'], - daysMin: ['الأحد', 'الأثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعه', 'السبت'], - months: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر'], - monthsShort: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر'], - today: 'اليوم', - clear: 'حذف', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'hh:mm aa', - firstDay: 0 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/cs.d.ts b/src/ui/static/js/air-datepicker/locale/cs.d.ts deleted file mode 100644 index 5e91529bb..000000000 --- a/src/ui/static/js/air-datepicker/locale/cs.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/cs' { - import {AirDatepickerLocale} from 'air-datepicker'; - const cs: AirDatepickerLocale; - - export default cs; -} diff --git a/src/ui/static/js/air-datepicker/locale/cs.js b/src/ui/static/js/air-datepicker/locale/cs.js deleted file mode 100644 index 65062439c..000000000 --- a/src/ui/static/js/air-datepicker/locale/cs.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'], - daysShort: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], - daysMin: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], - months: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'], - monthsShort: ['Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čvn', 'Čvc', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro'], - today: 'Dnes', - clear: 'Vymazat', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/da.d.ts b/src/ui/static/js/air-datepicker/locale/da.d.ts deleted file mode 100644 index 173e75805..000000000 --- a/src/ui/static/js/air-datepicker/locale/da.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/da' { - import {AirDatepickerLocale} from 'air-datepicker'; - const da: AirDatepickerLocale; - - export default da; -} diff --git a/src/ui/static/js/air-datepicker/locale/da.js b/src/ui/static/js/air-datepicker/locale/da.js deleted file mode 100644 index 7f527b4a2..000000000 --- a/src/ui/static/js/air-datepicker/locale/da.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'], - daysShort: ['Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'], - daysMin: ['Sø', 'Ma', 'Ti', 'On', 'To', 'Fr', 'Lø'], - months: ['Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December'], - monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], - today: 'I dag', - clear: 'Nulstil', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/de.d.ts b/src/ui/static/js/air-datepicker/locale/de.d.ts deleted file mode 100644 index ac35fc8ec..000000000 --- a/src/ui/static/js/air-datepicker/locale/de.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/de' { - import {AirDatepickerLocale} from 'air-datepicker'; - const de: AirDatepickerLocale; - - export default de; -} diff --git a/src/ui/static/js/air-datepicker/locale/de.js b/src/ui/static/js/air-datepicker/locale/de.js deleted file mode 100644 index da9c582a1..000000000 --- a/src/ui/static/js/air-datepicker/locale/de.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], - daysShort: ['Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam'], - daysMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], - months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], - monthsShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], - today: 'Heute', - clear: 'Aufräumen', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'HH:ii', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/en.d.ts b/src/ui/static/js/air-datepicker/locale/en.d.ts deleted file mode 100644 index 060236fc8..000000000 --- a/src/ui/static/js/air-datepicker/locale/en.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/en' { - import {AirDatepickerLocale} from 'air-datepicker'; - const en: AirDatepickerLocale; - - export default en; -} diff --git a/src/ui/static/js/air-datepicker/locale/en.js b/src/ui/static/js/air-datepicker/locale/en.js deleted file mode 100644 index 7788883c2..000000000 --- a/src/ui/static/js/air-datepicker/locale/en.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], - months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - today: 'Today', - clear: 'Clear', - dateFormat: 'MM/dd/yyyy', - timeFormat: 'hh:mm aa', - firstDay: 0 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/es.d.ts b/src/ui/static/js/air-datepicker/locale/es.d.ts deleted file mode 100644 index 2c7e2b041..000000000 --- a/src/ui/static/js/air-datepicker/locale/es.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/es' { - import {AirDatepickerLocale} from 'air-datepicker'; - const es: AirDatepickerLocale; - - export default es; -} diff --git a/src/ui/static/js/air-datepicker/locale/es.js b/src/ui/static/js/air-datepicker/locale/es.js deleted file mode 100644 index a5a1886fe..000000000 --- a/src/ui/static/js/air-datepicker/locale/es.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'], - daysShort: ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab'], - daysMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa'], - months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], - monthsShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], - today: 'Hoy', - clear: 'Limpiar', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'hh:mm aa', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/fi.d.ts b/src/ui/static/js/air-datepicker/locale/fi.d.ts deleted file mode 100644 index 6b8f7e5d0..000000000 --- a/src/ui/static/js/air-datepicker/locale/fi.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/fi' { - import {AirDatepickerLocale} from 'air-datepicker'; - const fi: AirDatepickerLocale; - - export default fi; -} diff --git a/src/ui/static/js/air-datepicker/locale/fi.js b/src/ui/static/js/air-datepicker/locale/fi.js deleted file mode 100644 index c4b538b54..000000000 --- a/src/ui/static/js/air-datepicker/locale/fi.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Sunnuntai', 'Maanantai', 'Tiistai', 'Keskiviikko', 'Torstai', 'Perjantai', 'Lauantai'], - daysShort: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], - daysMin: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], - months: ['Tammikuu', 'Helmikuu', 'Maaliskuu', 'Huhtikuu', 'Toukokuu', 'Kesäkuu', 'Heinäkuu', 'Elokuu', 'Syyskuu', 'Lokakuu', 'Marraskuu', 'Joulukuu'], - monthsShort: ['Tammi', 'Helmi', 'Maalis', 'Huhti', 'Touko', 'Kesä', 'Heinä', 'Elo', 'Syys', 'Loka', 'Marras', 'Joulu'], - today: 'Tänään', - clear: 'Tyhjennä', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/fr.d.ts b/src/ui/static/js/air-datepicker/locale/fr.d.ts deleted file mode 100644 index 9cc25a55b..000000000 --- a/src/ui/static/js/air-datepicker/locale/fr.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/fr' { - import {AirDatepickerLocale} from 'air-datepicker'; - const fr: AirDatepickerLocale; - - export default fr; -} diff --git a/src/ui/static/js/air-datepicker/locale/fr.js b/src/ui/static/js/air-datepicker/locale/fr.js deleted file mode 100644 index 11ab7fe31..000000000 --- a/src/ui/static/js/air-datepicker/locale/fr.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'], - daysShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'], - daysMin: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'], - months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'], - monthsShort: ['Jan', 'Fév', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Dec'], - today: "Aujourd'hui", - clear: 'Effacer', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/hu.d.ts b/src/ui/static/js/air-datepicker/locale/hu.d.ts deleted file mode 100644 index a6558b97a..000000000 --- a/src/ui/static/js/air-datepicker/locale/hu.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/hu' { - import {AirDatepickerLocale} from 'air-datepicker'; - const hu: AirDatepickerLocale; - - export default hu; -} diff --git a/src/ui/static/js/air-datepicker/locale/hu.js b/src/ui/static/js/air-datepicker/locale/hu.js deleted file mode 100644 index 30c5d38ef..000000000 --- a/src/ui/static/js/air-datepicker/locale/hu.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], - daysShort: ['Va', 'Hé', 'Ke', 'Sze', 'Cs', 'Pé', 'Szo'], - daysMin: ['V', 'H', 'K', 'Sz', 'Cs', 'P', 'Sz'], - months: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], - monthsShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], - today: 'Ma', - clear: 'Törlés', - dateFormat: 'yyyy-MM-dd', - timeFormat: 'hh:mm aa', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/it.d.ts b/src/ui/static/js/air-datepicker/locale/it.d.ts deleted file mode 100644 index ca8aecd37..000000000 --- a/src/ui/static/js/air-datepicker/locale/it.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/it' { - import {AirDatepickerLocale} from 'air-datepicker'; - const it: AirDatepickerLocale; - - export default it; -} diff --git a/src/ui/static/js/air-datepicker/locale/it.js b/src/ui/static/js/air-datepicker/locale/it.js deleted file mode 100644 index 12b663d6d..000000000 --- a/src/ui/static/js/air-datepicker/locale/it.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'], - daysShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'], - daysMin: ['Do', 'Lu', 'Ma', 'Me', 'Gi', 'Ve', 'Sa'], - months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'], - monthsShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'], - today: 'Oggi', - clear: 'Cancella', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/ja.d.ts b/src/ui/static/js/air-datepicker/locale/ja.d.ts deleted file mode 100644 index da763b250..000000000 --- a/src/ui/static/js/air-datepicker/locale/ja.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/ja' { - import {AirDatepickerLocale} from 'air-datepicker'; - const ja: AirDatepickerLocale; - - export default ja; -} diff --git a/src/ui/static/js/air-datepicker/locale/ja.js b/src/ui/static/js/air-datepicker/locale/ja.js deleted file mode 100644 index 1228fc60a..000000000 --- a/src/ui/static/js/air-datepicker/locale/ja.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'], - daysShort: ['日', '月', '火', '水', '木', '金', '土'], - daysMin: ['日', '月', '火', '水', '木', '金', '土'], - months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], - monthsShort: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], - today: '今日', - clear: 'クリア', - dateFormat: 'yyyy/MM/dd', - timeFormat: 'HH:mm', - firstDay: 0 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/ko.d.ts b/src/ui/static/js/air-datepicker/locale/ko.d.ts deleted file mode 100644 index db244b076..000000000 --- a/src/ui/static/js/air-datepicker/locale/ko.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/ko' { - import {AirDatepickerLocale} from 'air-datepicker'; - const ko: AirDatepickerLocale; - - export default ko; -} diff --git a/src/ui/static/js/air-datepicker/locale/ko.js b/src/ui/static/js/air-datepicker/locale/ko.js deleted file mode 100644 index 092901d71..000000000 --- a/src/ui/static/js/air-datepicker/locale/ko.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'], - daysShort: ['일', '월', '화', '수', '목', '금', '토'], - daysMin: ['일', '월', '화', '수', '목', '금', '토'], - months: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'], - monthsShort: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'], - today: '오늘', - clear: '초기화', - dateFormat: 'MM/dd/yyyy', - timeFormat: 'hh:mm aa', - firstDay: 0 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/nl.d.ts b/src/ui/static/js/air-datepicker/locale/nl.d.ts deleted file mode 100644 index ce294eec9..000000000 --- a/src/ui/static/js/air-datepicker/locale/nl.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/nl' { - import {AirDatepickerLocale} from 'air-datepicker'; - const nl: AirDatepickerLocale; - - export default nl; -} diff --git a/src/ui/static/js/air-datepicker/locale/nl.js b/src/ui/static/js/air-datepicker/locale/nl.js deleted file mode 100644 index 3c03fd2f3..000000000 --- a/src/ui/static/js/air-datepicker/locale/nl.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], - daysShort: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], - daysMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], - months: ['Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December'], - monthsShort: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], - today: 'Vandaag', - clear: 'Legen', - dateFormat: 'dd-MM-yyyy', - timeFormat: 'HH:mm', - firstDay: 0 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/pl.d.ts b/src/ui/static/js/air-datepicker/locale/pl.d.ts deleted file mode 100644 index a053d09e6..000000000 --- a/src/ui/static/js/air-datepicker/locale/pl.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/pl' { - import {AirDatepickerLocale} from 'air-datepicker'; - const pl: AirDatepickerLocale; - - export default pl; -} diff --git a/src/ui/static/js/air-datepicker/locale/pl.js b/src/ui/static/js/air-datepicker/locale/pl.js deleted file mode 100644 index 6bef2c36d..000000000 --- a/src/ui/static/js/air-datepicker/locale/pl.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'], - daysShort: ['Nie', 'Pon', 'Wto', 'Śro', 'Czw', 'Pią', 'Sob'], - daysMin: ['Nd', 'Pn', 'Wt', 'Śr', 'Czw', 'Pt', 'So'], - months: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'], - monthsShort: ['Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru'], - today: 'Dzisiaj', - clear: 'Wyczyść', - dateFormat: 'yyyy-MM-dd', - timeFormat: 'hh:mm:aa', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/pt-BR.d.ts b/src/ui/static/js/air-datepicker/locale/pt-BR.d.ts deleted file mode 100644 index 6c1c6baf4..000000000 --- a/src/ui/static/js/air-datepicker/locale/pt-BR.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/pt-BR' { - import {AirDatepickerLocale} from 'air-datepicker'; - const pt-BR: AirDatepickerLocale; - - export default pt-BR; -} diff --git a/src/ui/static/js/air-datepicker/locale/pt-BR.js b/src/ui/static/js/air-datepicker/locale/pt-BR.js deleted file mode 100644 index 455b3a5aa..000000000 --- a/src/ui/static/js/air-datepicker/locale/pt-BR.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'], - daysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], - daysMin: ['Do', 'Se', 'Te', 'Qu', 'Qu', 'Se', 'Sa'], - months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], - monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], - today: 'Hoje', - clear: 'Limpar', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'HH:mm', - firstDay: 0 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/pt.d.ts b/src/ui/static/js/air-datepicker/locale/pt.d.ts deleted file mode 100644 index 8881f43e7..000000000 --- a/src/ui/static/js/air-datepicker/locale/pt.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/pt' { - import {AirDatepickerLocale} from 'air-datepicker'; - const pt: AirDatepickerLocale; - - export default pt; -} diff --git a/src/ui/static/js/air-datepicker/locale/pt.js b/src/ui/static/js/air-datepicker/locale/pt.js deleted file mode 100644 index ff2c0cda6..000000000 --- a/src/ui/static/js/air-datepicker/locale/pt.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'], - daysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], - daysMin: ['Do', 'Se', 'Te', 'Qa', 'Qi', 'Sx', 'Sa'], - months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], - monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], - today: 'Hoje', - clear: 'Limpar', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/ro.d.ts b/src/ui/static/js/air-datepicker/locale/ro.d.ts deleted file mode 100644 index 7bfde1a1f..000000000 --- a/src/ui/static/js/air-datepicker/locale/ro.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/ro' { - import {AirDatepickerLocale} from 'air-datepicker'; - const ro: AirDatepickerLocale; - - export default ro; -} diff --git a/src/ui/static/js/air-datepicker/locale/ro.js b/src/ui/static/js/air-datepicker/locale/ro.js deleted file mode 100644 index a65920d0d..000000000 --- a/src/ui/static/js/air-datepicker/locale/ro.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], - daysShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], - daysMin: ['D', 'L', 'Ma', 'Mi', 'J', 'V', 'S'], - months: ['Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie'], - monthsShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'], - today: 'Azi', - clear: 'Şterge', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/ru.d.ts b/src/ui/static/js/air-datepicker/locale/ru.d.ts deleted file mode 100644 index 0d2e8fe5c..000000000 --- a/src/ui/static/js/air-datepicker/locale/ru.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/ru' { - import {AirDatepickerLocale} from 'air-datepicker'; - const ru: AirDatepickerLocale; - - export default ru; -} diff --git a/src/ui/static/js/air-datepicker/locale/ru.js b/src/ui/static/js/air-datepicker/locale/ru.js deleted file mode 100644 index 8910ba5bf..000000000 --- a/src/ui/static/js/air-datepicker/locale/ru.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'], - daysShort: ['Вос', 'Пон', 'Вто', 'Сре', 'Чет', 'Пят', 'Суб'], - daysMin: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'], - months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], - monthsShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], - today: 'Сегодня', - clear: 'Очистить', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/si.d.ts b/src/ui/static/js/air-datepicker/locale/si.d.ts deleted file mode 100644 index 59b6c2b1a..000000000 --- a/src/ui/static/js/air-datepicker/locale/si.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/si' { - import {AirDatepickerLocale} from 'air-datepicker'; - const si: AirDatepickerLocale; - - export default si; -} diff --git a/src/ui/static/js/air-datepicker/locale/si.js b/src/ui/static/js/air-datepicker/locale/si.js deleted file mode 100644 index fa5878642..000000000 --- a/src/ui/static/js/air-datepicker/locale/si.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['ඉරිදා', 'සදුදා', 'අඟහරැවදා', 'බදාදා', 'බ්‍රහස්‍පතින්‍', 'සිකුරාදා', 'සෙනසුරාදා'], - daysShort: ['ඉරිදා', 'සදුදා', 'අඟහ', 'බදාදා', 'බ්‍රහස්‍', 'සිකුරා', 'සෙන'], - daysMin: ['ඉරි', 'සදු', 'අඟ', 'බදා', 'බ්‍රහ', 'සිකු', 'සෙ'], - months: ['ජනවාරි', 'පෙබරවාරි', 'මාර්තු', 'අප්‍රේල්', 'මැයි', 'ජූනි', 'ජූලි', 'අගෝස්තු', 'සැප්තැම්බර්', 'ඔක්තෝබර්', 'නොවැම්බර්', 'දෙසැම්බර්'], - monthsShort: ['ජන', 'පෙබ', 'මාර්', 'අප්‍රේල්', 'මැයි', 'ජූනි', 'ජූලි', 'අගෝ', 'සැප්', 'ඔක්', 'නොවැ', 'දෙසැ'], - today: 'අද', - clear: 'යලි සකසන්න', - dateFormat: 'yyyy-mm-dd', - timeFormat: 'hh:ii aa', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/sk.d.ts b/src/ui/static/js/air-datepicker/locale/sk.d.ts deleted file mode 100644 index e0f2d0a28..000000000 --- a/src/ui/static/js/air-datepicker/locale/sk.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/sk' { - import {AirDatepickerLocale} from 'air-datepicker'; - const sk: AirDatepickerLocale; - - export default sk; -} diff --git a/src/ui/static/js/air-datepicker/locale/sk.js b/src/ui/static/js/air-datepicker/locale/sk.js deleted file mode 100644 index b3146e3d9..000000000 --- a/src/ui/static/js/air-datepicker/locale/sk.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Nedeľa', 'Pondelok', 'Utorok', 'Streda', 'Štvrtok', 'Piatok', 'Sobota'], - daysShort: ['Ned', 'Pon', 'Uto', 'Str', 'Štv', 'Pia', 'Sob'], - daysMin: ['Ne', 'Po', 'Ut', 'St', 'Št', 'Pi', 'So'], - months: ['Január', 'Február', 'Marec', 'Apríl', 'Máj', 'Jún', 'Júl', 'August', 'September', 'Október', 'November', 'December'], - monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], - today: 'Dnes', - clear: 'Vymazať', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/sv.d.ts b/src/ui/static/js/air-datepicker/locale/sv.d.ts deleted file mode 100644 index c8f20bd1b..000000000 --- a/src/ui/static/js/air-datepicker/locale/sv.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/sv' { - import {AirDatepickerLocale} from 'air-datepicker'; - const sv: AirDatepickerLocale; - - export default sv; -} diff --git a/src/ui/static/js/air-datepicker/locale/sv.js b/src/ui/static/js/air-datepicker/locale/sv.js deleted file mode 100644 index 5d775c3d8..000000000 --- a/src/ui/static/js/air-datepicker/locale/sv.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Söndag', 'Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lördag'], - daysShort: ['Sön', 'Mån', 'Tis', 'Ons', 'Tor', 'Fre', 'Lör'], - daysMin: ['Sö', 'Må', 'Ti', 'On', 'To', 'Fr', 'Lö'], - months: ['Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December'], - monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], - today: 'I dag', - clear: 'Nollställ', - dateFormat: 'yyyy-MM-dd', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/th.d.ts b/src/ui/static/js/air-datepicker/locale/th.d.ts deleted file mode 100644 index 79f604363..000000000 --- a/src/ui/static/js/air-datepicker/locale/th.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/th' { - import {AirDatepickerLocale} from 'air-datepicker'; - const th: AirDatepickerLocale; - - export default th; -} diff --git a/src/ui/static/js/air-datepicker/locale/th.js b/src/ui/static/js/air-datepicker/locale/th.js deleted file mode 100644 index bf46ca49c..000000000 --- a/src/ui/static/js/air-datepicker/locale/th.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['วันอาทิตย์', 'วันจันทร์', 'วันอังคาร', 'วันพุธ', 'วันพฤหัสบดี', 'วันศุกร์', 'วันเสาร์'], - daysShort: ['อา.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.'], - daysMin: ['อา.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.'], - months: ['มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'], - monthsShort: ['ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'], - today: 'วันนี้', - clear: 'ล้าง', - dateFormat: 'dd/MM/yyyy', - timeFormat: 'HH:mm', - firstDay: 0 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/tr.d.ts b/src/ui/static/js/air-datepicker/locale/tr.d.ts deleted file mode 100644 index d5b63430f..000000000 --- a/src/ui/static/js/air-datepicker/locale/tr.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/tr' { - import {AirDatepickerLocale} from 'air-datepicker'; - const tr: AirDatepickerLocale; - - export default tr; -} diff --git a/src/ui/static/js/air-datepicker/locale/tr.js b/src/ui/static/js/air-datepicker/locale/tr.js deleted file mode 100644 index 94939b0ab..000000000 --- a/src/ui/static/js/air-datepicker/locale/tr.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi'], - daysShort: ['Pzr', 'Pts', 'Sl', 'Çar', 'Per', 'Cum', 'Cts'], - daysMin: ['Pa', 'Pt', 'Sl', 'Ça', 'Pe', 'Cu', 'Ct'], - months: ['Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'], - monthsShort: ['Oca', 'Şbt', 'Mrt', 'Nsn', 'Mys', 'Hzr', 'Tmz', 'Ağt', 'Eyl', 'Ekm', 'Ksm', 'Arl'], - today: 'Bugün', - clear: 'Temizle', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'hh:mm aa', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/uk.d.ts b/src/ui/static/js/air-datepicker/locale/uk.d.ts deleted file mode 100644 index e09b47450..000000000 --- a/src/ui/static/js/air-datepicker/locale/uk.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/uk' { - import {AirDatepickerLocale} from 'air-datepicker'; - const uk: AirDatepickerLocale; - - export default uk; -} diff --git a/src/ui/static/js/air-datepicker/locale/uk.js b/src/ui/static/js/air-datepicker/locale/uk.js deleted file mode 100644 index f71db2b99..000000000 --- a/src/ui/static/js/air-datepicker/locale/uk.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['Неділя', 'Понеділок', 'Вівторок', 'Середа', 'Четвер', 'П’ятниця', 'Субота'], - daysShort: ['Нед', 'Пнд', 'Вів', 'Срд', 'Чтв', 'Птн', 'Сбт'], - daysMin: ['Нд', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'], - months: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень'], - monthsShort: ['Січ', 'Лют', 'Бер', 'Кві', 'Тра', 'Чер', 'Лип', 'Сер', 'Вер', 'Жов', 'Лис', 'Гру'], - today: 'Сьогодні', - clear: 'Очистити', - dateFormat: 'dd.MM.yyyy', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/air-datepicker/locale/zh.d.ts b/src/ui/static/js/air-datepicker/locale/zh.d.ts deleted file mode 100644 index 5e6be4f98..000000000 --- a/src/ui/static/js/air-datepicker/locale/zh.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'air-datepicker/locale/zh' { - import {AirDatepickerLocale} from 'air-datepicker'; - const zh: AirDatepickerLocale; - - export default zh; -} diff --git a/src/ui/static/js/air-datepicker/locale/zh.js b/src/ui/static/js/air-datepicker/locale/zh.js deleted file mode 100644 index 4a2b48ba4..000000000 --- a/src/ui/static/js/air-datepicker/locale/zh.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = void 0; -var _default = { - days: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], - daysShort: ['日', '一', '二', '三', '四', '五', '六'], - daysMin: ['日', '一', '二', '三', '四', '五', '六'], - months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], - monthsShort: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], - today: '今天', - clear: '清除', - dateFormat: 'yyyy-MM-dd', - timeFormat: 'HH:mm', - firstDay: 1 -}; -exports.default = _default; \ No newline at end of file diff --git a/src/ui/static/js/dashboard.js b/src/ui/static/js/dashboard.js index fbb264ca5..a9b6e35a5 100644 --- a/src/ui/static/js/dashboard.js +++ b/src/ui/static/js/dashboard.js @@ -44,6 +44,7 @@ class darkMode { this.htmlEl = document.querySelector("html"); this.darkToggleEl = document.querySelector("[dark-toggle]"); this.darkToggleLabel = document.querySelector("[dark-toggle-label]"); + this.csrf = document.querySelector("input#csrf_token"); this.init(); } @@ -63,14 +64,13 @@ class darkMode { async saveMode() { const isDark = this.darkToggleEl.checked ? "true" : "false"; - console.log(isDark); const data = { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, - body: JSON.stringify({ darkmode: isDark }), + body: JSON.stringify({ darkmode: isDark, csrf_token: this.csrf.value }), }; const send = await fetch(`${location.href}/darkmode}`, data); } diff --git a/src/ui/static/js/datepicker/DateRangePicker.js b/src/ui/static/js/datepicker/DateRangePicker.js new file mode 100644 index 000000000..0f5fa702e --- /dev/null +++ b/src/ui/static/js/datepicker/DateRangePicker.js @@ -0,0 +1,210 @@ +import {registerListeners, unregisterListeners} from './lib/event.js'; +import {formatDate} from './lib/date-format.js'; +import Datepicker from './Datepicker.js'; + +// filter out the config options inapproprite to pass to Datepicker +function filterOptions(options) { + const newOpts = Object.assign({}, options); + + delete newOpts.inputs; + delete newOpts.allowOneSidedRange; + delete newOpts.maxNumberOfDates; // to ensure each datepicker handles a single date + + return newOpts; +} + +function setupDatepicker(rangepicker, changeDateListener, el, options) { + registerListeners(rangepicker, [ + [el, 'changeDate', changeDateListener], + ]); + new Datepicker(el, options, rangepicker); +} + +function onChangeDate(rangepicker, ev) { + // to prevent both datepickers trigger the other side's update each other + if (rangepicker._updating) { + return; + } + rangepicker._updating = true; + + const target = ev.target; + if (target.datepicker === undefined) { + return; + } + + const datepickers = rangepicker.datepickers; + const setDateOptions = {render: false}; + const changedSide = rangepicker.inputs.indexOf(target); + const otherSide = changedSide === 0 ? 1 : 0; + const changedDate = datepickers[changedSide].dates[0]; + const otherDate = datepickers[otherSide].dates[0]; + + if (changedDate !== undefined && otherDate !== undefined) { + // if the start of the range > the end, swap them + if (changedSide === 0 && changedDate > otherDate) { + datepickers[0].setDate(otherDate, setDateOptions); + datepickers[1].setDate(changedDate, setDateOptions); + } else if (changedSide === 1 && changedDate < otherDate) { + datepickers[0].setDate(changedDate, setDateOptions); + datepickers[1].setDate(otherDate, setDateOptions); + } + } else if (!rangepicker.allowOneSidedRange) { + // to prevent the range from becoming one-sided, copy changed side's + // selection (no matter if it's empty) to the other side + if (changedDate !== undefined || otherDate !== undefined) { + setDateOptions.clear = true; + datepickers[otherSide].setDate(datepickers[changedSide].dates, setDateOptions); + } + } + datepickers[0].picker.update().render(); + datepickers[1].picker.update().render(); + delete rangepicker._updating; +} + +/** + * Class representing a date range picker + */ +export default class DateRangePicker { + /** + * Create a date range picker + * @param {Element} element - element to bind a date range picker + * @param {Object} [options] - config options + */ + constructor(element, options = {}) { + const inputs = Array.isArray(options.inputs) + ? options.inputs + : Array.from(element.querySelectorAll('input')); + if (inputs.length < 2) { + return; + } + + element.rangepicker = this; + this.element = element; + this.inputs = inputs.slice(0, 2); + this.allowOneSidedRange = !!options.allowOneSidedRange; + + const changeDateListener = onChangeDate.bind(null, this); + const cleanOptions = filterOptions(options); + // in order for initial date setup to work right when pcicLvel > 0, + // let Datepicker constructor add the instance to the rangepicker + const datepickers = []; + Object.defineProperty(this, 'datepickers', { + get() { + return datepickers; + }, + }); + setupDatepicker(this, changeDateListener, this.inputs[0], cleanOptions); + setupDatepicker(this, changeDateListener, this.inputs[1], cleanOptions); + Object.freeze(datepickers); + // normalize the range if inital dates are given + if (datepickers[0].dates.length > 0) { + onChangeDate(this, {target: this.inputs[0]}); + } else if (datepickers[1].dates.length > 0) { + onChangeDate(this, {target: this.inputs[1]}); + } + } + + /** + * @type {Array} - selected date of the linked date pickers + */ + get dates() { + return this.datepickers.length === 2 + ? [ + this.datepickers[0].dates[0], + this.datepickers[1].dates[0], + ] + : undefined; + } + + /** + * Set new values to the config options + * @param {Object} options - config options to update + */ + setOptions(options) { + this.allowOneSidedRange = !!options.allowOneSidedRange; + + const cleanOptions = filterOptions(options); + this.datepickers[0].setOptions(cleanOptions); + this.datepickers[1].setOptions(cleanOptions); + } + + /** + * Destroy the DateRangePicker instance + * @return {DateRangePicker} - the instance destroyed + */ + destroy() { + this.datepickers[0].destroy(); + this.datepickers[1].destroy(); + unregisterListeners(this); + delete this.element.rangepicker; + } + + /** + * Get the start and end dates of the date range + * + * The method returns Date objects by default. If format string is passed, + * it returns date strings formatted in given format. + * The result array always contains 2 items (start date/end date) and + * undefined is used for unselected side. (e.g. If none is selected, + * the result will be [undefined, undefined]. If only the end date is set + * when allowOneSidedRange config option is true, [undefined, endDate] will + * be returned.) + * + * @param {String} [format] - Format string to stringify the dates + * @return {Array} - Start and end dates + */ + getDates(format = undefined) { + const callback = format + ? date => formatDate(date, format, this.datepickers[0].config.locale) + : date => new Date(date); + + return this.dates.map(date => date === undefined ? date : callback(date)); + } + + /** + * Set the start and end dates of the date range + * + * The method calls datepicker.setDate() internally using each of the + * arguments in start→end order. + * + * When a clear: true option object is passed instead of a date, the method + * clears the date. + * + * If an invalid date, the same date as the current one or an option object + * without clear: true is passed, the method considers that argument as an + * "ineffective" argument because calling datepicker.setDate() with those + * values makes no changes to the date selection. + * + * When the allowOneSidedRange config option is false, passing {clear: true} + * to clear the range works only when it is done to the last effective + * argument (in other words, passed to rangeEnd or to rangeStart along with + * ineffective rangeEnd). This is because when the date range is changed, + * it gets normalized based on the last change at the end of the changing + * process. + * + * @param {Date|Number|String|Object} rangeStart - Start date of the range + * or {clear: true} to clear the date + * @param {Date|Number|String|Object} rangeEnd - End date of the range + * or {clear: true} to clear the date + */ + setDates(rangeStart, rangeEnd) { + const [datepicker0, datepicker1] = this.datepickers; + const origDates = this.dates; + + // If range normalization runs on every change, we can't set a new range + // that starts after the end of the current range correctly because the + // normalization process swaps start↔︎end right after setting the new start + // date. To prevent this, the normalization process needs to run once after + // both of the new dates are set. + this._updating = true; + datepicker0.setDate(rangeStart); + datepicker1.setDate(rangeEnd); + delete this._updating; + + if (datepicker1.dates[0] !== origDates[1]) { + onChangeDate(this, {target: this.inputs[1]}); + } else if (datepicker0.dates[0] !== origDates[0]) { + onChangeDate(this, {target: this.inputs[0]}); + } + } +} diff --git a/src/ui/static/js/datepicker/Datepicker.js b/src/ui/static/js/datepicker/Datepicker.js new file mode 100644 index 000000000..babffc06b --- /dev/null +++ b/src/ui/static/js/datepicker/Datepicker.js @@ -0,0 +1,502 @@ +import {lastItemOf, stringToArray, isInRange} from './lib/utils.js'; +import {today, regularizeDate} from './lib/date.js'; +import {parseDate, formatDate} from './lib/date-format.js'; +import {isActiveElement} from './lib/dom.js'; +import {registerListeners, unregisterListeners} from './lib/event.js'; +import {locales} from './i18n/base-locales.js'; +import defaultOptions from './options/defaultOptions.js'; +import processOptions from './options/processOptions.js'; +import Picker from './picker/Picker.js'; +import {triggerDatepickerEvent} from './events/functions.js'; +import {onKeydown, onFocus, onMousedown, onClickInput, onPaste} from './events/inputFieldListeners.js'; +import {onClickOutside} from './events/otherListeners.js'; + +function stringifyDates(dates, config) { + return dates + .map(dt => formatDate(dt, config.format, config.locale)) + .join(config.dateDelimiter); +} + +// parse input dates and create an array of time values for selection +// returns undefined if there are no valid dates in inputDates +// when origDates (current selection) is passed, the function works to mix +// the input dates into the current selection +function processInputDates(datepicker, inputDates, clear = false) { + // const {config, dates: origDates, rangepicker} = datepicker; + const {config, dates: origDates, rangeSideIndex} = datepicker; + if (inputDates.length === 0) { + // empty input is considered valid unless origiDates is passed + return clear ? [] : undefined; + } + + // const rangeEnd = rangepicker && datepicker === rangepicker.datepickers[1]; + let newDates = inputDates.reduce((dates, dt) => { + let date = parseDate(dt, config.format, config.locale); + if (date === undefined) { + return dates; + } + // adjust to 1st of the month/Jan 1st of the year + // or to the last day of the monh/Dec 31st of the year if the datepicker + // is the range-end picker of a rangepicker + date = regularizeDate(date, config.pickLevel, rangeSideIndex); + if ( + isInRange(date, config.minDate, config.maxDate) + && !dates.includes(date) + && !config.datesDisabled.includes(date) + && (config.pickLevel > 0 || !config.daysOfWeekDisabled.includes(new Date(date).getDay())) + ) { + dates.push(date); + } + return dates; + }, []); + if (newDates.length === 0) { + return; + } + if (config.multidate && !clear) { + // get the synmetric difference between origDates and newDates + newDates = newDates.reduce((dates, date) => { + if (!origDates.includes(date)) { + dates.push(date); + } + return dates; + }, origDates.filter(date => !newDates.includes(date))); + } + // do length check always because user can input multiple dates regardless of the mode + return config.maxNumberOfDates && newDates.length > config.maxNumberOfDates + ? newDates.slice(config.maxNumberOfDates * -1) + : newDates; +} + +// refresh the UI elements +// modes: 1: input only, 2, picker only, 3 both +function refreshUI(datepicker, mode = 3, quickRender = true) { + const {config, picker, inputField} = datepicker; + if (mode & 2) { + const newView = picker.active ? config.pickLevel : config.startView; + picker.update().changeView(newView).render(quickRender); + } + if (mode & 1 && inputField) { + inputField.value = stringifyDates(datepicker.dates, config); + } +} + +function setDate(datepicker, inputDates, options) { + let {clear, render, autohide, revert} = options; + if (render === undefined) { + render = true; + } + if (!render) { + autohide = false; + } else if (autohide === undefined) { + autohide = datepicker.config.autohide; + } + + const newDates = processInputDates(datepicker, inputDates, clear); + if (!newDates && !revert) { + return; + } + if (newDates && newDates.toString() !== datepicker.dates.toString()) { + datepicker.dates = newDates; + refreshUI(datepicker, render ? 3 : 1); + triggerDatepickerEvent(datepicker, 'changeDate'); + } else { + refreshUI(datepicker, 1); + } + + if (autohide) { + datepicker.hide(); + } +} + +/** + * Class representing a date picker + */ +export default class Datepicker { + /** + * Create a date picker + * @param {Element} element - element to bind a date picker + * @param {Object} [options] - config options + * @param {DateRangePicker} [rangepicker] - DateRangePicker instance the + * date picker belongs to. Use this only when creating date picker as a part + * of date range picker + */ + constructor(element, options = {}, rangepicker = undefined) { + element.datepicker = this; + this.element = element; + + const config = this.config = Object.assign({ + buttonClass: (options.buttonClass && String(options.buttonClass)) || 'button', + container: null, + defaultViewDate: today(), + maxDate: undefined, + minDate: undefined, + }, processOptions(defaultOptions, this)); + // configure by type + const inline = this.inline = element.tagName !== 'INPUT'; + let inputField; + if (inline) { + config.container = element; + } else { + if (options.container) { + // omit string type check because it doesn't guarantee to avoid errors + // (invalid selector string causes abend with sytax error) + config.container = options.container instanceof HTMLElement + ? options.container + : document.querySelector(options.container); + } + inputField = this.inputField = element; + inputField.classList.add('datepicker-input'); + } + if (rangepicker) { + // check validiry + const index = rangepicker.inputs.indexOf(inputField); + const datepickers = rangepicker.datepickers; + if (index < 0 || index > 1 || !Array.isArray(datepickers)) { + throw Error('Invalid rangepicker object.'); + } + // attach itaelf to the rangepicker here so that processInputDates() can + // determine if this is the range-end picker of the rangepicker while + // setting inital values when pickLevel > 0 + datepickers[index] = this; + // add getter for rangepicker + Object.defineProperty(this, 'rangepicker', { + get() { + return rangepicker; + }, + }); + Object.defineProperty(this, 'rangeSideIndex', { + get() { + return index; + }, + }); + } + + // set up config + this._options = options; + Object.assign(config, processOptions(options, this)); + + // set initial dates + let initialDates; + if (inline) { + initialDates = stringToArray(element.dataset.date, config.dateDelimiter); + delete element.dataset.date; + } else { + initialDates = stringToArray(inputField.value, config.dateDelimiter); + } + this.dates = []; + // process initial value + const inputDateValues = processInputDates(this, initialDates); + if (inputDateValues && inputDateValues.length > 0) { + this.dates = inputDateValues; + } + if (inputField) { + inputField.value = stringifyDates(this.dates, config); + } + + const picker = this.picker = new Picker(this); + + if (inline) { + this.show(); + } else { + // set up event listeners in other modes + const onMousedownDocument = onClickOutside.bind(null, this); + const listeners = [ + [inputField, 'keydown', onKeydown.bind(null, this)], + [inputField, 'focus', onFocus.bind(null, this)], + [inputField, 'mousedown', onMousedown.bind(null, this)], + [inputField, 'click', onClickInput.bind(null, this)], + [inputField, 'paste', onPaste.bind(null, this)], + [document, 'mousedown', onMousedownDocument], + [document, 'touchstart', onMousedownDocument], + [window, 'resize', picker.place.bind(picker)] + ]; + registerListeners(this, listeners); + } + } + + /** + * Format Date object or time value in given format and language + * @param {Date|Number} date - date or time value to format + * @param {String|Object} format - format string or object that contains + * toDisplay() custom formatter, whose signature is + * - args: + * - date: {Date} - Date instance of the date passed to the method + * - format: {Object} - the format object passed to the method + * - locale: {Object} - locale for the language specified by `lang` + * - return: + * {String} formatted date + * @param {String} [lang=en] - language code for the locale to use + * @return {String} formatted date + */ + static formatDate(date, format, lang) { + return formatDate(date, format, lang && locales[lang] || locales.en); + } + + /** + * Parse date string + * @param {String|Date|Number} dateStr - date string, Date object or time + * value to parse + * @param {String|Object} format - format string or object that contains + * toValue() custom parser, whose signature is + * - args: + * - dateStr: {String|Date|Number} - the dateStr passed to the method + * - format: {Object} - the format object passed to the method + * - locale: {Object} - locale for the language specified by `lang` + * - return: + * {Date|Number} parsed date or its time value + * @param {String} [lang=en] - language code for the locale to use + * @return {Number} time value of parsed date + */ + static parseDate(dateStr, format, lang) { + return parseDate(dateStr, format, lang && locales[lang] || locales.en); + } + + /** + * @type {Object} - Installed locales in `[languageCode]: localeObject` format + * en`:_English (US)_ is pre-installed. + */ + static get locales() { + return locales; + } + + /** + * @type {Boolean} - Whether the picker element is shown. `true` whne shown + */ + get active() { + return !!(this.picker && this.picker.active); + } + + /** + * @type {HTMLDivElement} - DOM object of picker element + */ + get pickerElement() { + return this.picker ? this.picker.element : undefined; + } + + /** + * Set new values to the config options + * @param {Object} options - config options to update + */ + setOptions(options) { + const picker = this.picker; + const newOptions = processOptions(options, this); + Object.assign(this._options, options); + Object.assign(this.config, newOptions); + picker.setOptions(newOptions); + + refreshUI(this, 3); + } + + /** + * Show the picker element + */ + show() { + if (this.inputField) { + if (this.inputField.disabled) { + return; + } + if (!isActiveElement(this.inputField) && !this.config.disableTouchKeyboard) { + this._showing = true; + this.inputField.focus(); + delete this._showing; + } + } + this.picker.show(); + } + + /** + * Hide the picker element + * Not available on inline picker + */ + hide() { + if (this.inline) { + return; + } + this.picker.hide(); + this.picker.update().changeView(this.config.startView).render(); + } + + /** + * Destroy the Datepicker instance + * @return {Detepicker} - the instance destroyed + */ + destroy() { + this.hide(); + unregisterListeners(this); + this.picker.detach(); + if (!this.inline) { + this.inputField.classList.remove('datepicker-input'); + } + delete this.element.datepicker; + return this; + } + + /** + * Get the selected date(s) + * + * The method returns a Date object of selected date by default, and returns + * an array of selected dates in multidate mode. If format string is passed, + * it returns date string(s) formatted in given format. + * + * @param {String} [format] - Format string to stringify the date(s) + * @return {Date|String|Date[]|String[]} - selected date(s), or if none is + * selected, empty array in multidate mode and untitled in sigledate mode + */ + getDate(format = undefined) { + const callback = format + ? date => formatDate(date, format, this.config.locale) + : date => new Date(date); + + if (this.config.multidate) { + return this.dates.map(callback); + } + if (this.dates.length > 0) { + return callback(this.dates[0]); + } + } + + /** + * Set selected date(s) + * + * In multidate mode, you can pass multiple dates as a series of arguments + * or an array. (Since each date is parsed individually, the type of the + * dates doesn't have to be the same.) + * The given dates are used to toggle the select status of each date. The + * number of selected dates is kept from exceeding the length set to + * maxNumberOfDates. + * + * With clear: true option, the method can be used to clear the selection + * and to replace the selection instead of toggling in multidate mode. + * If the option is passed with no date arguments or an empty dates array, + * it works as "clear" (clear the selection then set nothing), and if the + * option is passed with new dates to select, it works as "replace" (clear + * the selection then set the given dates) + * + * When render: false option is used, the method omits re-rendering the + * picker element. In this case, you need to call refresh() method later in + * order for the picker element to reflect the changes. The input field is + * refreshed always regardless of this option. + * + * When invalid (unparsable, repeated, disabled or out-of-range) dates are + * passed, the method ignores them and applies only valid ones. In the case + * that all the given dates are invalid, which is distinguished from passing + * no dates, the method considers it as an error and leaves the selection + * untouched. (The input field also remains untouched unless revert: true + * option is used.) + * + * @param {...(Date|Number|String)|Array} [dates] - Date strings, Date + * objects, time values or mix of those for new selection + * @param {Object} [options] - function options + * - clear: {boolean} - Whether to clear the existing selection + * defualt: false + * - render: {boolean} - Whether to re-render the picker element + * default: true + * - autohide: {boolean} - Whether to hide the picker element after re-render + * Ignored when used with render: false + * default: config.autohide + * - revert: {boolean} - Whether to refresh the input field when all the + * passed dates are invalid + * default: false + */ + setDate(...args) { + const dates = [...args]; + const opts = {}; + const lastArg = lastItemOf(args); + if ( + typeof lastArg === 'object' + && !Array.isArray(lastArg) + && !(lastArg instanceof Date) + && lastArg + ) { + Object.assign(opts, dates.pop()); + } + + const inputDates = Array.isArray(dates[0]) ? dates[0] : dates; + setDate(this, inputDates, opts); + } + + /** + * Update the selected date(s) with input field's value + * Not available on inline picker + * + * The input field will be refreshed with properly formatted date string. + * + * In the case that all the entered dates are invalid (unparsable, repeated, + * disabled or out-of-range), whixh is distinguished from empty input field, + * the method leaves the input field untouched as well as the selection by + * default. If revert: true option is used in this case, the input field is + * refreshed with the existing selection. + * + * @param {Object} [options] - function options + * - autohide: {boolean} - whether to hide the picker element after refresh + * default: false + * - revert: {boolean} - Whether to refresh the input field when all the + * passed dates are invalid + * default: false + */ + update(options = undefined) { + if (this.inline) { + return; + } + + const opts = Object.assign(options || {}, {clear: true, render: true}); + const inputDates = stringToArray(this.inputField.value, this.config.dateDelimiter); + setDate(this, inputDates, opts); + } + + /** + * Refresh the picker element and the associated input field + * @param {String} [target] - target item when refreshing one item only + * 'picker' or 'input' + * @param {Boolean} [forceRender] - whether to re-render the picker element + * regardless of its state instead of optimized refresh + */ + refresh(target = undefined, forceRender = false) { + if (target && typeof target !== 'string') { + forceRender = target; + target = undefined; + } + + let mode; + if (target === 'picker') { + mode = 2; + } else if (target === 'input') { + mode = 1; + } else { + mode = 3; + } + refreshUI(this, mode, !forceRender); + } + + /** + * Enter edit mode + * Not available on inline picker or when the picker element is hidden + */ + enterEditMode() { + if (this.inline || !this.picker.active || this.editMode) { + return; + } + this.editMode = true; + this.inputField.classList.add('in-edit'); + } + + /** + * Exit from edit mode + * Not available on inline picker + * @param {Object} [options] - function options + * - update: {boolean} - whether to call update() after exiting + * If false, input field is revert to the existing selection + * default: false + */ + exitEditMode(options = undefined) { + if (this.inline || !this.editMode) { + return; + } + const opts = Object.assign({update: false}, options); + delete this.editMode; + this.inputField.classList.remove('in-edit'); + if (opts.update) { + this.update(opts); + } + } +} diff --git a/src/ui/static/js/datepicker/datepicker-full.js b/src/ui/static/js/datepicker/datepicker-full.js new file mode 100644 index 000000000..b054896ac --- /dev/null +++ b/src/ui/static/js/datepicker/datepicker-full.js @@ -0,0 +1,5 @@ +import Datepicker from './Datepicker.js'; +import DateRangePicker from './DateRangePicker.js'; + +window.Datepicker = Datepicker; +window.DateRangePicker = DateRangePicker; diff --git a/src/ui/static/js/datepicker/datepicker-full.min.js b/src/ui/static/js/datepicker/datepicker-full.min.js new file mode 100644 index 000000000..dab79456b --- /dev/null +++ b/src/ui/static/js/datepicker/datepicker-full.min.js @@ -0,0 +1 @@ +!function(){"use strict";function e(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function t(e){return e[e.length-1]}function i(e,...t){return t.forEach((t=>{e.includes(t)||e.push(t)})),e}function s(e,t){return e?e.split(t):[]}function n(e,t,i){return(void 0===t||e>=t)&&(void 0===i||e<=i)}function a(e,t,i){return ei?i:e}function r(e,t,i={},s=0,n=""){n+=`<${Object.keys(i).reduce(((e,t)=>{let n=i[t];return"function"==typeof n&&(n=n(s)),`${e} ${t}="${n}"`}),e)}>`;const a=s+1;return a\s+/g,">").replace(/\s+new Date(e).setFullYear(parseInt(t,10)),m(e,t,i){const s=new Date(e);let n=parseInt(t,10)-1;if(isNaN(n)){if(!t)return NaN;const e=t.toLowerCase(),s=t=>t.toLowerCase().startsWith(e);if(n=i.monthsShort.findIndex(s),n<0&&(n=i.months.findIndex(s)),n<0)return NaN}return s.setMonth(n),s.getMonth()!==x(n)?s.setDate(0):s.getTime()},d:(e,t)=>new Date(e).setDate(parseInt(t,10))},k={d:e=>e.getDate(),dd:e=>M(e.getDate(),2),D:(e,t)=>t.daysShort[e.getDay()],DD:(e,t)=>t.days[e.getDay()],m:e=>e.getMonth()+1,mm:e=>M(e.getMonth()+1,2),M:(e,t)=>t.monthsShort[e.getMonth()],MM:(e,t)=>t.months[e.getMonth()],y:e=>e.getFullYear(),yy:e=>M(e.getFullYear(),2).slice(-2),yyyy:e=>M(e.getFullYear(),4)};function x(e){return e>-1?e%12:x(e+12)}function M(e,t){return e.toString().padStart(t,"0")}function S(e){if("string"!=typeof e)throw new Error("Invalid date format.");if(e in v)return v[e];const i=e.split(D),s=e.match(new RegExp(D,"g"));if(0===i.length||!s)throw new Error("Invalid date format.");const n=s.map((e=>k[e])),a=Object.keys(b).reduce(((e,t)=>(s.find((e=>"D"!==e[0]&&e[0].toLowerCase()===t))&&e.push(t),e)),[]);return v[e]={parser(e,t){const i=e.split(y).reduce(((e,t,i)=>{if(t.length>0&&s[i]){const n=s[i][0];"M"===n?e.m=t:"D"!==n&&(e[n]=t)}return e}),{});return a.reduce(((e,s)=>{const n=b[s](e,i[s],t);return isNaN(n)?e:n}),c())},formatter:(e,s)=>n.reduce(((t,n,a)=>t+`${i[a]}${n(e,s)}`),"")+t(i)}}function O(e,t,i){if(e instanceof Date||"number"==typeof e){const t=o(e);return isNaN(t)?void 0:t}if(e){if("today"===e)return c();if(t&&t.toValue){const s=t.toValue(e,t,i);return isNaN(s)?void 0:o(s)}return S(t).parser(e,i)}}function C(e,t,i){if(isNaN(e)||!e&&0!==e)return"";const s="number"==typeof e?new Date(e):e;return t.toDisplay?t.toDisplay(s,t,i):S(t).formatter(s,i)}const E=document.createRange();function F(e){return E.createContextualFragment(e)}function V(e){return e.parentElement||(e.parentNode instanceof ShadowRoot?e.parentNode.host:void 0)}function N(e){return e.getRootNode().activeElement===e}function L(e){"none"!==e.style.display&&(e.style.display&&(e.dataset.styleDisplay=e.style.display),e.style.display="none")}function B(e){"none"===e.style.display&&(e.dataset.styleDisplay?(e.style.display=e.dataset.styleDisplay,delete e.dataset.styleDisplay):e.style.display="")}function A(e){e.firstChild&&(e.removeChild(e.firstChild),A(e))}const Y=new WeakMap,{addEventListener:W,removeEventListener:H}=EventTarget.prototype;function j(e,t){let i=Y.get(e);i||(i=[],Y.set(e,i)),t.forEach((e=>{W.call(...e),i.push(e)}))}function T(e){let t=Y.get(e);t&&(t.forEach((e=>{H.call(...e)})),Y.delete(e))}if(!Event.prototype.composedPath){const e=(t,i=[])=>{let s;return i.push(t),t.parentNode?s=t.parentNode:t.host?s=t.host:t.defaultView&&(s=t.defaultView),s?e(s,i):i};Event.prototype.composedPath=function(){return e(this.target)}}function _(e,t,i){const[s,...n]=e;return t(s)?s:s!==i&&"HTML"!==s.tagName&&0!==n.length?_(n,t,i):void 0}function K(e,t){const i="function"==typeof t?t:e=>e instanceof Element&&e.matches(t);return _(e.composedPath(),i,e.currentTarget)}const $={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear",titleFormat:"MM y"}},R={autohide:!1,beforeShowDay:null,beforeShowDecade:null,beforeShowMonth:null,beforeShowYear:null,calendarWeeks:!1,clearBtn:!1,dateDelimiter:",",datesDisabled:[],daysOfWeekDisabled:[],daysOfWeekHighlighted:[],defaultViewDate:void 0,disableTouchKeyboard:!1,format:"mm/dd/yyyy",language:"en",maxDate:null,maxNumberOfDates:1,maxView:3,minDate:null,nextArrow:"»",orientation:"auto",pickLevel:0,prevArrow:"«",showDaysOfWeek:!0,showOnClick:!0,showOnFocus:!0,startView:0,title:"",todayBtn:!1,todayBtnMode:0,todayHighlight:!1,updateOnBlur:!0,weekStart:0},{language:I,format:P,weekStart:q}=R;function J(e,t){return e.length<6&&t>=0&&t<7?i(e,t):e}function U(e){return(e+6)%7}function z(e,t,i,s){const n=O(e,t,i);return void 0!==n?n:s}function X(e,t,i=3){const s=parseInt(e,10);return s>=0&&s<=i?s:t}function G(t,s){const n=Object.assign({},t),a={},r=s.constructor.locales,d=s.rangeSideIndex;let{format:o,language:c,locale:h,maxDate:u,maxView:f,minDate:p,pickLevel:g,startView:m,weekStart:y}=s.config||{};if(n.language){let e;if(n.language!==c&&(r[n.language]?e=n.language:(e=n.language.split("-")[0],void 0===r[e]&&(e=!1))),delete n.language,e){c=a.language=e;const t=h||r[I];h=Object.assign({format:P,weekStart:q},r[I]),c!==I&&Object.assign(h,r[c]),a.locale=h,o===t.format&&(o=a.format=h.format),y===t.weekStart&&(y=a.weekStart=h.weekStart,a.weekEnd=U(h.weekStart))}}if(n.format){const e="function"==typeof n.format.toDisplay,t="function"==typeof n.format.toValue,i=D.test(n.format);(e&&t||i)&&(o=a.format=n.format),delete n.format}let v=g;void 0!==n.pickLevel&&(v=X(n.pickLevel,2),delete n.pickLevel),v!==g&&(v>g&&(void 0===n.minDate&&(n.minDate=p),void 0===n.maxDate&&(n.maxDate=u)),n.datesDisabled||(n.datesDisabled=[]),g=a.pickLevel=v);let b=p,k=u;if(void 0!==n.minDate){const e=l(0,0,1);b=null===n.minDate?e:z(n.minDate,o,h,b),b!==e&&(b=w(b,g,!1)),delete n.minDate}if(void 0!==n.maxDate&&(k=null===n.maxDate?void 0:z(n.maxDate,o,h,k),void 0!==k&&(k=w(k,g,!0)),delete n.maxDate),k{const s=O(t,o,h);return void 0!==s?i(e,w(s,g,d)):e}),[]),delete n.datesDisabled),void 0!==n.defaultViewDate){const e=O(n.defaultViewDate,o,h);void 0!==e&&(a.defaultViewDate=e),delete n.defaultViewDate}if(void 0!==n.weekStart){const e=Number(n.weekStart)%7;isNaN(e)||(y=a.weekStart=e,a.weekEnd=U(e)),delete n.weekStart}if(n.daysOfWeekDisabled&&(a.daysOfWeekDisabled=n.daysOfWeekDisabled.reduce(J,[]),delete n.daysOfWeekDisabled),n.daysOfWeekHighlighted&&(a.daysOfWeekHighlighted=n.daysOfWeekHighlighted.reduce(J,[]),delete n.daysOfWeekHighlighted),void 0!==n.maxNumberOfDates){const e=parseInt(n.maxNumberOfDates,10);e>=0&&(a.maxNumberOfDates=e,a.multidate=1!==e),delete n.maxNumberOfDates}n.dateDelimiter&&(a.dateDelimiter=String(n.dateDelimiter),delete n.dateDelimiter);let x=f;void 0!==n.maxView&&(x=X(n.maxView,f),delete n.maxView),x=g>x?g:x,x!==f&&(f=a.maxView=x);let M=m;if(void 0!==n.startView&&(M=X(n.startView,M),delete n.startView),Mf&&(M=f),M!==m&&(a.startView=M),n.prevArrow){const e=F(n.prevArrow);e.childNodes.length>0&&(a.prevArrow=e.childNodes),delete n.prevArrow}if(n.nextArrow){const e=F(n.nextArrow);e.childNodes.length>0&&(a.nextArrow=e.childNodes),delete n.nextArrow}if(void 0!==n.disableTouchKeyboard&&(a.disableTouchKeyboard="ontouchstart"in document&&!!n.disableTouchKeyboard,delete n.disableTouchKeyboard),n.orientation){const e=n.orientation.toLowerCase().split(/\s+/g);a.orientation={x:e.find((e=>"left"===e||"right"===e))||"auto",y:e.find((e=>"top"===e||"bottom"===e))||"auto"},delete n.orientation}if(void 0!==n.todayBtnMode){switch(n.todayBtnMode){case 0:case 1:a.todayBtnMode=n.todayBtnMode}delete n.todayBtnMode}return Object.keys(n).forEach((t=>{void 0!==n[t]&&e(R,t)&&(a[t]=n[t])})),a}const Q=d('
\n
\n
\n
\n
\n \n \n \n
\n
\n
\n \n
\n
'),Z=d(`
\n
${r("span",7,{class:"dow"})}
\n
${r("span",42)}
\n
`),ee=d(`
\n
\n
${r("span",6,{class:"week"})}
\n
`);class te{constructor(e,t){Object.assign(this,t,{picker:e,element:F('
').firstChild,selected:[]}),this.init(this.picker.datepicker.config)}init(e){void 0!==e.pickLevel&&(this.isMinView=this.id===e.pickLevel),this.setOptions(e),this.updateFocus(),this.updateSelection()}performBeforeHook(e,t,s){let n=this.beforeShow(new Date(s));switch(typeof n){case"boolean":n={enabled:n};break;case"string":n={classes:n}}if(n){if(!1===n.enabled&&(e.classList.add("disabled"),i(this.disabled,t)),n.classes){const s=n.classes.split(/\s+/);e.classList.add(...s),s.includes("disabled")&&i(this.disabled,t)}n.content&&function(e,t){A(e),t instanceof DocumentFragment?e.appendChild(t):"string"==typeof t?e.appendChild(F(t)):"function"==typeof t.forEach&&t.forEach((t=>{e.appendChild(t)}))}(e,n.content)}}}class ie extends te{constructor(e){super(e,{id:0,name:"days",cellClass:"day"})}init(e,t=!0){if(t){const e=F(Z).firstChild;this.dow=e.firstChild,this.grid=e.lastChild,this.element.appendChild(e)}super.init(e)}setOptions(t){let i;if(e(t,"minDate")&&(this.minDate=t.minDate),e(t,"maxDate")&&(this.maxDate=t.maxDate),t.datesDisabled&&(this.datesDisabled=t.datesDisabled),t.daysOfWeekDisabled&&(this.daysOfWeekDisabled=t.daysOfWeekDisabled,i=!0),t.daysOfWeekHighlighted&&(this.daysOfWeekHighlighted=t.daysOfWeekHighlighted),void 0!==t.todayHighlight&&(this.todayHighlight=t.todayHighlight),void 0!==t.weekStart&&(this.weekStart=t.weekStart,this.weekEnd=t.weekEnd,i=!0),t.locale){const e=this.locale=t.locale;this.dayNames=e.daysMin,this.switchLabelFormat=e.titleFormat,i=!0}if(void 0!==t.beforeShowDay&&(this.beforeShow="function"==typeof t.beforeShowDay?t.beforeShowDay:void 0),void 0!==t.calendarWeeks)if(t.calendarWeeks&&!this.calendarWeeks){const e=F(ee).firstChild;this.calendarWeeks={element:e,dow:e.firstChild,weeks:e.lastChild},this.element.insertBefore(e,this.element.firstChild)}else this.calendarWeeks&&!t.calendarWeeks&&(this.element.removeChild(this.calendarWeeks.element),this.calendarWeeks=null);void 0!==t.showDaysOfWeek&&(t.showDaysOfWeek?(B(this.dow),this.calendarWeeks&&B(this.calendarWeeks.dow)):(L(this.dow),this.calendarWeeks&&L(this.calendarWeeks.dow))),i&&Array.from(this.dow.children).forEach(((e,t)=>{const i=(this.weekStart+t)%7;e.textContent=this.dayNames[i],e.className=this.daysOfWeekDisabled.includes(i)?"dow disabled":"dow"}))}updateFocus(){const e=new Date(this.picker.viewDate),t=e.getFullYear(),i=e.getMonth(),s=l(t,i,1),n=g(s,this.weekStart,this.weekStart);this.first=s,this.last=l(t,i+1,0),this.start=n,this.focused=this.picker.viewDate}updateSelection(){const{dates:e,rangepicker:t}=this.picker.datepicker;this.selected=e,t&&(this.range=t.dates)}render(){this.today=this.todayHighlight?c():void 0,this.disabled=[...this.datesDisabled];const e=C(this.focused,this.switchLabelFormat,this.locale);if(this.picker.setViewSwitchLabel(e),this.picker.setPrevBtnDisabled(this.first<=this.minDate),this.picker.setNextBtnDisabled(this.last>=this.maxDate),this.calendarWeeks){const e=g(this.first,1,1);Array.from(this.calendarWeeks.weeks.children).forEach(((t,i)=>{t.textContent=function(e){const t=g(e,4,1),i=g(new Date(t).setMonth(0,4),4,1);return Math.round((t-i)/6048e5)+1}(h(e,7*i))}))}Array.from(this.grid.children).forEach(((e,t)=>{const s=e.classList,n=h(this.start,t),a=new Date(n),r=a.getDay();if(e.className=`datepicker-cell ${this.cellClass}`,e.dataset.date=n,e.textContent=a.getDate(),nthis.last&&s.add("next"),this.today===n&&s.add("today"),(nthis.maxDate||this.disabled.includes(n))&&s.add("disabled"),this.daysOfWeekDisabled.includes(r)&&(s.add("disabled"),i(this.disabled,n)),this.daysOfWeekHighlighted.includes(r)&&s.add("highlighted"),this.range){const[e,t]=this.range;n>e&&n{e.classList.remove("range","range-start","range-end","selected","focused")})),Array.from(this.grid.children).forEach((i=>{const s=Number(i.dataset.date),n=i.classList;s>e&&s{e.classList.remove("focused")})),this.grid.children[e].classList.add("focused")}}function se(e,t){if(!e||!e[0]||!e[1])return;const[[i,s],[n,a]]=e;return i>t||ne})))),super.init(e)}setOptions(t){if(t.locale&&(this.monthNames=t.locale.monthsShort),e(t,"minDate"))if(void 0===t.minDate)this.minYear=this.minMonth=this.minDate=void 0;else{const e=new Date(t.minDate);this.minYear=e.getFullYear(),this.minMonth=e.getMonth(),this.minDate=e.setDate(1)}if(e(t,"maxDate"))if(void 0===t.maxDate)this.maxYear=this.maxMonth=this.maxDate=void 0;else{const e=new Date(t.maxDate);this.maxYear=e.getFullYear(),this.maxMonth=e.getMonth(),this.maxDate=l(this.maxYear,this.maxMonth+1,0)}this.isMinView?t.datesDisabled&&(this.datesDisabled=t.datesDisabled):this.datesDisabled=[],void 0!==t.beforeShowMonth&&(this.beforeShow="function"==typeof t.beforeShowMonth?t.beforeShowMonth:void 0)}updateFocus(){const e=new Date(this.picker.viewDate);this.year=e.getFullYear(),this.focused=e.getMonth()}updateSelection(){const{dates:e,rangepicker:t}=this.picker.datepicker;this.selected=e.reduce(((e,t)=>{const s=new Date(t),n=s.getFullYear(),a=s.getMonth();return void 0===e[n]?e[n]=[a]:i(e[n],a),e}),{}),t&&t.dates&&(this.range=t.dates.map((e=>{const t=new Date(e);return isNaN(t)?void 0:[t.getFullYear(),t.getMonth()]})))}render(){this.disabled=this.datesDisabled.reduce(((e,t)=>{const i=new Date(t);return this.year===i.getFullYear()&&e.push(i.getMonth()),e}),[]),this.picker.setViewSwitchLabel(this.year),this.picker.setPrevBtnDisabled(this.year<=this.minYear),this.picker.setNextBtnDisabled(this.year>=this.maxYear);const e=this.selected[this.year]||[],t=this.yearthis.maxYear,i=this.year===this.minYear,s=this.year===this.maxYear,n=se(this.range,this.year);Array.from(this.grid.children).forEach(((a,r)=>{const d=a.classList,o=l(this.year,r,1);if(a.className=`datepicker-cell ${this.cellClass}`,this.isMinView&&(a.dataset.date=o),a.textContent=this.monthNames[r],(t||i&&rthis.maxMonth||this.disabled.includes(r))&&d.add("disabled"),n){const[e,t]=n;r>e&&r{e.classList.remove("range","range-start","range-end","selected","focused")})),Array.from(this.grid.children).forEach(((s,n)=>{const a=s.classList;n>t&&n{e.classList.remove("focused")})),this.grid.children[this.focused].classList.add("focused")}}class ae extends te{constructor(e,t){super(e,t)}init(e,t=!0){var i;t&&(this.navStep=10*this.step,this.beforeShowOption=`beforeShow${i=this.cellClass,[...i].reduce(((e,t,i)=>e+(i?t:t.toUpperCase())),"")}`,this.grid=this.element,this.element.classList.add(this.name,"datepicker-grid"),this.grid.appendChild(F(r("span",12)))),super.init(e)}setOptions(t){if(e(t,"minDate")&&(void 0===t.minDate?this.minYear=this.minDate=void 0:(this.minYear=m(t.minDate,this.step),this.minDate=l(this.minYear,0,1))),e(t,"maxDate")&&(void 0===t.maxDate?this.maxYear=this.maxDate=void 0:(this.maxYear=m(t.maxDate,this.step),this.maxDate=l(this.maxYear,11,31))),this.isMinView?t.datesDisabled&&(this.datesDisabled=t.datesDisabled):this.datesDisabled=[],void 0!==t[this.beforeShowOption]){const e=t[this.beforeShowOption];this.beforeShow="function"==typeof e?e:void 0}}updateFocus(){const e=new Date(this.picker.viewDate),t=m(e,this.navStep),i=t+9*this.step;this.first=t,this.last=i,this.start=t-this.step,this.focused=m(e,this.step)}updateSelection(){const{dates:e,rangepicker:t}=this.picker.datepicker;this.selected=e.reduce(((e,t)=>i(e,m(t,this.step))),[]),t&&t.dates&&(this.range=t.dates.map((e=>{if(void 0!==e)return m(e,this.step)})))}render(){this.disabled=this.datesDisabled.map((e=>new Date(e).getFullYear())),this.picker.setViewSwitchLabel(`${this.first}-${this.last}`),this.picker.setPrevBtnDisabled(this.first<=this.minYear),this.picker.setNextBtnDisabled(this.last>=this.maxYear),Array.from(this.grid.children).forEach(((e,t)=>{const i=e.classList,s=this.start+t*this.step,n=l(s,0,1);if(e.className=`datepicker-cell ${this.cellClass}`,this.isMinView&&(e.dataset.date=n),e.textContent=e.dataset.year=s,0===t?i.add("prev"):11===t&&i.add("next"),(sthis.maxYear||this.disabled.includes(s))&&i.add("disabled"),this.range){const[e,t]=this.range;s>e&&s{e.classList.remove("range","range-start","range-end","selected","focused")})),Array.from(this.grid.children).forEach((i=>{const s=Number(i.textContent),n=i.classList;s>e&&s{e.classList.remove("focused")})),this.grid.children[e].classList.add("focused")}}function re(e,t){const i={date:e.getDate(),viewDate:new Date(e.picker.viewDate),viewId:e.picker.currentView.id,datepicker:e};e.element.dispatchEvent(new CustomEvent(t,{detail:i}))}function de(e,t){const{minDate:i,maxDate:s}=e.config,{currentView:n,viewDate:r}=e.picker;let d;switch(n.id){case 0:d=u(r,t);break;case 1:d=f(r,t);break;default:d=f(r,t*n.navStep)}d=a(d,i,s),e.picker.changeFocus(d).render()}function oe(e){const t=e.picker.currentView.id;t!==e.config.maxView&&e.picker.changeView(t+1).render()}function ce(e){e.config.updateOnBlur?e.update({revert:!0}):e.refresh("input"),e.hide()}function le(e,t){const i=e.picker,s=new Date(i.viewDate),n=i.currentView.id,a=1===n?u(s,t-s.getMonth()):f(s,t-s.getFullYear());i.changeFocus(a).changeView(n-1).render()}function he(e){const t=e.picker,i=c();if(1===e.config.todayBtnMode){if(e.config.autohide)return void e.setDate(i);e.setDate(i,{render:!1}),t.update()}t.viewDate!==i&&t.changeFocus(i),t.changeView(0).render()}function ue(e){e.setDate({clear:!0})}function fe(e){oe(e)}function pe(e){de(e,-1)}function ge(e){de(e,1)}function me(e,t){const i=K(t,".datepicker-cell");if(!i||i.classList.contains("disabled"))return;const{id:s,isMinView:n}=e.picker.currentView;n?e.setDate(Number(i.dataset.date)):le(e,Number(1===s?i.dataset.month:i.dataset.year))}function we(e){e.preventDefault()}const De=["left","top","right","bottom"].reduce(((e,t)=>(e[t]=`datepicker-orient-${t}`,e)),{}),ye=e=>e?`${e}px`:e;function ve(t,i){if(void 0!==i.title&&(i.title?(t.controls.title.textContent=i.title,B(t.controls.title)):(t.controls.title.textContent="",L(t.controls.title))),i.prevArrow){const e=t.controls.prevBtn;A(e),i.prevArrow.forEach((t=>{e.appendChild(t.cloneNode(!0))}))}if(i.nextArrow){const e=t.controls.nextBtn;A(e),i.nextArrow.forEach((t=>{e.appendChild(t.cloneNode(!0))}))}if(i.locale&&(t.controls.todayBtn.textContent=i.locale.today,t.controls.clearBtn.textContent=i.locale.clear),void 0!==i.todayBtn&&(i.todayBtn?B(t.controls.todayBtn):L(t.controls.todayBtn)),e(i,"minDate")||e(i,"maxDate")){const{minDate:e,maxDate:i}=t.datepicker.config;t.controls.todayBtn.disabled=!n(c(),e,i)}void 0!==i.clearBtn&&(i.clearBtn?B(t.controls.clearBtn):L(t.controls.clearBtn))}function be(e){const{dates:i,config:s}=e;return a(i.length>0?t(i):s.defaultViewDate,s.minDate,s.maxDate)}function ke(e,t){const i=new Date(e.viewDate),s=new Date(t),{id:n,year:a,first:r,last:d}=e.currentView,o=s.getFullYear();switch(e.viewDate=t,o!==i.getFullYear()&&re(e.datepicker,"changeYear"),s.getMonth()!==i.getMonth()&&re(e.datepicker,"changeMonth"),n){case 0:return td;case 1:return o!==a;default:return od}}function xe(e){return window.getComputedStyle(e).direction}function Me(e){const t=V(e);if(t!==document.body&&t)return"visible"!==window.getComputedStyle(t).overflow?t:Me(t)}class Se{constructor(e){const{config:t}=this.datepicker=e,i=Q.replace(/%buttonClass%/g,t.buttonClass),s=this.element=F(i).firstChild,[n,a,r]=s.firstChild.children,d=n.firstElementChild,[o,c,l]=n.lastElementChild.children,[h,u]=r.firstChild.children,f={title:d,prevBtn:o,viewSwitch:c,nextBtn:l,todayBtn:h,clearBtn:u};this.main=a,this.controls=f;const p=e.inline?"inline":"dropdown";s.classList.add(`datepicker-${p}`),ve(this,t),this.viewDate=be(e),j(e,[[s,"mousedown",we],[a,"click",me.bind(null,e)],[f.viewSwitch,"click",fe.bind(null,e)],[f.prevBtn,"click",pe.bind(null,e)],[f.nextBtn,"click",ge.bind(null,e)],[f.todayBtn,"click",he.bind(null,e)],[f.clearBtn,"click",ue.bind(null,e)]]),this.views=[new ie(this),new ne(this),new ae(this,{id:2,name:"years",cellClass:"year",step:1}),new ae(this,{id:3,name:"decades",cellClass:"decade",step:10})],this.currentView=this.views[t.startView],this.currentView.render(),this.main.appendChild(this.currentView.element),t.container?t.container.appendChild(this.element):e.inputField.after(this.element)}setOptions(e){ve(this,e),this.views.forEach((t=>{t.init(e,!1)})),this.currentView.render()}detach(){this.element.remove()}show(){if(this.active)return;const{datepicker:e,element:t}=this;if(e.inline)t.classList.add("active");else{const i=xe(e.inputField);i!==xe(V(t))?t.dir=i:t.dir&&t.removeAttribute("dir"),t.style.visiblity="hidden",t.classList.add("active"),this.place(),t.style.visiblity="",e.config.disableTouchKeyboard&&e.inputField.blur()}this.active=!0,re(e,"show")}hide(){this.active&&(this.datepicker.exitEditMode(),this.element.classList.remove("active"),this.active=!1,re(this.datepicker,"hide"))}place(){const{classList:e,offsetParent:t,style:i}=this.element,{config:s,inputField:n}=this.datepicker,{width:a,height:r}=this.element.getBoundingClientRect(),{left:d,top:o,right:c,bottom:l,width:h,height:u}=n.getBoundingClientRect();let{x:f,y:p}=s.orientation,g=d,m=o;if(t!==document.body&&t){const e=t.getBoundingClientRect();g-=e.left-t.scrollLeft,m-=e.top-t.scrollTop}else g+=window.scrollX,m+=window.scrollY;const w=Me(n);let D=0,y=0,{clientWidth:v,clientHeight:b}=document.documentElement;if(w){const e=w.getBoundingClientRect();e.top>0&&(y=e.top),e.left>0&&(D=e.left),e.rightv?(f="right",vy&&l+r>b?"top":"bottom"),"top"===p?m-=r:m+=u,e.remove(...Object.values(De)),e.add(De[f],De[p]),i.left=ye(g),i.top=ye(m)}setViewSwitchLabel(e){this.controls.viewSwitch.textContent=e}setPrevBtnDisabled(e){this.controls.prevBtn.disabled=e}setNextBtnDisabled(e){this.controls.nextBtn.disabled=e}changeView(e){const t=this.currentView,i=this.views[e];return i.id!==t.id&&(this.currentView=i,this._renderMethod="render",re(this.datepicker,"changeView"),this.main.replaceChild(i.element,t.element)),this}changeFocus(e){return this._renderMethod=ke(this,e)?"render":"refreshFocus",this.views.forEach((e=>{e.updateFocus()})),this}update(){const e=be(this.datepicker);return this._renderMethod=ke(this,e)?"render":"refresh",this.views.forEach((e=>{e.updateFocus(),e.updateSelection()})),this}render(e=!0){const t=e&&this._renderMethod||"render";delete this._renderMethod,this.currentView[t]()}}function Oe(e,t,i,s,a,r){if(n(e,a,r)){if(s(e)){return Oe(t(e,i),t,i,s,a,r)}return e}}function Ce(e,t,i,s){const n=e.picker,a=n.currentView,r=a.step||1;let d,o,c=n.viewDate;switch(a.id){case 0:c=s?h(c,7*i):t.ctrlKey||t.metaKey?f(c,i):h(c,i),d=h,o=e=>a.disabled.includes(e);break;case 1:c=u(c,s?4*i:i),d=u,o=e=>{const t=new Date(e),{year:i,disabled:s}=a;return t.getFullYear()===i&&s.includes(t.getMonth())};break;default:c=f(c,i*(s?4:1)*r),d=f,o=e=>a.disabled.includes(m(e,r))}c=Oe(c,d,i<0?-r:r,o,a.minDate,a.maxDate),void 0!==c&&n.changeFocus(c).render()}function Ee(e,t){const i=t.key;if("Tab"===i)return void ce(e);const s=e.picker,{id:n,isMinView:a}=s.currentView;if(s.active){if(e.editMode)return void("Enter"===i?e.exitEditMode({update:!0,autohide:e.config.autohide}):"Escape"===i&&s.hide());if("ArrowLeft"===i)if(t.ctrlKey||t.metaKey)de(e,-1);else{if(t.shiftKey)return void e.enterEditMode();Ce(e,t,-1,!1)}else if("ArrowRight"===i)if(t.ctrlKey||t.metaKey)de(e,1);else{if(t.shiftKey)return void e.enterEditMode();Ce(e,t,1,!1)}else if("ArrowUp"===i)if(t.ctrlKey||t.metaKey)oe(e);else{if(t.shiftKey)return void e.enterEditMode();Ce(e,t,-1,!0)}else if("ArrowDown"===i){if(t.shiftKey&&!t.ctrlKey&&!t.metaKey)return void e.enterEditMode();Ce(e,t,1,!0)}else{if("Enter"!==i)return void("Escape"===i?s.hide():"Backspace"!==i&&"Delete"!==i&&(1!==i.length||t.ctrlKey||t.metaKey)||e.enterEditMode());if(a)return void e.setDate(s.viewDate);s.changeView(n-1).render()}}else{if("ArrowDown"!==i)return void("Enter"===i?e.update():"Escape"===i&&s.show());s.show()}t.preventDefault()}function Fe(e){e.config.showOnFocus&&!e._showing&&e.show()}function Ve(e,t){const i=t.target;(e.picker.active||e.config.showOnClick)&&(i._active=N(i),i._clicking=setTimeout((()=>{delete i._active,delete i._clicking}),2e3))}function Ne(e,t){const i=t.target;i._clicking&&(clearTimeout(i._clicking),delete i._clicking,i._active&&e.enterEditMode(),delete i._active,e.config.showOnClick&&e.show())}function Le(e,t){t.clipboardData.types.includes("text/plain")&&e.enterEditMode()}function Be(e,t){const{element:i,picker:s}=e;if(!s.active&&!N(i))return;const n=s.element;K(t,(e=>e===i||e===n))||ce(e)}function Ae(e,t){return e.map((e=>C(e,t.format,t.locale))).join(t.dateDelimiter)}function Ye(e,t,i=!1){const{config:s,dates:a,rangeSideIndex:r}=e;if(0===t.length)return i?[]:void 0;let d=t.reduce(((e,t)=>{let i=O(t,s.format,s.locale);return void 0===i||(i=w(i,s.pickLevel,r),!n(i,s.minDate,s.maxDate)||e.includes(i)||s.datesDisabled.includes(i)||!(s.pickLevel>0)&&s.daysOfWeekDisabled.includes(new Date(i).getDay())||e.push(i)),e}),[]);return 0!==d.length?(s.multidate&&!i&&(d=d.reduce(((e,t)=>(a.includes(t)||e.push(t),e)),a.filter((e=>!d.includes(e))))),s.maxNumberOfDates&&d.length>s.maxNumberOfDates?d.slice(-1*s.maxNumberOfDates):d):void 0}function We(e,t=3,i=!0){const{config:s,picker:n,inputField:a}=e;if(2&t){const e=n.active?s.pickLevel:s.startView;n.update().changeView(e).render(i)}1&t&&a&&(a.value=Ae(e.dates,s))}function He(e,t,i){let{clear:s,render:n,autohide:a,revert:r}=i;void 0===n&&(n=!0),n?void 0===a&&(a=e.config.autohide):a=!1;const d=Ye(e,t,s);(d||r)&&(d&&d.toString()!==e.dates.toString()?(e.dates=d,We(e,n?3:1),re(e,"changeDate")):We(e,1),a&&e.hide())}class je{constructor(e,t={},i){e.datepicker=this,this.element=e;const n=this.config=Object.assign({buttonClass:t.buttonClass&&String(t.buttonClass)||"button",container:null,defaultViewDate:c(),maxDate:void 0,minDate:void 0},G(R,this)),a=this.inline="INPUT"!==e.tagName;let r,d;if(a?n.container=e:(t.container&&(n.container=t.container instanceof HTMLElement?t.container:document.querySelector(t.container)),r=this.inputField=e,r.classList.add("datepicker-input")),i){const e=i.inputs.indexOf(r),t=i.datepickers;if(e<0||e>1||!Array.isArray(t))throw Error("Invalid rangepicker object.");t[e]=this,Object.defineProperty(this,"rangepicker",{get:()=>i}),Object.defineProperty(this,"rangeSideIndex",{get:()=>e})}this._options=t,Object.assign(n,G(t,this)),a?(d=s(e.dataset.date,n.dateDelimiter),delete e.dataset.date):d=s(r.value,n.dateDelimiter),this.dates=[];const o=Ye(this,d);o&&o.length>0&&(this.dates=o),r&&(r.value=Ae(this.dates,n));const l=this.picker=new Se(this);if(a)this.show();else{const e=Be.bind(null,this);j(this,[[r,"keydown",Ee.bind(null,this)],[r,"focus",Fe.bind(null,this)],[r,"mousedown",Ve.bind(null,this)],[r,"click",Ne.bind(null,this)],[r,"paste",Le.bind(null,this)],[document,"mousedown",e],[document,"touchstart",e],[window,"resize",l.place.bind(l)]])}}static formatDate(e,t,i){return C(e,t,i&&$[i]||$.en)}static parseDate(e,t,i){return O(e,t,i&&$[i]||$.en)}static get locales(){return $}get active(){return!(!this.picker||!this.picker.active)}get pickerElement(){return this.picker?this.picker.element:void 0}setOptions(e){const t=this.picker,i=G(e,this);Object.assign(this._options,e),Object.assign(this.config,i),t.setOptions(i),We(this,3)}show(){if(this.inputField){if(this.inputField.disabled)return;N(this.inputField)||this.config.disableTouchKeyboard||(this._showing=!0,this.inputField.focus(),delete this._showing)}this.picker.show()}hide(){this.inline||(this.picker.hide(),this.picker.update().changeView(this.config.startView).render())}destroy(){return this.hide(),T(this),this.picker.detach(),this.inline||this.inputField.classList.remove("datepicker-input"),delete this.element.datepicker,this}getDate(e){const t=e?t=>C(t,e,this.config.locale):e=>new Date(e);return this.config.multidate?this.dates.map(t):this.dates.length>0?t(this.dates[0]):void 0}setDate(...e){const i=[...e],s={},n=t(e);"object"!=typeof n||Array.isArray(n)||n instanceof Date||!n||Object.assign(s,i.pop());He(this,Array.isArray(i[0])?i[0]:i,s)}update(e){if(this.inline)return;const t=Object.assign(e||{},{clear:!0,render:!0});He(this,s(this.inputField.value,this.config.dateDelimiter),t)}refresh(e,t=!1){let i;e&&"string"!=typeof e&&(t=e,e=void 0),i="picker"===e?2:"input"===e?1:3,We(this,i,!t)}enterEditMode(){this.inline||!this.picker.active||this.editMode||(this.editMode=!0,this.inputField.classList.add("in-edit"))}exitEditMode(e){if(this.inline||!this.editMode)return;const t=Object.assign({update:!1},e);delete this.editMode,this.inputField.classList.remove("in-edit"),t.update&&this.update(t)}}function Te(e){const t=Object.assign({},e);return delete t.inputs,delete t.allowOneSidedRange,delete t.maxNumberOfDates,t}function _e(e,t,i,s){j(e,[[i,"changeDate",t]]),new je(i,s,e)}function Ke(e,t){if(e._updating)return;e._updating=!0;const i=t.target;if(void 0===i.datepicker)return;const s=e.datepickers,n={render:!1},a=e.inputs.indexOf(i),r=0===a?1:0,d=s[a].dates[0],o=s[r].dates[0];void 0!==d&&void 0!==o?0===a&&d>o?(s[0].setDate(o,n),s[1].setDate(d,n)):1===a&&da}),_e(this,s,this.inputs[0],n),_e(this,s,this.inputs[1],n),Object.freeze(a),a[0].dates.length>0?Ke(this,{target:this.inputs[0]}):a[1].dates.length>0&&Ke(this,{target:this.inputs[1]})}get dates(){return 2===this.datepickers.length?[this.datepickers[0].dates[0],this.datepickers[1].dates[0]]:void 0}setOptions(e){this.allowOneSidedRange=!!e.allowOneSidedRange;const t=Te(e);this.datepickers[0].setOptions(t),this.datepickers[1].setOptions(t)}destroy(){this.datepickers[0].destroy(),this.datepickers[1].destroy(),T(this),delete this.element.rangepicker}getDates(e){const t=e?t=>C(t,e,this.datepickers[0].config.locale):e=>new Date(e);return this.dates.map((e=>void 0===e?e:t(e)))}setDates(e,t){const[i,s]=this.datepickers,n=this.dates;this._updating=!0,i.setDate(e),s.setDate(t),delete this._updating,s.dates[0]!==n[1]?Ke(this,{target:this.inputs[1]}):i.dates[0]!==n[0]&&Ke(this,{target:this.inputs[0]})}}}(); \ No newline at end of file diff --git a/src/ui/static/js/datepicker/datepicker.min.js b/src/ui/static/js/datepicker/datepicker.min.js new file mode 100644 index 000000000..7590ab30b --- /dev/null +++ b/src/ui/static/js/datepicker/datepicker.min.js @@ -0,0 +1 @@ +var Datepicker=function(){"use strict";function e(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function t(e){return e[e.length-1]}function i(e,...t){return t.forEach((t=>{e.includes(t)||e.push(t)})),e}function s(e,t){return e?e.split(t):[]}function n(e,t,i){return(void 0===t||e>=t)&&(void 0===i||e<=i)}function a(e,t,i){return ei?i:e}function r(e,t,i={},s=0,n=""){n+=`<${Object.keys(i).reduce(((e,t)=>{let n=i[t];return"function"==typeof n&&(n=n(s)),`${e} ${t}="${n}"`}),e)}>`;const a=s+1;return a\s+/g,">").replace(/\s+new Date(e).setFullYear(parseInt(t,10)),m(e,t,i){const s=new Date(e);let n=parseInt(t,10)-1;if(isNaN(n)){if(!t)return NaN;const e=t.toLowerCase(),s=t=>t.toLowerCase().startsWith(e);if(n=i.monthsShort.findIndex(s),n<0&&(n=i.months.findIndex(s)),n<0)return NaN}return s.setMonth(n),s.getMonth()!==x(n)?s.setDate(0):s.getTime()},d:(e,t)=>new Date(e).setDate(parseInt(t,10))},k={d:e=>e.getDate(),dd:e=>M(e.getDate(),2),D:(e,t)=>t.daysShort[e.getDay()],DD:(e,t)=>t.days[e.getDay()],m:e=>e.getMonth()+1,mm:e=>M(e.getMonth()+1,2),M:(e,t)=>t.monthsShort[e.getMonth()],MM:(e,t)=>t.months[e.getMonth()],y:e=>e.getFullYear(),yy:e=>M(e.getFullYear(),2).slice(-2),yyyy:e=>M(e.getFullYear(),4)};function x(e){return e>-1?e%12:x(e+12)}function M(e,t){return e.toString().padStart(t,"0")}function S(e){if("string"!=typeof e)throw new Error("Invalid date format.");if(e in v)return v[e];const i=e.split(y),s=e.match(new RegExp(y,"g"));if(0===i.length||!s)throw new Error("Invalid date format.");const n=s.map((e=>k[e])),a=Object.keys(b).reduce(((e,t)=>(s.find((e=>"D"!==e[0]&&e[0].toLowerCase()===t))&&e.push(t),e)),[]);return v[e]={parser(e,t){const i=e.split(D).reduce(((e,t,i)=>{if(t.length>0&&s[i]){const n=s[i][0];"M"===n?e.m=t:"D"!==n&&(e[n]=t)}return e}),{});return a.reduce(((e,s)=>{const n=b[s](e,i[s],t);return isNaN(n)?e:n}),c())},formatter:(e,s)=>n.reduce(((t,n,a)=>t+`${i[a]}${n(e,s)}`),"")+t(i)}}function C(e,t,i){if(e instanceof Date||"number"==typeof e){const t=o(e);return isNaN(t)?void 0:t}if(e){if("today"===e)return c();if(t&&t.toValue){const s=t.toValue(e,t,i);return isNaN(s)?void 0:o(s)}return S(t).parser(e,i)}}function O(e,t,i){if(isNaN(e)||!e&&0!==e)return"";const s="number"==typeof e?new Date(e):e;return t.toDisplay?t.toDisplay(s,t,i):S(t).formatter(s,i)}const E=document.createRange();function F(e){return E.createContextualFragment(e)}function V(e){return e.parentElement||(e.parentNode instanceof ShadowRoot?e.parentNode.host:void 0)}function N(e){return e.getRootNode().activeElement===e}function L(e){"none"!==e.style.display&&(e.style.display&&(e.dataset.styleDisplay=e.style.display),e.style.display="none")}function B(e){"none"===e.style.display&&(e.dataset.styleDisplay?(e.style.display=e.dataset.styleDisplay,delete e.dataset.styleDisplay):e.style.display="")}function Y(e){e.firstChild&&(e.removeChild(e.firstChild),Y(e))}const A=new WeakMap,{addEventListener:W,removeEventListener:H}=EventTarget.prototype;function T(e,t){let i=A.get(e);i||(i=[],A.set(e,i)),t.forEach((e=>{W.call(...e),i.push(e)}))}if(!Event.prototype.composedPath){const e=(t,i=[])=>{let s;return i.push(t),t.parentNode?s=t.parentNode:t.host?s=t.host:t.defaultView&&(s=t.defaultView),s?e(s,i):i};Event.prototype.composedPath=function(){return e(this.target)}}function K(e,t,i){const[s,...n]=e;return t(s)?s:s!==i&&"HTML"!==s.tagName&&0!==n.length?K(n,t,i):void 0}function j(e,t){const i="function"==typeof t?t:e=>e instanceof Element&&e.matches(t);return K(e.composedPath(),i,e.currentTarget)}const $={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear",titleFormat:"MM y"}},_={autohide:!1,beforeShowDay:null,beforeShowDecade:null,beforeShowMonth:null,beforeShowYear:null,calendarWeeks:!1,clearBtn:!1,dateDelimiter:",",datesDisabled:[],daysOfWeekDisabled:[],daysOfWeekHighlighted:[],defaultViewDate:void 0,disableTouchKeyboard:!1,format:"mm/dd/yyyy",language:"en",maxDate:null,maxNumberOfDates:1,maxView:3,minDate:null,nextArrow:"»",orientation:"auto",pickLevel:0,prevArrow:"«",showDaysOfWeek:!0,showOnClick:!0,showOnFocus:!0,startView:0,title:"",todayBtn:!1,todayBtnMode:0,todayHighlight:!1,updateOnBlur:!0,weekStart:0},{language:I,format:P,weekStart:R}=_;function q(e,t){return e.length<6&&t>=0&&t<7?i(e,t):e}function J(e){return(e+6)%7}function U(e,t,i,s){const n=C(e,t,i);return void 0!==n?n:s}function z(e,t,i=3){const s=parseInt(e,10);return s>=0&&s<=i?s:t}function X(t,s){const n=Object.assign({},t),a={},r=s.constructor.locales,d=s.rangeSideIndex;let{format:o,language:c,locale:h,maxDate:u,maxView:f,minDate:p,pickLevel:g,startView:m,weekStart:D}=s.config||{};if(n.language){let e;if(n.language!==c&&(r[n.language]?e=n.language:(e=n.language.split("-")[0],void 0===r[e]&&(e=!1))),delete n.language,e){c=a.language=e;const t=h||r[I];h=Object.assign({format:P,weekStart:R},r[I]),c!==I&&Object.assign(h,r[c]),a.locale=h,o===t.format&&(o=a.format=h.format),D===t.weekStart&&(D=a.weekStart=h.weekStart,a.weekEnd=J(h.weekStart))}}if(n.format){const e="function"==typeof n.format.toDisplay,t="function"==typeof n.format.toValue,i=y.test(n.format);(e&&t||i)&&(o=a.format=n.format),delete n.format}let v=g;void 0!==n.pickLevel&&(v=z(n.pickLevel,2),delete n.pickLevel),v!==g&&(v>g&&(void 0===n.minDate&&(n.minDate=p),void 0===n.maxDate&&(n.maxDate=u)),n.datesDisabled||(n.datesDisabled=[]),g=a.pickLevel=v);let b=p,k=u;if(void 0!==n.minDate){const e=l(0,0,1);b=null===n.minDate?e:U(n.minDate,o,h,b),b!==e&&(b=w(b,g,!1)),delete n.minDate}if(void 0!==n.maxDate&&(k=null===n.maxDate?void 0:U(n.maxDate,o,h,k),void 0!==k&&(k=w(k,g,!0)),delete n.maxDate),k{const s=C(t,o,h);return void 0!==s?i(e,w(s,g,d)):e}),[]),delete n.datesDisabled),void 0!==n.defaultViewDate){const e=C(n.defaultViewDate,o,h);void 0!==e&&(a.defaultViewDate=e),delete n.defaultViewDate}if(void 0!==n.weekStart){const e=Number(n.weekStart)%7;isNaN(e)||(D=a.weekStart=e,a.weekEnd=J(e)),delete n.weekStart}if(n.daysOfWeekDisabled&&(a.daysOfWeekDisabled=n.daysOfWeekDisabled.reduce(q,[]),delete n.daysOfWeekDisabled),n.daysOfWeekHighlighted&&(a.daysOfWeekHighlighted=n.daysOfWeekHighlighted.reduce(q,[]),delete n.daysOfWeekHighlighted),void 0!==n.maxNumberOfDates){const e=parseInt(n.maxNumberOfDates,10);e>=0&&(a.maxNumberOfDates=e,a.multidate=1!==e),delete n.maxNumberOfDates}n.dateDelimiter&&(a.dateDelimiter=String(n.dateDelimiter),delete n.dateDelimiter);let x=f;void 0!==n.maxView&&(x=z(n.maxView,f),delete n.maxView),x=g>x?g:x,x!==f&&(f=a.maxView=x);let M=m;if(void 0!==n.startView&&(M=z(n.startView,M),delete n.startView),Mf&&(M=f),M!==m&&(a.startView=M),n.prevArrow){const e=F(n.prevArrow);e.childNodes.length>0&&(a.prevArrow=e.childNodes),delete n.prevArrow}if(n.nextArrow){const e=F(n.nextArrow);e.childNodes.length>0&&(a.nextArrow=e.childNodes),delete n.nextArrow}if(void 0!==n.disableTouchKeyboard&&(a.disableTouchKeyboard="ontouchstart"in document&&!!n.disableTouchKeyboard,delete n.disableTouchKeyboard),n.orientation){const e=n.orientation.toLowerCase().split(/\s+/g);a.orientation={x:e.find((e=>"left"===e||"right"===e))||"auto",y:e.find((e=>"top"===e||"bottom"===e))||"auto"},delete n.orientation}if(void 0!==n.todayBtnMode){switch(n.todayBtnMode){case 0:case 1:a.todayBtnMode=n.todayBtnMode}delete n.todayBtnMode}return Object.keys(n).forEach((t=>{void 0!==n[t]&&e(_,t)&&(a[t]=n[t])})),a}const G=d('
\n
\n
\n
\n
\n \n \n \n
\n
\n
\n \n
\n
'),Q=d(`
\n
${r("span",7,{class:"dow"})}
\n
${r("span",42)}
\n
`),Z=d(`
\n
\n
${r("span",6,{class:"week"})}
\n
`);class ee{constructor(e,t){Object.assign(this,t,{picker:e,element:F('
').firstChild,selected:[]}),this.init(this.picker.datepicker.config)}init(e){void 0!==e.pickLevel&&(this.isMinView=this.id===e.pickLevel),this.setOptions(e),this.updateFocus(),this.updateSelection()}performBeforeHook(e,t,s){let n=this.beforeShow(new Date(s));switch(typeof n){case"boolean":n={enabled:n};break;case"string":n={classes:n}}if(n){if(!1===n.enabled&&(e.classList.add("disabled"),i(this.disabled,t)),n.classes){const s=n.classes.split(/\s+/);e.classList.add(...s),s.includes("disabled")&&i(this.disabled,t)}n.content&&function(e,t){Y(e),t instanceof DocumentFragment?e.appendChild(t):"string"==typeof t?e.appendChild(F(t)):"function"==typeof t.forEach&&t.forEach((t=>{e.appendChild(t)}))}(e,n.content)}}}class te extends ee{constructor(e){super(e,{id:0,name:"days",cellClass:"day"})}init(e,t=!0){if(t){const e=F(Q).firstChild;this.dow=e.firstChild,this.grid=e.lastChild,this.element.appendChild(e)}super.init(e)}setOptions(t){let i;if(e(t,"minDate")&&(this.minDate=t.minDate),e(t,"maxDate")&&(this.maxDate=t.maxDate),t.datesDisabled&&(this.datesDisabled=t.datesDisabled),t.daysOfWeekDisabled&&(this.daysOfWeekDisabled=t.daysOfWeekDisabled,i=!0),t.daysOfWeekHighlighted&&(this.daysOfWeekHighlighted=t.daysOfWeekHighlighted),void 0!==t.todayHighlight&&(this.todayHighlight=t.todayHighlight),void 0!==t.weekStart&&(this.weekStart=t.weekStart,this.weekEnd=t.weekEnd,i=!0),t.locale){const e=this.locale=t.locale;this.dayNames=e.daysMin,this.switchLabelFormat=e.titleFormat,i=!0}if(void 0!==t.beforeShowDay&&(this.beforeShow="function"==typeof t.beforeShowDay?t.beforeShowDay:void 0),void 0!==t.calendarWeeks)if(t.calendarWeeks&&!this.calendarWeeks){const e=F(Z).firstChild;this.calendarWeeks={element:e,dow:e.firstChild,weeks:e.lastChild},this.element.insertBefore(e,this.element.firstChild)}else this.calendarWeeks&&!t.calendarWeeks&&(this.element.removeChild(this.calendarWeeks.element),this.calendarWeeks=null);void 0!==t.showDaysOfWeek&&(t.showDaysOfWeek?(B(this.dow),this.calendarWeeks&&B(this.calendarWeeks.dow)):(L(this.dow),this.calendarWeeks&&L(this.calendarWeeks.dow))),i&&Array.from(this.dow.children).forEach(((e,t)=>{const i=(this.weekStart+t)%7;e.textContent=this.dayNames[i],e.className=this.daysOfWeekDisabled.includes(i)?"dow disabled":"dow"}))}updateFocus(){const e=new Date(this.picker.viewDate),t=e.getFullYear(),i=e.getMonth(),s=l(t,i,1),n=g(s,this.weekStart,this.weekStart);this.first=s,this.last=l(t,i+1,0),this.start=n,this.focused=this.picker.viewDate}updateSelection(){const{dates:e,rangepicker:t}=this.picker.datepicker;this.selected=e,t&&(this.range=t.dates)}render(){this.today=this.todayHighlight?c():void 0,this.disabled=[...this.datesDisabled];const e=O(this.focused,this.switchLabelFormat,this.locale);if(this.picker.setViewSwitchLabel(e),this.picker.setPrevBtnDisabled(this.first<=this.minDate),this.picker.setNextBtnDisabled(this.last>=this.maxDate),this.calendarWeeks){const e=g(this.first,1,1);Array.from(this.calendarWeeks.weeks.children).forEach(((t,i)=>{t.textContent=function(e){const t=g(e,4,1),i=g(new Date(t).setMonth(0,4),4,1);return Math.round((t-i)/6048e5)+1}(h(e,7*i))}))}Array.from(this.grid.children).forEach(((e,t)=>{const s=e.classList,n=h(this.start,t),a=new Date(n),r=a.getDay();if(e.className=`datepicker-cell ${this.cellClass}`,e.dataset.date=n,e.textContent=a.getDate(),nthis.last&&s.add("next"),this.today===n&&s.add("today"),(nthis.maxDate||this.disabled.includes(n))&&s.add("disabled"),this.daysOfWeekDisabled.includes(r)&&(s.add("disabled"),i(this.disabled,n)),this.daysOfWeekHighlighted.includes(r)&&s.add("highlighted"),this.range){const[e,t]=this.range;n>e&&n{e.classList.remove("range","range-start","range-end","selected","focused")})),Array.from(this.grid.children).forEach((i=>{const s=Number(i.dataset.date),n=i.classList;s>e&&s{e.classList.remove("focused")})),this.grid.children[e].classList.add("focused")}}function ie(e,t){if(!e||!e[0]||!e[1])return;const[[i,s],[n,a]]=e;return i>t||ne})))),super.init(e)}setOptions(t){if(t.locale&&(this.monthNames=t.locale.monthsShort),e(t,"minDate"))if(void 0===t.minDate)this.minYear=this.minMonth=this.minDate=void 0;else{const e=new Date(t.minDate);this.minYear=e.getFullYear(),this.minMonth=e.getMonth(),this.minDate=e.setDate(1)}if(e(t,"maxDate"))if(void 0===t.maxDate)this.maxYear=this.maxMonth=this.maxDate=void 0;else{const e=new Date(t.maxDate);this.maxYear=e.getFullYear(),this.maxMonth=e.getMonth(),this.maxDate=l(this.maxYear,this.maxMonth+1,0)}this.isMinView?t.datesDisabled&&(this.datesDisabled=t.datesDisabled):this.datesDisabled=[],void 0!==t.beforeShowMonth&&(this.beforeShow="function"==typeof t.beforeShowMonth?t.beforeShowMonth:void 0)}updateFocus(){const e=new Date(this.picker.viewDate);this.year=e.getFullYear(),this.focused=e.getMonth()}updateSelection(){const{dates:e,rangepicker:t}=this.picker.datepicker;this.selected=e.reduce(((e,t)=>{const s=new Date(t),n=s.getFullYear(),a=s.getMonth();return void 0===e[n]?e[n]=[a]:i(e[n],a),e}),{}),t&&t.dates&&(this.range=t.dates.map((e=>{const t=new Date(e);return isNaN(t)?void 0:[t.getFullYear(),t.getMonth()]})))}render(){this.disabled=this.datesDisabled.reduce(((e,t)=>{const i=new Date(t);return this.year===i.getFullYear()&&e.push(i.getMonth()),e}),[]),this.picker.setViewSwitchLabel(this.year),this.picker.setPrevBtnDisabled(this.year<=this.minYear),this.picker.setNextBtnDisabled(this.year>=this.maxYear);const e=this.selected[this.year]||[],t=this.yearthis.maxYear,i=this.year===this.minYear,s=this.year===this.maxYear,n=ie(this.range,this.year);Array.from(this.grid.children).forEach(((a,r)=>{const d=a.classList,o=l(this.year,r,1);if(a.className=`datepicker-cell ${this.cellClass}`,this.isMinView&&(a.dataset.date=o),a.textContent=this.monthNames[r],(t||i&&rthis.maxMonth||this.disabled.includes(r))&&d.add("disabled"),n){const[e,t]=n;r>e&&r{e.classList.remove("range","range-start","range-end","selected","focused")})),Array.from(this.grid.children).forEach(((s,n)=>{const a=s.classList;n>t&&n{e.classList.remove("focused")})),this.grid.children[this.focused].classList.add("focused")}}class ne extends ee{constructor(e,t){super(e,t)}init(e,t=!0){var i;t&&(this.navStep=10*this.step,this.beforeShowOption=`beforeShow${i=this.cellClass,[...i].reduce(((e,t,i)=>e+(i?t:t.toUpperCase())),"")}`,this.grid=this.element,this.element.classList.add(this.name,"datepicker-grid"),this.grid.appendChild(F(r("span",12)))),super.init(e)}setOptions(t){if(e(t,"minDate")&&(void 0===t.minDate?this.minYear=this.minDate=void 0:(this.minYear=m(t.minDate,this.step),this.minDate=l(this.minYear,0,1))),e(t,"maxDate")&&(void 0===t.maxDate?this.maxYear=this.maxDate=void 0:(this.maxYear=m(t.maxDate,this.step),this.maxDate=l(this.maxYear,11,31))),this.isMinView?t.datesDisabled&&(this.datesDisabled=t.datesDisabled):this.datesDisabled=[],void 0!==t[this.beforeShowOption]){const e=t[this.beforeShowOption];this.beforeShow="function"==typeof e?e:void 0}}updateFocus(){const e=new Date(this.picker.viewDate),t=m(e,this.navStep),i=t+9*this.step;this.first=t,this.last=i,this.start=t-this.step,this.focused=m(e,this.step)}updateSelection(){const{dates:e,rangepicker:t}=this.picker.datepicker;this.selected=e.reduce(((e,t)=>i(e,m(t,this.step))),[]),t&&t.dates&&(this.range=t.dates.map((e=>{if(void 0!==e)return m(e,this.step)})))}render(){this.disabled=this.datesDisabled.map((e=>new Date(e).getFullYear())),this.picker.setViewSwitchLabel(`${this.first}-${this.last}`),this.picker.setPrevBtnDisabled(this.first<=this.minYear),this.picker.setNextBtnDisabled(this.last>=this.maxYear),Array.from(this.grid.children).forEach(((e,t)=>{const i=e.classList,s=this.start+t*this.step,n=l(s,0,1);if(e.className=`datepicker-cell ${this.cellClass}`,this.isMinView&&(e.dataset.date=n),e.textContent=e.dataset.year=s,0===t?i.add("prev"):11===t&&i.add("next"),(sthis.maxYear||this.disabled.includes(s))&&i.add("disabled"),this.range){const[e,t]=this.range;s>e&&s{e.classList.remove("range","range-start","range-end","selected","focused")})),Array.from(this.grid.children).forEach((i=>{const s=Number(i.textContent),n=i.classList;s>e&&s{e.classList.remove("focused")})),this.grid.children[e].classList.add("focused")}}function ae(e,t){const i={date:e.getDate(),viewDate:new Date(e.picker.viewDate),viewId:e.picker.currentView.id,datepicker:e};e.element.dispatchEvent(new CustomEvent(t,{detail:i}))}function re(e,t){const{minDate:i,maxDate:s}=e.config,{currentView:n,viewDate:r}=e.picker;let d;switch(n.id){case 0:d=u(r,t);break;case 1:d=f(r,t);break;default:d=f(r,t*n.navStep)}d=a(d,i,s),e.picker.changeFocus(d).render()}function de(e){const t=e.picker.currentView.id;t!==e.config.maxView&&e.picker.changeView(t+1).render()}function oe(e){e.config.updateOnBlur?e.update({revert:!0}):e.refresh("input"),e.hide()}function ce(e,t){const i=e.picker,s=new Date(i.viewDate),n=i.currentView.id,a=1===n?u(s,t-s.getMonth()):f(s,t-s.getFullYear());i.changeFocus(a).changeView(n-1).render()}function le(e){const t=e.picker,i=c();if(1===e.config.todayBtnMode){if(e.config.autohide)return void e.setDate(i);e.setDate(i,{render:!1}),t.update()}t.viewDate!==i&&t.changeFocus(i),t.changeView(0).render()}function he(e){e.setDate({clear:!0})}function ue(e){de(e)}function fe(e){re(e,-1)}function pe(e){re(e,1)}function ge(e,t){const i=j(t,".datepicker-cell");if(!i||i.classList.contains("disabled"))return;const{id:s,isMinView:n}=e.picker.currentView;n?e.setDate(Number(i.dataset.date)):ce(e,Number(1===s?i.dataset.month:i.dataset.year))}function me(e){e.preventDefault()}const we=["left","top","right","bottom"].reduce(((e,t)=>(e[t]=`datepicker-orient-${t}`,e)),{}),ye=e=>e?`${e}px`:e;function De(t,i){if(void 0!==i.title&&(i.title?(t.controls.title.textContent=i.title,B(t.controls.title)):(t.controls.title.textContent="",L(t.controls.title))),i.prevArrow){const e=t.controls.prevBtn;Y(e),i.prevArrow.forEach((t=>{e.appendChild(t.cloneNode(!0))}))}if(i.nextArrow){const e=t.controls.nextBtn;Y(e),i.nextArrow.forEach((t=>{e.appendChild(t.cloneNode(!0))}))}if(i.locale&&(t.controls.todayBtn.textContent=i.locale.today,t.controls.clearBtn.textContent=i.locale.clear),void 0!==i.todayBtn&&(i.todayBtn?B(t.controls.todayBtn):L(t.controls.todayBtn)),e(i,"minDate")||e(i,"maxDate")){const{minDate:e,maxDate:i}=t.datepicker.config;t.controls.todayBtn.disabled=!n(c(),e,i)}void 0!==i.clearBtn&&(i.clearBtn?B(t.controls.clearBtn):L(t.controls.clearBtn))}function ve(e){const{dates:i,config:s}=e;return a(i.length>0?t(i):s.defaultViewDate,s.minDate,s.maxDate)}function be(e,t){const i=new Date(e.viewDate),s=new Date(t),{id:n,year:a,first:r,last:d}=e.currentView,o=s.getFullYear();switch(e.viewDate=t,o!==i.getFullYear()&&ae(e.datepicker,"changeYear"),s.getMonth()!==i.getMonth()&&ae(e.datepicker,"changeMonth"),n){case 0:return td;case 1:return o!==a;default:return od}}function ke(e){return window.getComputedStyle(e).direction}function xe(e){const t=V(e);if(t!==document.body&&t)return"visible"!==window.getComputedStyle(t).overflow?t:xe(t)}class Me{constructor(e){const{config:t}=this.datepicker=e,i=G.replace(/%buttonClass%/g,t.buttonClass),s=this.element=F(i).firstChild,[n,a,r]=s.firstChild.children,d=n.firstElementChild,[o,c,l]=n.lastElementChild.children,[h,u]=r.firstChild.children,f={title:d,prevBtn:o,viewSwitch:c,nextBtn:l,todayBtn:h,clearBtn:u};this.main=a,this.controls=f;const p=e.inline?"inline":"dropdown";s.classList.add(`datepicker-${p}`),De(this,t),this.viewDate=ve(e),T(e,[[s,"mousedown",me],[a,"click",ge.bind(null,e)],[f.viewSwitch,"click",ue.bind(null,e)],[f.prevBtn,"click",fe.bind(null,e)],[f.nextBtn,"click",pe.bind(null,e)],[f.todayBtn,"click",le.bind(null,e)],[f.clearBtn,"click",he.bind(null,e)]]),this.views=[new te(this),new se(this),new ne(this,{id:2,name:"years",cellClass:"year",step:1}),new ne(this,{id:3,name:"decades",cellClass:"decade",step:10})],this.currentView=this.views[t.startView],this.currentView.render(),this.main.appendChild(this.currentView.element),t.container?t.container.appendChild(this.element):e.inputField.after(this.element)}setOptions(e){De(this,e),this.views.forEach((t=>{t.init(e,!1)})),this.currentView.render()}detach(){this.element.remove()}show(){if(this.active)return;const{datepicker:e,element:t}=this;if(e.inline)t.classList.add("active");else{const i=ke(e.inputField);i!==ke(V(t))?t.dir=i:t.dir&&t.removeAttribute("dir"),t.style.visiblity="hidden",t.classList.add("active"),this.place(),t.style.visiblity="",e.config.disableTouchKeyboard&&e.inputField.blur()}this.active=!0,ae(e,"show")}hide(){this.active&&(this.datepicker.exitEditMode(),this.element.classList.remove("active"),this.active=!1,ae(this.datepicker,"hide"))}place(){const{classList:e,offsetParent:t,style:i}=this.element,{config:s,inputField:n}=this.datepicker,{width:a,height:r}=this.element.getBoundingClientRect(),{left:d,top:o,right:c,bottom:l,width:h,height:u}=n.getBoundingClientRect();let{x:f,y:p}=s.orientation,g=d,m=o;if(t!==document.body&&t){const e=t.getBoundingClientRect();g-=e.left-t.scrollLeft,m-=e.top-t.scrollTop}else g+=window.scrollX,m+=window.scrollY;const w=xe(n);let y=0,D=0,{clientWidth:v,clientHeight:b}=document.documentElement;if(w){const e=w.getBoundingClientRect();e.top>0&&(D=e.top),e.left>0&&(y=e.left),e.rightv?(f="right",vD&&l+r>b?"top":"bottom"),"top"===p?m-=r:m+=u,e.remove(...Object.values(we)),e.add(we[f],we[p]),i.left=ye(g),i.top=ye(m)}setViewSwitchLabel(e){this.controls.viewSwitch.textContent=e}setPrevBtnDisabled(e){this.controls.prevBtn.disabled=e}setNextBtnDisabled(e){this.controls.nextBtn.disabled=e}changeView(e){const t=this.currentView,i=this.views[e];return i.id!==t.id&&(this.currentView=i,this._renderMethod="render",ae(this.datepicker,"changeView"),this.main.replaceChild(i.element,t.element)),this}changeFocus(e){return this._renderMethod=be(this,e)?"render":"refreshFocus",this.views.forEach((e=>{e.updateFocus()})),this}update(){const e=ve(this.datepicker);return this._renderMethod=be(this,e)?"render":"refresh",this.views.forEach((e=>{e.updateFocus(),e.updateSelection()})),this}render(e=!0){const t=e&&this._renderMethod||"render";delete this._renderMethod,this.currentView[t]()}}function Se(e,t,i,s,a,r){if(n(e,a,r)){if(s(e)){return Se(t(e,i),t,i,s,a,r)}return e}}function Ce(e,t,i,s){const n=e.picker,a=n.currentView,r=a.step||1;let d,o,c=n.viewDate;switch(a.id){case 0:c=s?h(c,7*i):t.ctrlKey||t.metaKey?f(c,i):h(c,i),d=h,o=e=>a.disabled.includes(e);break;case 1:c=u(c,s?4*i:i),d=u,o=e=>{const t=new Date(e),{year:i,disabled:s}=a;return t.getFullYear()===i&&s.includes(t.getMonth())};break;default:c=f(c,i*(s?4:1)*r),d=f,o=e=>a.disabled.includes(m(e,r))}c=Se(c,d,i<0?-r:r,o,a.minDate,a.maxDate),void 0!==c&&n.changeFocus(c).render()}function Oe(e,t){const i=t.key;if("Tab"===i)return void oe(e);const s=e.picker,{id:n,isMinView:a}=s.currentView;if(s.active){if(e.editMode)return void("Enter"===i?e.exitEditMode({update:!0,autohide:e.config.autohide}):"Escape"===i&&s.hide());if("ArrowLeft"===i)if(t.ctrlKey||t.metaKey)re(e,-1);else{if(t.shiftKey)return void e.enterEditMode();Ce(e,t,-1,!1)}else if("ArrowRight"===i)if(t.ctrlKey||t.metaKey)re(e,1);else{if(t.shiftKey)return void e.enterEditMode();Ce(e,t,1,!1)}else if("ArrowUp"===i)if(t.ctrlKey||t.metaKey)de(e);else{if(t.shiftKey)return void e.enterEditMode();Ce(e,t,-1,!0)}else if("ArrowDown"===i){if(t.shiftKey&&!t.ctrlKey&&!t.metaKey)return void e.enterEditMode();Ce(e,t,1,!0)}else{if("Enter"!==i)return void("Escape"===i?s.hide():"Backspace"!==i&&"Delete"!==i&&(1!==i.length||t.ctrlKey||t.metaKey)||e.enterEditMode());if(a)return void e.setDate(s.viewDate);s.changeView(n-1).render()}}else{if("ArrowDown"!==i)return void("Enter"===i?e.update():"Escape"===i&&s.show());s.show()}t.preventDefault()}function Ee(e){e.config.showOnFocus&&!e._showing&&e.show()}function Fe(e,t){const i=t.target;(e.picker.active||e.config.showOnClick)&&(i._active=N(i),i._clicking=setTimeout((()=>{delete i._active,delete i._clicking}),2e3))}function Ve(e,t){const i=t.target;i._clicking&&(clearTimeout(i._clicking),delete i._clicking,i._active&&e.enterEditMode(),delete i._active,e.config.showOnClick&&e.show())}function Ne(e,t){t.clipboardData.types.includes("text/plain")&&e.enterEditMode()}function Le(e,t){const{element:i,picker:s}=e;if(!s.active&&!N(i))return;const n=s.element;j(t,(e=>e===i||e===n))||oe(e)}function Be(e,t){return e.map((e=>O(e,t.format,t.locale))).join(t.dateDelimiter)}function Ye(e,t,i=!1){const{config:s,dates:a,rangeSideIndex:r}=e;if(0===t.length)return i?[]:void 0;let d=t.reduce(((e,t)=>{let i=C(t,s.format,s.locale);return void 0===i||(i=w(i,s.pickLevel,r),!n(i,s.minDate,s.maxDate)||e.includes(i)||s.datesDisabled.includes(i)||!(s.pickLevel>0)&&s.daysOfWeekDisabled.includes(new Date(i).getDay())||e.push(i)),e}),[]);return 0!==d.length?(s.multidate&&!i&&(d=d.reduce(((e,t)=>(a.includes(t)||e.push(t),e)),a.filter((e=>!d.includes(e))))),s.maxNumberOfDates&&d.length>s.maxNumberOfDates?d.slice(-1*s.maxNumberOfDates):d):void 0}function Ae(e,t=3,i=!0){const{config:s,picker:n,inputField:a}=e;if(2&t){const e=n.active?s.pickLevel:s.startView;n.update().changeView(e).render(i)}1&t&&a&&(a.value=Be(e.dates,s))}function We(e,t,i){let{clear:s,render:n,autohide:a,revert:r}=i;void 0===n&&(n=!0),n?void 0===a&&(a=e.config.autohide):a=!1;const d=Ye(e,t,s);(d||r)&&(d&&d.toString()!==e.dates.toString()?(e.dates=d,Ae(e,n?3:1),ae(e,"changeDate")):Ae(e,1),a&&e.hide())}return class{constructor(e,t={},i){e.datepicker=this,this.element=e;const n=this.config=Object.assign({buttonClass:t.buttonClass&&String(t.buttonClass)||"button",container:null,defaultViewDate:c(),maxDate:void 0,minDate:void 0},X(_,this)),a=this.inline="INPUT"!==e.tagName;let r,d;if(a?n.container=e:(t.container&&(n.container=t.container instanceof HTMLElement?t.container:document.querySelector(t.container)),r=this.inputField=e,r.classList.add("datepicker-input")),i){const e=i.inputs.indexOf(r),t=i.datepickers;if(e<0||e>1||!Array.isArray(t))throw Error("Invalid rangepicker object.");t[e]=this,Object.defineProperty(this,"rangepicker",{get:()=>i}),Object.defineProperty(this,"rangeSideIndex",{get:()=>e})}this._options=t,Object.assign(n,X(t,this)),a?(d=s(e.dataset.date,n.dateDelimiter),delete e.dataset.date):d=s(r.value,n.dateDelimiter),this.dates=[];const o=Ye(this,d);o&&o.length>0&&(this.dates=o),r&&(r.value=Be(this.dates,n));const l=this.picker=new Me(this);if(a)this.show();else{const e=Le.bind(null,this);T(this,[[r,"keydown",Oe.bind(null,this)],[r,"focus",Ee.bind(null,this)],[r,"mousedown",Fe.bind(null,this)],[r,"click",Ve.bind(null,this)],[r,"paste",Ne.bind(null,this)],[document,"mousedown",e],[document,"touchstart",e],[window,"resize",l.place.bind(l)]])}}static formatDate(e,t,i){return O(e,t,i&&$[i]||$.en)}static parseDate(e,t,i){return C(e,t,i&&$[i]||$.en)}static get locales(){return $}get active(){return!(!this.picker||!this.picker.active)}get pickerElement(){return this.picker?this.picker.element:void 0}setOptions(e){const t=this.picker,i=X(e,this);Object.assign(this._options,e),Object.assign(this.config,i),t.setOptions(i),Ae(this,3)}show(){if(this.inputField){if(this.inputField.disabled)return;N(this.inputField)||this.config.disableTouchKeyboard||(this._showing=!0,this.inputField.focus(),delete this._showing)}this.picker.show()}hide(){this.inline||(this.picker.hide(),this.picker.update().changeView(this.config.startView).render())}destroy(){return this.hide(),function(e){let t=A.get(e);t&&(t.forEach((e=>{H.call(...e)})),A.delete(e))}(this),this.picker.detach(),this.inline||this.inputField.classList.remove("datepicker-input"),delete this.element.datepicker,this}getDate(e){const t=e?t=>O(t,e,this.config.locale):e=>new Date(e);return this.config.multidate?this.dates.map(t):this.dates.length>0?t(this.dates[0]):void 0}setDate(...e){const i=[...e],s={},n=t(e);"object"!=typeof n||Array.isArray(n)||n instanceof Date||!n||Object.assign(s,i.pop());We(this,Array.isArray(i[0])?i[0]:i,s)}update(e){if(this.inline)return;const t=Object.assign(e||{},{clear:!0,render:!0});We(this,s(this.inputField.value,this.config.dateDelimiter),t)}refresh(e,t=!1){let i;e&&"string"!=typeof e&&(t=e,e=void 0),i="picker"===e?2:"input"===e?1:3,Ae(this,i,!t)}enterEditMode(){this.inline||!this.picker.active||this.editMode||(this.editMode=!0,this.inputField.classList.add("in-edit"))}exitEditMode(e){if(this.inline||!this.editMode)return;const t=Object.assign({update:!1},e);delete this.editMode,this.inputField.classList.remove("in-edit"),t.update&&this.update(t)}}}(); \ No newline at end of file diff --git a/src/ui/static/js/datepicker/events/functions.js b/src/ui/static/js/datepicker/events/functions.js new file mode 100644 index 000000000..c0853017a --- /dev/null +++ b/src/ui/static/js/datepicker/events/functions.js @@ -0,0 +1,48 @@ +import {limitToRange} from '../lib/utils.js'; +import {addMonths, addYears} from '../lib/date.js'; + +export function triggerDatepickerEvent(datepicker, type) { + const detail = { + date: datepicker.getDate(), + viewDate: new Date(datepicker.picker.viewDate), + viewId: datepicker.picker.currentView.id, + datepicker, + }; + datepicker.element.dispatchEvent(new CustomEvent(type, {detail})); +} + +// direction: -1 (to previous), 1 (to next) +export function goToPrevOrNext(datepicker, direction) { + const {minDate, maxDate} = datepicker.config; + const {currentView, viewDate} = datepicker.picker; + let newViewDate; + switch (currentView.id) { + case 0: + newViewDate = addMonths(viewDate, direction); + break; + case 1: + newViewDate = addYears(viewDate, direction); + break; + default: + newViewDate = addYears(viewDate, direction * currentView.navStep); + } + newViewDate = limitToRange(newViewDate, minDate, maxDate); + datepicker.picker.changeFocus(newViewDate).render(); +} + +export function switchView(datepicker) { + const viewId = datepicker.picker.currentView.id; + if (viewId === datepicker.config.maxView) { + return; + } + datepicker.picker.changeView(viewId + 1).render(); +} + +export function unfocus(datepicker) { + if (datepicker.config.updateOnBlur) { + datepicker.update({revert: true}); + } else { + datepicker.refresh('input'); + } + datepicker.hide(); +} diff --git a/src/ui/static/js/datepicker/events/inputFieldListeners.js b/src/ui/static/js/datepicker/events/inputFieldListeners.js new file mode 100644 index 000000000..acc9cc2a9 --- /dev/null +++ b/src/ui/static/js/datepicker/events/inputFieldListeners.js @@ -0,0 +1,195 @@ +import {isInRange} from '../lib/utils.js'; +import {isActiveElement} from '../lib/dom.js'; +import {addDays, addMonths, addYears, startOfYearPeriod} from '../lib/date.js'; +import {goToPrevOrNext, switchView, unfocus} from './functions.js'; + +// Find the closest date that doesn't meet the condition for unavailable date +// Returns undefined if no available date is found +// addFn: function to calculate the next date +// - args: time value, amount +// increase: amount to pass to addFn +// testFn: function to test the unavailablity of the date +// - args: time value; retun: true if unavailable +function findNextAvailableOne(date, addFn, increase, testFn, min, max) { + if (!isInRange(date, min, max)) { + return; + } + if (testFn(date)) { + const newDate = addFn(date, increase); + return findNextAvailableOne(newDate, addFn, increase, testFn, min, max); + } + return date; +} + +// direction: -1 (left/up), 1 (right/down) +// vertical: true for up/down, false for left/right +function moveByArrowKey(datepicker, ev, direction, vertical) { + const picker = datepicker.picker; + const currentView = picker.currentView; + const step = currentView.step || 1; + let viewDate = picker.viewDate; + let addFn; + let testFn; + switch (currentView.id) { + case 0: + if (vertical) { + viewDate = addDays(viewDate, direction * 7); + } else if (ev.ctrlKey || ev.metaKey) { + viewDate = addYears(viewDate, direction); + } else { + viewDate = addDays(viewDate, direction); + } + addFn = addDays; + testFn = (date) => currentView.disabled.includes(date); + break; + case 1: + viewDate = addMonths(viewDate, vertical ? direction * 4 : direction); + addFn = addMonths; + testFn = (date) => { + const dt = new Date(date); + const {year, disabled} = currentView; + return dt.getFullYear() === year && disabled.includes(dt.getMonth()); + }; + break; + default: + viewDate = addYears(viewDate, direction * (vertical ? 4 : 1) * step); + addFn = addYears; + testFn = date => currentView.disabled.includes(startOfYearPeriod(date, step)); + } + viewDate = findNextAvailableOne( + viewDate, + addFn, + direction < 0 ? -step : step, + testFn, + currentView.minDate, + currentView.maxDate + ); + if (viewDate !== undefined) { + picker.changeFocus(viewDate).render(); + } +} + +export function onKeydown(datepicker, ev) { + const key = ev.key; + if (key === 'Tab') { + unfocus(datepicker); + return; + } + + const picker = datepicker.picker; + const {id, isMinView} = picker.currentView; + if (!picker.active) { + if (key === 'ArrowDown') { + picker.show(); + } else { + if (key === 'Enter') { + datepicker.update(); + } else if (key === 'Escape') { + picker.show(); + } + return; + } + } else if (datepicker.editMode) { + if (key === 'Enter') { + datepicker.exitEditMode({update: true, autohide: datepicker.config.autohide}); + } else if (key === 'Escape') { + picker.hide(); + } + return; + } else { + if (key === 'ArrowLeft') { + if (ev.ctrlKey || ev.metaKey) { + goToPrevOrNext(datepicker, -1); + } else if (ev.shiftKey) { + datepicker.enterEditMode(); + return; + } else { + moveByArrowKey(datepicker, ev, -1, false); + } + } else if (key === 'ArrowRight') { + if (ev.ctrlKey || ev.metaKey) { + goToPrevOrNext(datepicker, 1); + } else if (ev.shiftKey) { + datepicker.enterEditMode(); + return; + } else { + moveByArrowKey(datepicker, ev, 1, false); + } + } else if (key === 'ArrowUp') { + if (ev.ctrlKey || ev.metaKey) { + switchView(datepicker); + } else if (ev.shiftKey) { + datepicker.enterEditMode(); + return; + } else { + moveByArrowKey(datepicker, ev, -1, true); + } + } else if (key === 'ArrowDown') { + if (ev.shiftKey && !ev.ctrlKey && !ev.metaKey) { + datepicker.enterEditMode(); + return; + } + moveByArrowKey(datepicker, ev, 1, true); + } else if (key === 'Enter') { + if (isMinView) { + datepicker.setDate(picker.viewDate); + return; + } + picker.changeView(id - 1).render(); + } else { + if (key === 'Escape') { + picker.hide(); + } else if ( + key === 'Backspace' + || key === 'Delete' + || (key.length === 1 && !ev.ctrlKey && !ev.metaKey) + ) { + datepicker.enterEditMode(); + } + return; + } + } + ev.preventDefault(); +} + +export function onFocus(datepicker) { + if (datepicker.config.showOnFocus && !datepicker._showing) { + datepicker.show(); + } +} + +// for the prevention for entering edit mode while getting focus on click +export function onMousedown(datepicker, ev) { + const el = ev.target; + if (datepicker.picker.active || datepicker.config.showOnClick) { + el._active = isActiveElement(el); + el._clicking = setTimeout(() => { + delete el._active; + delete el._clicking; + }, 2000); + } +} + +export function onClickInput(datepicker, ev) { + const el = ev.target; + if (!el._clicking) { + return; + } + clearTimeout(el._clicking); + delete el._clicking; + + if (el._active) { + datepicker.enterEditMode(); + } + delete el._active; + + if (datepicker.config.showOnClick) { + datepicker.show(); + } +} + +export function onPaste(datepicker, ev) { + if (ev.clipboardData.types.includes('text/plain')) { + datepicker.enterEditMode(); + } +} diff --git a/src/ui/static/js/datepicker/events/otherListeners.js b/src/ui/static/js/datepicker/events/otherListeners.js new file mode 100644 index 000000000..d25b5daa3 --- /dev/null +++ b/src/ui/static/js/datepicker/events/otherListeners.js @@ -0,0 +1,20 @@ +import {isActiveElement} from '../lib/dom.js'; +import {findElementInEventPath} from '../lib/event.js'; +import {unfocus} from './functions.js'; + +// for the `document` to delegate the events from outside the picker/input field +export function onClickOutside(datepicker, ev) { + const {element, picker} = datepicker; + // check both picker's and input's activeness to make updateOnBlur work in + // the cases where... + // - picker is hidden by ESC key press → input stays focused + // - input is unfocused by closing mobile keyboard → piker is kept shown + if (!picker.active && !isActiveElement(element)) { + return; + } + const pickerElem = picker.element; + if (findElementInEventPath(ev, el => el === element || el === pickerElem)) { + return; + } + unfocus(datepicker); +} diff --git a/src/ui/static/js/datepicker/events/pickerListeners.js b/src/ui/static/js/datepicker/events/pickerListeners.js new file mode 100644 index 000000000..3deff58c1 --- /dev/null +++ b/src/ui/static/js/datepicker/events/pickerListeners.js @@ -0,0 +1,68 @@ +import {today, addMonths, addYears} from '../lib/date.js'; +import {findElementInEventPath} from '../lib/event.js'; +import {goToPrevOrNext, switchView} from './functions.js'; + +function goToSelectedMonthOrYear(datepicker, selection) { + const picker = datepicker.picker; + const viewDate = new Date(picker.viewDate); + const viewId = picker.currentView.id; + const newDate = viewId === 1 + ? addMonths(viewDate, selection - viewDate.getMonth()) + : addYears(viewDate, selection - viewDate.getFullYear()); + + picker.changeFocus(newDate).changeView(viewId - 1).render(); +} + +export function onClickTodayBtn(datepicker) { + const picker = datepicker.picker; + const currentDate = today(); + if (datepicker.config.todayBtnMode === 1) { + if (datepicker.config.autohide) { + datepicker.setDate(currentDate); + return; + } + datepicker.setDate(currentDate, {render: false}); + picker.update(); + } + if (picker.viewDate !== currentDate) { + picker.changeFocus(currentDate); + } + picker.changeView(0).render(); +} + +export function onClickClearBtn(datepicker) { + datepicker.setDate({clear: true}); +} + +export function onClickViewSwitch(datepicker) { + switchView(datepicker); +} + +export function onClickPrevBtn(datepicker) { + goToPrevOrNext(datepicker, -1); +} + +export function onClickNextBtn(datepicker) { + goToPrevOrNext(datepicker, 1); +} + +// For the picker's main block to delegete the events from `datepicker-cell`s +export function onClickView(datepicker, ev) { + const target = findElementInEventPath(ev, '.datepicker-cell'); + if (!target || target.classList.contains('disabled')) { + return; + } + + const {id, isMinView} = datepicker.picker.currentView; + if (isMinView) { + datepicker.setDate(Number(target.dataset.date)); + } else if (id === 1) { + goToSelectedMonthOrYear(datepicker, Number(target.dataset.month)); + } else { + goToSelectedMonthOrYear(datepicker, Number(target.dataset.year)); + } +} + +export function onMousedownPicker(ev) { + ev.preventDefault(); +} diff --git a/src/ui/static/js/datepicker/i18n/base-locales.js b/src/ui/static/js/datepicker/i18n/base-locales.js new file mode 100644 index 000000000..96bd963d7 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/base-locales.js @@ -0,0 +1,13 @@ +// default locales +export const locales = { + en: { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + clear: "Clear", + titleFormat: "MM y" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ar-DZ.js b/src/ui/static/js/datepicker/i18n/locales/ar-DZ.js new file mode 100644 index 000000000..0a9269d91 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ar-DZ.js @@ -0,0 +1,19 @@ +/** + * Arabic-Algeria translation for bootstrap-datepicker + * Rabah Saadi + */ +export default { + 'ar-DZ': { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], + months: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + monthsShort: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + today: "هذا اليوم", + rtl: true, + monthsTitle: "أشهر", + clear: "إزالة", + format: "yyyy/mm/dd", + weekStart: 0 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ar-tn.js b/src/ui/static/js/datepicker/i18n/locales/ar-tn.js new file mode 100644 index 000000000..5a3b6af8e --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ar-tn.js @@ -0,0 +1,15 @@ +/** + * Arabic-Tunisia translation for bootstrap-datepicker + * Souhaieb Besbes + */ +export default { + 'ar-tn': { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], + months: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + monthsShort: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + today: "هذا اليوم", + rtl: true + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ar.js b/src/ui/static/js/datepicker/i18n/locales/ar.js new file mode 100644 index 000000000..3ee311fe2 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ar.js @@ -0,0 +1,15 @@ +/** + * Arabic translation for bootstrap-datepicker + * Mohammed Alshehri + */ +export default { + ar: { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], + months: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + monthsShort: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + today: "هذا اليوم", + rtl: true + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/az.js b/src/ui/static/js/datepicker/i18n/locales/az.js new file mode 100644 index 000000000..52c38bb8d --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/az.js @@ -0,0 +1,14 @@ +// Azerbaijani +export default { + az: { + days: ["Bazar", "Bazar ertəsi", "Çərşənbə axşamı", "Çərşənbə", "Cümə axşamı", "Cümə", "Şənbə"], + daysShort: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş."], + daysMin: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş."], + months: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr"], + monthsShort: ["Yan", "Fev", "Mar", "Apr", "May", "İyun", "İyul", "Avq", "Sen", "Okt", "Noy", "Dek"], + today: "Bu gün", + weekStart: 1, + clear: "Təmizlə", + monthsTitle: 'Aylar' + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/bg.js b/src/ui/static/js/datepicker/i18n/locales/bg.js new file mode 100644 index 000000000..a667db287 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/bg.js @@ -0,0 +1,14 @@ +/** + * Bulgarian translation for bootstrap-datepicker + * Apostol Apostolov + */ +export default { + bg: { + days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота"], + daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб"], + daysMin: ["Н", "П", "В", "С", "Ч", "П", "С"], + months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "днес" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/bm.js b/src/ui/static/js/datepicker/i18n/locales/bm.js new file mode 100644 index 000000000..92bcdbbc5 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/bm.js @@ -0,0 +1,18 @@ +/** + * Bamanankan (bm) translation for bootstrap-datepicker + * Fatou Fall + */ +export default { + bm: { + days: ["Kari","Ntɛnɛn","Tarata","Araba","Alamisa","Juma","Sibiri"], + daysShort: ["Kar","Ntɛ","Tar","Ara","Ala","Jum","Sib"], + daysMin: ["Ka","Nt","Ta","Ar","Al","Ju","Si"], + months: ["Zanwuyekalo","Fewuruyekalo","Marisikalo","Awirilikalo","Mɛkalo","Zuwɛnkalo","Zuluyekalo","Utikalo","Sɛtanburukalo","ɔkutɔburukalo","Nowanburukalo","Desanburukalo"], + monthsShort: ["Zan","Few","Mar","Awi","Mɛ","Zuw","Zul","Uti","Sɛt","ɔku","Now","Des"], + today: "Bi", + monthsTitle: "Kalo", + clear: "Ka jɔsi", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/bn.js b/src/ui/static/js/datepicker/i18n/locales/bn.js new file mode 100644 index 000000000..94aca096d --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/bn.js @@ -0,0 +1,19 @@ +/** + * Bengali (Bangla) translation for bootstrap-datepicker + * Karim Khan + * Orif N. Jr. + */ +export default { + bn: { + days: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], + daysShort: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], + daysMin: ["রবি","সোম","মঙ্গল","বুধ","বৃহস্পতি","শুক্র","শনি"], + months: ["জানুয়ারী","ফেব্রুয়ারি","মার্চ","এপ্রিল","মে","জুন","জুলাই","অগাস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর"], + monthsShort: ["জানুয়ারী","ফেব্রুয়ারি","মার্চ","এপ্রিল","মে","জুন","জুলাই","অগাস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর"], + today: "আজ", + monthsTitle: "মাস", + clear: "পরিষ্কার", + weekStart: 0, + format: "mm/dd/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/br.js b/src/ui/static/js/datepicker/i18n/locales/br.js new file mode 100644 index 000000000..39ca7a7ea --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/br.js @@ -0,0 +1,18 @@ +/** + * Breton translation for bootstrap-datepicker + * Gwenn Meynier + */ +export default { + br: { + days: ["Sul", "Lun", "Meurzh", "Merc'her", "Yaou", "Gwener", "Sadorn"], + daysShort: ["Sul", "Lun", "Meu.", "Mer.", "Yao.", "Gwe.", "Sad."], + daysMin: ["Su", "L", "Meu", "Mer", "Y", "G", "Sa"], + months: ["Genver", "C'hwevrer", "Meurzh", "Ebrel", "Mae", "Mezheven", "Gouere", "Eost", "Gwengolo", "Here", "Du", "Kerzu"], + monthsShort: ["Genv.", "C'hw.", "Meur.", "Ebre.", "Mae", "Mezh.", "Goue.", "Eost", "Gwen.", "Here", "Du", "Kerz."], + today: "Hiziv", + monthsTitle: "Miz", + clear: "Dilemel", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/bs.js b/src/ui/static/js/datepicker/i18n/locales/bs.js new file mode 100644 index 000000000..47b7fa49c --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/bs.js @@ -0,0 +1,15 @@ +/** + * Bosnian translation for bootstrap-datepicker + */ +export default { + bs: { + days: ["Nedjelja","Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"], + daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Juni", "Juli", "August", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Danas", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ca.js b/src/ui/static/js/datepicker/i18n/locales/ca.js new file mode 100644 index 000000000..9260b6071 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ca.js @@ -0,0 +1,18 @@ +/** + * Catalan translation for bootstrap-datepicker + * J. Garcia + */ +export default { + ca: { + days: ["diumenge", "dilluns", "dimarts", "dimecres", "dijous", "divendres", "dissabte"], + daysShort: ["dg.", "dl.", "dt.", "dc.", "dj.", "dv.", "ds."], + daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds"], + months: ["gener", "febrer", "març", "abril", "maig", "juny", "juliol", "agost", "setembre", "octubre", "novembre", "desembre"], + monthsShort: ["gen.", "febr.", "març", "abr.", "maig", "juny", "jul.", "ag.", "set.", "oct.", "nov.", "des."], + today: "Avui", + monthsTitle: "Mesos", + clear: "Esborra", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/cs.js b/src/ui/static/js/datepicker/i18n/locales/cs.js new file mode 100644 index 000000000..ac3e584af --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/cs.js @@ -0,0 +1,19 @@ +/** + * Czech translation for bootstrap-datepicker + * Matěj Koubík + * Fixes by Michal Remiš + */ +export default { + cs: { + days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota"], + daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob"], + daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So"], + months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], + monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], + today: "Dnes", + clear: "Vymazat", + monthsTitle: "Měsíc", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/cy.js b/src/ui/static/js/datepicker/i18n/locales/cy.js new file mode 100644 index 000000000..0efd1a695 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/cy.js @@ -0,0 +1,14 @@ +/** + * Welsh translation for bootstrap-datepicker + * S. Morris + */ +export default { + cy: { + days: ["Sul", "Llun", "Mawrth", "Mercher", "Iau", "Gwener", "Sadwrn"], + daysShort: ["Sul", "Llu", "Maw", "Mer", "Iau", "Gwe", "Sad"], + daysMin: ["Su", "Ll", "Ma", "Me", "Ia", "Gwe", "Sa"], + months: ["Ionawr", "Chewfror", "Mawrth", "Ebrill", "Mai", "Mehefin", "Gorfennaf", "Awst", "Medi", "Hydref", "Tachwedd", "Rhagfyr"], + monthsShort: ["Ion", "Chw", "Maw", "Ebr", "Mai", "Meh", "Gor", "Aws", "Med", "Hyd", "Tach", "Rha"], + today: "Heddiw" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/da.js b/src/ui/static/js/datepicker/i18n/locales/da.js new file mode 100644 index 000000000..5bbdbec1e --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/da.js @@ -0,0 +1,19 @@ +/** + * Danish translation for bootstrap-datepicker + * Christian Pedersen + * Ivan Mylyanyk + */ +export default { + da: { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø"], + months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "I Dag", + weekStart: 1, + clear: "Nulstil", + format: "dd/mm/yyyy", + monthsTitle: "Måneder" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/de.js b/src/ui/static/js/datepicker/i18n/locales/de.js new file mode 100644 index 000000000..bd0f5dd4a --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/de.js @@ -0,0 +1,18 @@ +/** + * German translation for bootstrap-datepicker + * Sam Zurcher + */ +export default { + de: { + days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], + daysShort: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], + daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], + months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], + monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], + today: "Heute", + monthsTitle: "Monate", + clear: "Löschen", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/el.js b/src/ui/static/js/datepicker/i18n/locales/el.js new file mode 100644 index 000000000..4a3f2df3b --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/el.js @@ -0,0 +1,16 @@ +/** + * Greek translation for bootstrap-datepicker + */ +export default { + el: { + days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"], + daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"], + daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα"], + months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], + monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], + today: "Σήμερα", + clear: "Καθαρισμός", + weekStart: 1, + format: "d/m/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/en-AU.js b/src/ui/static/js/datepicker/i18n/locales/en-AU.js new file mode 100644 index 000000000..cddae4086 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/en-AU.js @@ -0,0 +1,18 @@ +/** + * Australian English translation for bootstrap-datepicker + * Steve Chapman + */ +export default { + 'en-AU': { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "d/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/en-CA.js b/src/ui/static/js/datepicker/i18n/locales/en-CA.js new file mode 100644 index 000000000..aeef9b690 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/en-CA.js @@ -0,0 +1,18 @@ +/** + * Canadian English translation for bootstrap-datepicker + * Mike Nacey + */ +export default { + 'en-CA': { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 0, + format: "yyyy-mm-dd" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/en-GB.js b/src/ui/static/js/datepicker/i18n/locales/en-GB.js new file mode 100644 index 000000000..fa865ad71 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/en-GB.js @@ -0,0 +1,18 @@ +/** + * British English translation for bootstrap-datepicker + * Xavier Dutreilh + */ +export default { + 'en-GB': { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/en-IE.js b/src/ui/static/js/datepicker/i18n/locales/en-IE.js new file mode 100644 index 000000000..c9988bd48 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/en-IE.js @@ -0,0 +1,17 @@ +/** + * Irish English translation for bootstrap-datepicker + */ +export default { + 'en-IE': { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/en-NZ.js b/src/ui/static/js/datepicker/i18n/locales/en-NZ.js new file mode 100644 index 000000000..bad9a0766 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/en-NZ.js @@ -0,0 +1,17 @@ +/** + * New Zealand English translation for bootstrap-datepicker + */ +export default { + 'en-NZ': { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "d/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/en-ZA.js b/src/ui/static/js/datepicker/i18n/locales/en-ZA.js new file mode 100644 index 000000000..e44e4693d --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/en-ZA.js @@ -0,0 +1,17 @@ +/** + * South African English translation for bootstrap-datepicker + */ +export default { + 'en-ZA': { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "yyyy/mm/d" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/eo.js b/src/ui/static/js/datepicker/i18n/locales/eo.js new file mode 100644 index 000000000..a53430013 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/eo.js @@ -0,0 +1,17 @@ +/** + * Esperanto translation for bootstrap-datepicker + * Emmanuel Debanne + */ +export default { + eo: { + days: ["dimanĉo", "lundo", "mardo", "merkredo", "ĵaŭdo", "vendredo", "sabato"], + daysShort: ["dim.", "lun.", "mar.", "mer.", "ĵaŭ.", "ven.", "sam."], + daysMin: ["d", "l", "ma", "me", "ĵ", "v", "s"], + months: ["januaro", "februaro", "marto", "aprilo", "majo", "junio", "julio", "aŭgusto", "septembro", "oktobro", "novembro", "decembro"], + monthsShort: ["jan.", "feb.", "mar.", "apr.", "majo", "jun.", "jul.", "aŭg.", "sep.", "okt.", "nov.", "dec."], + today: "Hodiaŭ", + clear: "Nuligi", + weekStart: 1, + format: "yyyy-mm-dd" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/es.js b/src/ui/static/js/datepicker/i18n/locales/es.js new file mode 100644 index 000000000..201f52f65 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/es.js @@ -0,0 +1,18 @@ +/** + * Spanish translation for bootstrap-datepicker + * Bruno Bonamin + */ +export default { + es: { + days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"], + daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"], + daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa"], + months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], + monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], + today: "Hoy", + monthsTitle: "Meses", + clear: "Borrar", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/et.js b/src/ui/static/js/datepicker/i18n/locales/et.js new file mode 100644 index 000000000..183878b1c --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/et.js @@ -0,0 +1,18 @@ +/** + * Estonian translation for bootstrap-datepicker + * Ando Roots + * Fixes by Illimar Tambek < + */ +export default { + et: { + days: ["Pühapäev", "Esmaspäev", "Teisipäev", "Kolmapäev", "Neljapäev", "Reede", "Laupäev"], + daysShort: ["Pühap", "Esmasp", "Teisip", "Kolmap", "Neljap", "Reede", "Laup"], + daysMin: ["P", "E", "T", "K", "N", "R", "L"], + months: ["Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember"], + monthsShort: ["Jaan", "Veebr", "Märts", "Apr", "Mai", "Juuni", "Juuli", "Aug", "Sept", "Okt", "Nov", "Dets"], + today: "Täna", + clear: "Tühjenda", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/eu.js b/src/ui/static/js/datepicker/i18n/locales/eu.js new file mode 100644 index 000000000..1f3c2c30e --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/eu.js @@ -0,0 +1,18 @@ +/** + * Basque translation for bootstrap-datepicker + * Arkaitz Etxeberria + */ +export default { + eu: { + days: ['Igandea', 'Astelehena', 'Asteartea', 'Asteazkena', 'Osteguna', 'Ostirala', 'Larunbata'], + daysShort: ['Ig', 'Al', 'Ar', 'Az', 'Og', 'Ol', 'Lr'], + daysMin: ['Ig', 'Al', 'Ar', 'Az', 'Og', 'Ol', 'Lr'], + months: ['Urtarrila', 'Otsaila', 'Martxoa', 'Apirila', 'Maiatza', 'Ekaina', 'Uztaila', 'Abuztua', 'Iraila', 'Urria', 'Azaroa', 'Abendua'], + monthsShort: ['Urt', 'Ots', 'Mar', 'Api', 'Mai', 'Eka', 'Uzt', 'Abu', 'Ira', 'Urr', 'Aza', 'Abe'], + today: "Gaur", + monthsTitle: "Hilabeteak", + clear: "Ezabatu", + weekStart: 1, + format: "yyyy/mm/dd" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/fa.js b/src/ui/static/js/datepicker/i18n/locales/fa.js new file mode 100644 index 000000000..dece24ed0 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/fa.js @@ -0,0 +1,17 @@ +/** + * Persian translation for bootstrap-datepicker + * Mostafa Rokooie + */ +export default { + fa: { + days: ["یک‌شنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنج‌شنبه", "جمعه", "شنبه", "یک‌شنبه"], + daysShort: ["یک", "دو", "سه", "چهار", "پنج", "جمعه", "شنبه", "یک"], + daysMin: ["ی", "د", "س", "چ", "پ", "ج", "ش", "ی"], + months: ["ژانویه", "فوریه", "مارس", "آوریل", "مه", "ژوئن", "ژوئیه", "اوت", "سپتامبر", "اکتبر", "نوامبر", "دسامبر"], + monthsShort: ["ژان", "فور", "مار", "آور", "مه", "ژون", "ژوی", "اوت", "سپت", "اکت", "نوا", "دسا"], + today: "امروز", + clear: "پاک کن", + weekStart: 1, + format: "yyyy/mm/dd" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/fi.js b/src/ui/static/js/datepicker/i18n/locales/fi.js new file mode 100644 index 000000000..d9fde77fb --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/fi.js @@ -0,0 +1,17 @@ +/** + * Finnish translation for bootstrap-datepicker + * Jaakko Salonen + */ +export default { + fi: { + days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"], + daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau"], + daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la"], + months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], + monthsShort: ["tammi", "helmi", "maalis", "huhti", "touko", "kesä", "heinä", "elo", "syys", "loka", "marras", "joulu"], + today: "tänään", + clear: "Tyhjennä", + weekStart: 1, + format: "d.m.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/fo.js b/src/ui/static/js/datepicker/i18n/locales/fo.js new file mode 100644 index 000000000..908ccfcc8 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/fo.js @@ -0,0 +1,15 @@ +/** + * Faroese translation for bootstrap-datepicker + * Theodor Johannesen + */ +export default { + fo: { + days: ["Sunnudagur", "Mánadagur", "Týsdagur", "Mikudagur", "Hósdagur", "Fríggjadagur", "Leygardagur"], + daysShort: ["Sun", "Mán", "Týs", "Mik", "Hós", "Frí", "Ley"], + daysMin: ["Su", "Má", "Tý", "Mi", "Hó", "Fr", "Le"], + months: ["Januar", "Februar", "Marts", "Apríl", "Mei", "Juni", "Juli", "August", "Septembur", "Oktobur", "Novembur", "Desembur"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], + today: "Í Dag", + clear: "Reinsa" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/fr-CH.js b/src/ui/static/js/datepicker/i18n/locales/fr-CH.js new file mode 100644 index 000000000..6d90d69bd --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/fr-CH.js @@ -0,0 +1,21 @@ +/** + * French (Switzerland) translation for bootstrap-datepicker + * Christoph Jossi + * Based on + * French translation for bootstrap-datepicker + * Nico Mollet + */ +export default { + 'fr-CH': { + days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"], + daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"], + daysMin: ["D", "L", "Ma", "Me", "J", "V", "S"], + months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], + monthsShort: ["Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Déc"], + today: "Aujourd'hui", + monthsTitle: "Mois", + clear: "Effacer", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/fr.js b/src/ui/static/js/datepicker/i18n/locales/fr.js new file mode 100644 index 000000000..cac7cc355 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/fr.js @@ -0,0 +1,18 @@ +/** + * French translation for bootstrap-datepicker + * Nico Mollet + */ +export default { + fr: { + days: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], + daysShort: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], + daysMin: ["d", "l", "ma", "me", "j", "v", "s"], + months: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"], + monthsShort: ["janv.", "févr.", "mars", "avril", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."], + today: "Aujourd'hui", + monthsTitle: "Mois", + clear: "Effacer", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/gl.js b/src/ui/static/js/datepicker/i18n/locales/gl.js new file mode 100644 index 000000000..86581e78d --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/gl.js @@ -0,0 +1,16 @@ +/** + * Galician translation + */ +export default { + gl: { + days: ["Domingo", "Luns", "Martes", "Mércores", "Xoves", "Venres", "Sábado"], + daysShort: ["Dom", "Lun", "Mar", "Mér", "Xov", "Ven", "Sáb"], + daysMin: ["Do", "Lu", "Ma", "Me", "Xo", "Ve", "Sa"], + months: ["Xaneiro", "Febreiro", "Marzo", "Abril", "Maio", "Xuño", "Xullo", "Agosto", "Setembro", "Outubro", "Novembro", "Decembro"], + monthsShort: ["Xan", "Feb", "Mar", "Abr", "Mai", "Xun", "Xul", "Ago", "Sep", "Out", "Nov", "Dec"], + today: "Hoxe", + clear: "Limpar", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/he.js b/src/ui/static/js/datepicker/i18n/locales/he.js new file mode 100644 index 000000000..c7f1d62e6 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/he.js @@ -0,0 +1,15 @@ +/** + * Hebrew translation for bootstrap-datepicker + * Sagie Maoz + */ +export default { + he: { + days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], + daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], + monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], + today: "היום", + rtl: true + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/hi.js b/src/ui/static/js/datepicker/i18n/locales/hi.js new file mode 100644 index 000000000..25d68cdab --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/hi.js @@ -0,0 +1,18 @@ +/** + * Hindi translation for bootstrap-datepicker + * Visar Uruqi + */ +export default { + hi: { + days: ["रविवार", "सोमवार", "मंगलवार", "बुधवार", "गुरुवार", "शुक्रवार", "शनिवार"], + daysShort: ["सूर्य", "सोम", "मंगल", "बुध", "गुरु", "शुक्र", "शनि"], + daysMin: ["र", "सो", "मं", "बु", "गु", "शु", "श"], + months: ["जनवरी", "फ़रवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितम्बर", "अक्टूबर", "नवंबर", "दिसम्बर"], + monthsShort: ["जन", "फ़रवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितं", "अक्टूबर", "नवं", "दिसम्बर"], + today: "आज", + monthsTitle: "महीने", + clear: "साफ", + weekStart: 1, + format: "dd / mm / yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/hr.js b/src/ui/static/js/datepicker/i18n/locales/hr.js new file mode 100644 index 000000000..0360859c2 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/hr.js @@ -0,0 +1,13 @@ +/** + * Croatian localisation + */ +export default { + hr: { + days: ["Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"], + daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su"], + months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], + monthsShort: ["Sij", "Velj", "Ožu", "Tra", "Svi", "Lip", "Srp", "Kol", "Ruj", "Lis", "Stu", "Pro"], + today: "Danas" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/hu.js b/src/ui/static/js/datepicker/i18n/locales/hu.js new file mode 100644 index 000000000..f5342671b --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/hu.js @@ -0,0 +1,18 @@ +/** + * Hungarian translation for bootstrap-datepicker + * Sotus László + */ +export default { + hu: { + days: ["vasárnap", "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat"], + daysShort: ["vas", "hét", "ked", "sze", "csü", "pén", "szo"], + daysMin: ["V", "H", "K", "Sze", "Cs", "P", "Szo"], + months: ["január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december"], + monthsShort: ["jan", "feb", "már", "ápr", "máj", "jún", "júl", "aug", "sze", "okt", "nov", "dec"], + today: "ma", + weekStart: 1, + clear: "töröl", + titleFormat: "y. MM", + format: "yyyy.mm.dd" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/hy.js b/src/ui/static/js/datepicker/i18n/locales/hy.js new file mode 100644 index 000000000..599dc800e --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/hy.js @@ -0,0 +1,18 @@ +/** + * Armenian translation for bootstrap-datepicker + * Hayk Chamyan + */ +export default { + hy: { + days: ["Կիրակի", "Երկուշաբթի", "Երեքշաբթի", "Չորեքշաբթի", "Հինգշաբթի", "Ուրբաթ", "Շաբաթ"], + daysShort: ["Կիր", "Երկ", "Երե", "Չոր", "Հին", "Ուրբ", "Շաբ"], + daysMin: ["Կի", "Եկ", "Եք", "Չո", "Հի", "Ու", "Շա"], + months: ["Հունվար", "Փետրվար", "Մարտ", "Ապրիլ", "Մայիս", "Հունիս", "Հուլիս", "Օգոստոս", "Սեպտեմբեր", "Հոկտեմբեր", "Նոյեմբեր", "Դեկտեմբեր"], + monthsShort: ["Հնվ", "Փետ", "Մար", "Ապր", "Մայ", "Հուն", "Հուլ", "Օգս", "Սեպ", "Հոկ", "Նոյ", "Դեկ"], + today: "Այսօր", + clear: "Ջնջել", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Ամիսնէր' + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/id.js b/src/ui/static/js/datepicker/i18n/locales/id.js new file mode 100644 index 000000000..4dc532baa --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/id.js @@ -0,0 +1,19 @@ +/** + * Bahasa translation for bootstrap-datepicker + * Azwar Akbar + * Ardeman + */ +export default { + id: { + days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"], + daysShort: ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"], + daysMin: ["Mg", "Sn", "Sl", "Rb", "Km", "Jm", "Sb"], + months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agt", "Sep", "Okt", "Nov", "Des"], + today: "Hari Ini", + monthsTitle: "Bulan", + clear: "Kosongkan", + weekStart: 0, + format: "dd-mm-yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/is.js b/src/ui/static/js/datepicker/i18n/locales/is.js new file mode 100644 index 000000000..efbd2a6d9 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/is.js @@ -0,0 +1,14 @@ +/** + * Icelandic translation for bootstrap-datepicker + * Hinrik Örn Sigurðsson + */ +export default { + is: { + days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur"], + daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau"], + daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La"], + months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], + today: "Í Dag" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/it-CH.js b/src/ui/static/js/datepicker/i18n/locales/it-CH.js new file mode 100644 index 000000000..21e355bb9 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/it-CH.js @@ -0,0 +1,20 @@ +/** + * Italian (Switzerland) translation for bootstrap-datepicker + * Christoph Jossi + * Based on + * Italian translation for bootstrap-datepicker + * Enrico Rubboli + */ +export default { + 'it-CH': { + days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"], + daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"], + daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa"], + months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], + today: "Oggi", + clear: "Cancella", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/it.js b/src/ui/static/js/datepicker/i18n/locales/it.js new file mode 100644 index 000000000..169500447 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/it.js @@ -0,0 +1,18 @@ +/** + * Italian translation for bootstrap-datepicker + * Enrico Rubboli + */ +export default { + it: { + days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"], + daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"], + daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa"], + months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], + today: "Oggi", + monthsTitle: "Mesi", + clear: "Cancella", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ja.js b/src/ui/static/js/datepicker/i18n/locales/ja.js new file mode 100644 index 000000000..bdcb0dd99 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ja.js @@ -0,0 +1,17 @@ +/** + * Japanese translation for bootstrap-datepicker + * Norio Suzuki + */ +export default { + ja: { + days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜"], + daysShort: ["日", "月", "火", "水", "木", "金", "土"], + daysMin: ["日", "月", "火", "水", "木", "金", "土"], + months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今日", + format: "yyyy/mm/dd", + titleFormat: "y年mm月", + clear: "クリア" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ka.js b/src/ui/static/js/datepicker/i18n/locales/ka.js new file mode 100644 index 000000000..b2a7c0ddf --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ka.js @@ -0,0 +1,17 @@ +/** + * Georgian translation for bootstrap-datepicker + * Levan Melikishvili + */ +export default { + ka: { + days: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი"], + daysShort: ["კვი", "ორშ", "სამ", "ოთხ", "ხუთ", "პარ", "შაბ"], + daysMin: ["კვ", "ორ", "სა", "ოთ", "ხუ", "პა", "შა"], + months: ["იანვარი", "თებერვალი", "მარტი", "აპრილი", "მაისი", "ივნისი", "ივლისი", "აგვისტო", "სექტემბერი", "ოქტომბერი", "ნოემბერი", "დეკემბერი"], + monthsShort: ["იან", "თებ", "მარ", "აპრ", "მაი", "ივნ", "ივლ", "აგვ", "სექ", "ოქტ", "ნოე", "დეკ"], + today: "დღეს", + clear: "გასუფთავება", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/kk.js b/src/ui/static/js/datepicker/i18n/locales/kk.js new file mode 100644 index 000000000..46ad589e8 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/kk.js @@ -0,0 +1,15 @@ +/** + * Kazakh translation for bootstrap-datepicker + * Yerzhan Tolekov + */ +export default { + kk: { + days: ["Жексенбі", "Дүйсенбі", "Сейсенбі", "Сәрсенбі", "Бейсенбі", "Жұма", "Сенбі"], + daysShort: ["Жек", "Дүй", "Сей", "Сәр", "Бей", "Жұм", "Сен"], + daysMin: ["Жк", "Дс", "Сс", "Ср", "Бс", "Жм", "Сн"], + months: ["Қаңтар", "Ақпан", "Наурыз", "Сәуір", "Мамыр", "Маусым", "Шілде", "Тамыз", "Қыркүйек", "Қазан", "Қараша", "Желтоқсан"], + monthsShort: ["Қаң", "Ақп", "Нау", "Сәу", "Мам", "Мау", "Шіл", "Там", "Қыр", "Қаз", "Қар", "Жел"], + today: "Бүгін", + weekStart: 1 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/km.js b/src/ui/static/js/datepicker/i18n/locales/km.js new file mode 100644 index 000000000..1688262e0 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/km.js @@ -0,0 +1,15 @@ +/** + * Khmer translation for bootstrap-datepicker + * This is the Updated Version of: https: //github.com/uxsolutions/bootstrap-datepicker/blob/71308d42cce9524284c50c6fac50422d1790ac0f/js/locales/bootstrap-datepicker.kh.js + */ +export default { + km: { + days: ["អាទិត្យ", "ចន្ទ", "អង្គារ", "ពុធ", "ព្រហស្បតិ៍", "សុក្រ", "សៅរ៍"], + daysShort: ["អា.ទិ", "ចន្ទ", "អង្គារ", "ពុធ", "ព្រ.ហ", "សុក្រ", "សៅរ៍"], + daysMin: ["អា.ទិ", "ចន្ទ", "អង្គារ", "ពុធ", "ព្រ.ហ", "សុក្រ", "សៅរ៍"], + months: ["មករា", "កុម្ភះ", "មិនា", "មេសា", "ឧសភា", "មិថុនា", "កក្កដា", "សីហា", "កញ្ញា", "តុលា", "វិច្ឆិកា", "ធ្នូ"], + monthsShort: ["មករា", "កុម្ភះ", "មិនា", "មេសា", "ឧសភា", "មិថុនា", "កក្កដា", "សីហា", "កញ្ញា", "តុលា", "វិច្ឆិកា", "ធ្នូ"], + today: "ថ្ងៃនេះ", + clear: "សំអាត" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ko.js b/src/ui/static/js/datepicker/i18n/locales/ko.js new file mode 100644 index 000000000..d5eb49e8b --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ko.js @@ -0,0 +1,18 @@ +/** + * Korean translation for bootstrap-datepicker + * This is a port from https: //github.com/moment/moment/blob/develop/src/locale/ko.js + */ +export default { + ko: { + days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"], + daysShort: ["일", "월", "화", "수", "목", "금", "토"], + daysMin: ["일", "월", "화", "수", "목", "금", "토"], + months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + today: "오늘", + clear: "삭제", + format: "yyyy-mm-dd", + titleFormat: "y년mm월", + weekStart: 0 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/lt.js b/src/ui/static/js/datepicker/i18n/locales/lt.js new file mode 100644 index 000000000..960ef9fff --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/lt.js @@ -0,0 +1,19 @@ +/** + * Lithuanian translation for bootstrap-datepicker + * Šarūnas Gliebus + */ + +export default { + lt: { + days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis"], + daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š"], + daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št"], + months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], + monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], + today: "Šiandien", + monthsTitle: "Mėnesiai", + clear: "Išvalyti", + weekStart: 1, + format: "yyyy-mm-dd" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/lv.js b/src/ui/static/js/datepicker/i18n/locales/lv.js new file mode 100644 index 000000000..68a4542f8 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/lv.js @@ -0,0 +1,18 @@ +/** + * Latvian translation for bootstrap-datepicker + * Artis Avotins + */ + +export default { + lv: { + days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena"], + daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S"], + daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"], + months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec"], + monthsTitle: "Mēneši", + today: "Šodien", + clear: "Nodzēst", + weekStart: 1 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/me.js b/src/ui/static/js/datepicker/i18n/locales/me.js new file mode 100644 index 000000000..7fa5cb376 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/me.js @@ -0,0 +1,17 @@ +/** + * Montenegrin translation for bootstrap-datepicker + * Miodrag Nikač + */ +export default { + me: { + days: ["Nedjelja","Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"], + daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danas", + weekStart: 1, + clear: "Izbriši", + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/mk.js b/src/ui/static/js/datepicker/i18n/locales/mk.js new file mode 100644 index 000000000..7debd94fd --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/mk.js @@ -0,0 +1,15 @@ +/** + * Macedonian translation for bootstrap-datepicker + * Marko Aleksic + */ +export default { + mk: { + days: ["Недела", "Понеделник", "Вторник", "Среда", "Четврток", "Петок", "Сабота"], + daysShort: ["Нед", "Пон", "Вто", "Сре", "Чет", "Пет", "Саб"], + daysMin: ["Не", "По", "Вт", "Ср", "Че", "Пе", "Са"], + months: ["Јануари", "Февруари", "Март", "Април", "Мај", "Јуни", "Јули", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Јан", "Фев", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "Денес", + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/mn.js b/src/ui/static/js/datepicker/i18n/locales/mn.js new file mode 100644 index 000000000..6bd14dbe7 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/mn.js @@ -0,0 +1,17 @@ +/** + * Mongolian translation for bootstrap-datepicker + * Andrey Torsunov + */ +export default { + mn: { + days: ["Ням", "Даваа", "Мягмар", "Лхагва", "Пүрэв", "Баасан", "Бямба"], + daysShort: ["Ням", "Дав", "Мяг", "Лха", "Пүр", "Баа", "Бям"], + daysMin: ["Ня", "Да", "Мя", "Лх", "Пү", "Ба", "Бя"], + months: ["Хулгана", "Үхэр", "Бар", "Туулай", "Луу", "Могой", "Морь", "Хонь", "Бич", "Тахиа", "Нохой", "Гахай"], + monthsShort: ["Хул", "Үхэ", "Бар", "Туу", "Луу", "Мог", "Мор", "Хон", "Бич", "Тах", "Нох", "Гах"], + today: "Өнөөдөр", + clear: "Тодорхой", + format: "yyyy.mm.dd", + weekStart: 1 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/mr.js b/src/ui/static/js/datepicker/i18n/locales/mr.js new file mode 100644 index 000000000..3f29a0266 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/mr.js @@ -0,0 +1,18 @@ +/** + * Marathi translation for bootstrap-datepicker + * Sushant Pimple + */ +export default { + mr: { + days: ["रविवार", "सोमवार", "मंगळवार", "बुधवार", "गुरुवार", "शुक्रवार", "शनिवार"], + daysShort: ["रवि", "सोम", "मंगळ", "बुध", "गुरु", "शुक्र", "शनि"], + daysMin: ["र", "सो", "मं", "बु", "गु", "शु", "श"], + months: ["जानेवारी", "फेब्रुवारी", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टेंबर", "ऑक्टोबर", "नोव्हेंबर", "डिसेंबर"], + monthsShort: ["जाने.", "फेब्रु.", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टें.", "ऑक्टो.", "नोव्हें.", "डिसें."], + today: "आज", + monthsTitle: "महीने", + clear: "हटवा", + weekStart: 1, + format: "dd / mm / yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ms.js b/src/ui/static/js/datepicker/i18n/locales/ms.js new file mode 100644 index 000000000..66a947ffd --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ms.js @@ -0,0 +1,15 @@ +/** + * Malay translation for bootstrap-datepicker + * Ateman Faiz + */ +export default { + ms: { + days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu"], + daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab"], + daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa"], + months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], + today: "Hari Ini", + clear: "Bersihkan" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/nl-BE.js b/src/ui/static/js/datepicker/i18n/locales/nl-BE.js new file mode 100644 index 000000000..b4a5c878b --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/nl-BE.js @@ -0,0 +1,18 @@ +/** + * Belgium-Dutch translation for bootstrap-datepicker + * Julien Poulin + */ +export default { + 'nl-BE': { + days: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"], + daysShort: ["zo", "ma", "di", "wo", "do", "vr", "za"], + daysMin: ["zo", "ma", "di", "wo", "do", "vr", "za"], + months: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"], + monthsShort: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"], + today: "Vandaag", + monthsTitle: "Maanden", + clear: "Leegmaken", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/nl.js b/src/ui/static/js/datepicker/i18n/locales/nl.js new file mode 100644 index 000000000..365dc21b3 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/nl.js @@ -0,0 +1,18 @@ +/** + * Dutch translation for bootstrap-datepicker + * Reinier Goltstein + */ +export default { + nl: { + days: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"], + daysShort: ["zo", "ma", "di", "wo", "do", "vr", "za"], + daysMin: ["zo", "ma", "di", "wo", "do", "vr", "za"], + months: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"], + monthsShort: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"], + today: "Vandaag", + monthsTitle: "Maanden", + clear: "Wissen", + weekStart: 1, + format: "dd-mm-yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/no.js b/src/ui/static/js/datepicker/i18n/locales/no.js new file mode 100644 index 000000000..aa54b82c4 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/no.js @@ -0,0 +1,18 @@ +/** + * Norwegian translation for bootstrap-datepicker + * George Gooding + */ +export default { + no: { + days: ['søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag'], + daysShort: ['søn', 'man', 'tir', 'ons', 'tor', 'fre', 'lør'], + daysMin: ['sø', 'ma', 'ti', 'on', 'to', 'fr', 'lø'], + months: ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'], + monthsShort: ['jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'], + today: 'i dag', + monthsTitle: 'Måneder', + clear: 'Nullstill', + weekStart: 1, + format: 'dd.mm.yyyy' + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/oc.js b/src/ui/static/js/datepicker/i18n/locales/oc.js new file mode 100644 index 000000000..b04e9f00c --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/oc.js @@ -0,0 +1,17 @@ +/** + * Occitan translation for bootstrap-datepicker + */ +export default { + oc: { + days: ["Dimenge", "Diluns", "Dimars", "Dimècres", "Dijòus", "Divendres", "Dissabte"], + daysShort: ["Dim", "Dil", "Dmr", "Dmc", "Dij", "Div", "Dis"], + daysMin: ["dg", "dl", "dr", "dc", "dj", "dv", "ds"], + months: ["Genièr", "Febrièr", "Març", "Abrial", "Mai", "Junh", "Julhet", "Agost", "Setembre", "Octobre", "Novembre", "Decembre"], + monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Dec"], + today: "Uèi", + monthsTitle: "Meses", + clear: "Escafar", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/pl.js b/src/ui/static/js/datepicker/i18n/locales/pl.js new file mode 100644 index 000000000..62b8ede6c --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/pl.js @@ -0,0 +1,17 @@ +/** + * Polish translation for bootstrap-datepicker + * Robert + */ +export default { + pl: { + days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"], + daysShort: ["Niedz.", "Pon.", "Wt.", "Śr.", "Czw.", "Piąt.", "Sob."], + daysMin: ["Ndz.", "Pn.", "Wt.", "Śr.", "Czw.", "Pt.", "Sob."], + months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], + monthsShort: ["Sty.", "Lut.", "Mar.", "Kwi.", "Maj", "Cze.", "Lip.", "Sie.", "Wrz.", "Paź.", "Lis.", "Gru."], + today: "Dzisiaj", + weekStart: 1, + clear: "Wyczyść", + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/pt-BR.js b/src/ui/static/js/datepicker/i18n/locales/pt-BR.js new file mode 100644 index 000000000..051c03119 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/pt-BR.js @@ -0,0 +1,17 @@ +/** + * Brazilian translation for bootstrap-datepicker + * Cauan Cabral + */ +export default { + 'pt-BR': { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje", + monthsTitle: "Meses", + clear: "Limpar", + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/pt.js b/src/ui/static/js/datepicker/i18n/locales/pt.js new file mode 100644 index 000000000..baaa6ea7c --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/pt.js @@ -0,0 +1,18 @@ +/** + * Portuguese translation for bootstrap-datepicker + * Original code: Cauan Cabral + * Tiago Melo + */ +export default { + pt: { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje", + monthsTitle: "Meses", + clear: "Limpar", + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ro.js b/src/ui/static/js/datepicker/i18n/locales/ro.js new file mode 100644 index 000000000..1039334c8 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ro.js @@ -0,0 +1,17 @@ +/** + * Romanian translation for bootstrap-datepicker + * Cristian Vasile + */ +export default { + ro: { + days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă"], + daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm"], + daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ"], + months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], + monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Astăzi", + clear: "Șterge", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ru.js b/src/ui/static/js/datepicker/i18n/locales/ru.js new file mode 100644 index 000000000..b1e866ede --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ru.js @@ -0,0 +1,18 @@ +/** + * Russian translation for bootstrap-datepicker + * Victor Taranenko + */ +export default { + ru: { + days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"], + daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб"], + daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], + months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], + monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], + today: "Сегодня", + clear: "Очистить", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Месяцы' + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/si.js b/src/ui/static/js/datepicker/i18n/locales/si.js new file mode 100644 index 000000000..a09d0dfaa --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/si.js @@ -0,0 +1,18 @@ +/** + * Sinhala translation for bootstrap-datepicker + * Chanaka Fernando + */ +export default { + si: { + days: ["ඉරිදා", "සඳුදා", "අඟහරුවාදා", "බදාදා", "බ්‍රහස්පතින්දා", "සිකුරාදා", "සෙනසුරාදා"], + daysShort: ["ඉරි", "සඳු", "අඟ", "බදා", "බ්‍රහ", "සිකු", "සෙන"], + daysMin: ["ඉ", "ස", "අ", "බ", "බ්‍ර", "සි", "සෙ"], + months: ["ජනවාරි", "පෙබරවාරි", "මාර්තු", "අප්‍රේල්", "මැයි", "ජුනි", "ජූලි", "අගෝස්තු", "සැප්තැම්බර්", "ඔක්තෝබර්", "නොවැම්බර්", "දෙසැම්බර්"], + monthsShort: ["ජන", "පෙබ", "මාර්", "අප්‍රේ", "මැයි", "ජුනි", "ජූලි", "අගෝ", "සැප්", "ඔක්", "නොවැ", "දෙසැ"], + today: "අද", + monthsTitle: "මාස", + clear: "මකන්න", + weekStart: 0, + format: "yyyy-mm-dd" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/sk.js b/src/ui/static/js/datepicker/i18n/locales/sk.js new file mode 100644 index 000000000..9c4a70d4c --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/sk.js @@ -0,0 +1,18 @@ +/** + * Slovak translation for bootstrap-datepicker + * Marek Lichtner + * Fixes by Michal Remiš + */ +export default { + sk: { + days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"], + daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob"], + daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pia", "So"], + months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Dnes", + clear: "Vymazať", + weekStart: 1, + format: "d.m.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/sl.js b/src/ui/static/js/datepicker/i18n/locales/sl.js new file mode 100644 index 000000000..87acf5a62 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/sl.js @@ -0,0 +1,15 @@ +/** + * Slovene translation for bootstrap-datepicker + * Gregor Rudolf + */ +export default { + sl: { + days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota"], + daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob"], + daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So"], + months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danes", + weekStart: 1 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/sq.js b/src/ui/static/js/datepicker/i18n/locales/sq.js new file mode 100644 index 000000000..be94a7643 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/sq.js @@ -0,0 +1,18 @@ +/** + * Albanian translation for bootstrap-datepicker + * Tomor Pupovci + */ +export default { + sq: { + days: ["E Diel", "E Hënë", "E Martē", "E Mërkurë", "E Enjte", "E Premte", "E Shtunë"], + daysShort: ["Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Shtu"], + daysMin: ["Di", "Hë", "Ma", "Më", "En", "Pr", "Sht"], + months: ["Janar", "Shkurt", "Mars", "Prill", "Maj", "Qershor", "Korrik", "Gusht", "Shtator", "Tetor", "Nëntor", "Dhjetor"], + monthsShort: ["Jan", "Shk", "Mar", "Pri", "Maj", "Qer", "Korr", "Gu", "Sht", "Tet", "Nën", "Dhjet"], + monthsTitle: "Muaj", + today: "Sot", + weekStart: 1, + format: "dd/mm/yyyy", + clear: "Pastro" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/sr-latn.js b/src/ui/static/js/datepicker/i18n/locales/sr-latn.js new file mode 100644 index 000000000..a84b45196 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/sr-latn.js @@ -0,0 +1,16 @@ +/** + * Serbian latin translation for bootstrap-datepicker + * Bojan Milosavlević + */ +export default { + 'sr-latn': { + days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub"], + daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danas", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/sr.js b/src/ui/static/js/datepicker/i18n/locales/sr.js new file mode 100644 index 000000000..2a2ae0a05 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/sr.js @@ -0,0 +1,16 @@ +/** + * Serbian cyrillic translation for bootstrap-datepicker + * Bojan Milosavlević + */ +export default { + sr: { + days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота"], + daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб"], + daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су"], + months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], + monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], + today: "Данас", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/sv.js b/src/ui/static/js/datepicker/i18n/locales/sv.js new file mode 100644 index 000000000..2323d4363 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/sv.js @@ -0,0 +1,17 @@ +/** + * Swedish translation for bootstrap-datepicker + * Patrik Ragnarsson + */ +export default { + sv: { + days: ["söndag", "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag"], + daysShort: ["sön", "mån", "tis", "ons", "tor", "fre", "lör"], + daysMin: ["sö", "må", "ti", "on", "to", "fr", "lö"], + months: ["januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"], + monthsShort: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"], + today: "Idag", + format: "yyyy-mm-dd", + weekStart: 1, + clear: "Rensa" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/sw.js b/src/ui/static/js/datepicker/i18n/locales/sw.js new file mode 100644 index 000000000..61ce0add2 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/sw.js @@ -0,0 +1,15 @@ +/** + * Swahili translation for bootstrap-datepicker + * Edwin Mugendi + * Source: http: //scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku + */ +export default { + sw: { + days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi"], + daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1"], + daysMin: ["2", "3", "4", "5", "A", "I", "1"], + months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], + monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], + today: "Leo" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/ta.js b/src/ui/static/js/datepicker/i18n/locales/ta.js new file mode 100644 index 000000000..3a7ed92b1 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/ta.js @@ -0,0 +1,18 @@ +/** + * Tamil translation for bootstrap-datepicker + * Abubacker Siddik A + */ +export default { + ta: { + days: ["ஞாயிறு", "திங்கள்", "செவ்வாய்", "புதன்", "வியாழன்", "வெள்ளி", "சனி"], + daysShort: ["ஞாயி", "திங்", "செவ்", "புத", "வியா", "வெள்", "சனி"], + daysMin: ["ஞா", "தி", "செ", "பு", "வி", "வெ", "ச"], + months: ["ஜனவரி", "பிப்ரவரி", "மார்ச்", "ஏப்ரல்", "மே", "ஜூன்", "ஜூலை", "ஆகஸ்டு", "செப்டம்பர்", "அக்டோபர்", "நவம்பர்", "டிசம்பர்"], + monthsShort: ["ஜன", "பிப்", "மார்", "ஏப்", "மே", "ஜூன்", "ஜூலை", "ஆக", "செப்", "அக்", "நவ", "டிச"], + today: "இன்று", + monthsTitle: "மாதங்கள்", + clear: "நீக்கு", + weekStart: 1, + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/tg.js b/src/ui/static/js/datepicker/i18n/locales/tg.js new file mode 100644 index 000000000..b389e6b3f --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/tg.js @@ -0,0 +1,19 @@ +/** + * Tajik (cyrillic) translation for bootstrap-datepicker + * Bakhtiyor Bahritidinov + * Orif N. Jr. + */ +export default { + tg: { + days: ["Якшанбе", "Душанбе", "Сешанбе", "Чоршанбе", "Панҷшанбе", "Ҷумъа", "Шанбе"], + daysShort: ["Яшб", "Дшб", "Сшб", "Чшб", "Пшб", "Ҷум", "Шнб"], + daysMin: ["Яш", "Дш", "Сш", "Чш", "Пш", "Ҷм", "Шб"], + months: ["Январ", "Феврал", "Март", "Апрел", "Май", "Июн", "Июл", "Август", "Сентябр", "Октябр", "Ноябр", "Декабр"], + monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], + today: "Имрӯз", + monthsTitle: "Моҳҳо", + clear: "Тоза намудан", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/th.js b/src/ui/static/js/datepicker/i18n/locales/th.js new file mode 100644 index 000000000..cbfa391e7 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/th.js @@ -0,0 +1,14 @@ +/** + * Thai translation for bootstrap-datepicker + * Suchau Jiraprapot + */ +export default { + th: { + days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], + daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], + monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], + today: "วันนี้" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/tk.js b/src/ui/static/js/datepicker/i18n/locales/tk.js new file mode 100644 index 000000000..0705b1ccd --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/tk.js @@ -0,0 +1,18 @@ +/** + * Turkmen translation for bootstrap-datepicker + * N'Bayramberdiyev + */ +export default { + tk: { + days: ["Ýekşenbe", "Duşenbe", "Sişenbe", "Çarşenbe", "Penşenbe", "Anna", "Şenbe"], + daysShort: ["Ýek", "Duş", "Siş", "Çar", "Pen", "Ann", "Şen"], + daysMin: ["Ýe", "Du", "Si", "Ça", "Pe", "An", "Şe"], + months: ["Ýanwar", "Fewral", "Mart", "Aprel", "Maý", "Iýun", "Iýul", "Awgust", "Sentýabr", "Oktýabr", "Noýabr", "Dekabr"], + monthsShort: ["Ýan", "Few", "Mar", "Apr", "Maý", "Iýn", "Iýl", "Awg", "Sen", "Okt", "Noý", "Dek"], + today: "Bu gün", + monthsTitle: "Aýlar", + clear: "Aýyr", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/tr.js b/src/ui/static/js/datepicker/i18n/locales/tr.js new file mode 100644 index 000000000..0f8390e10 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/tr.js @@ -0,0 +1,17 @@ +/** + * Turkish translation for bootstrap-datepicker + * Serkan Algur + */ +export default { + tr: { + days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"], + daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts"], + daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct"], + months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], + monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], + today: "Bugün", + clear: "Temizle", + weekStart: 1, + format: "dd.mm.yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/uk.js b/src/ui/static/js/datepicker/i18n/locales/uk.js new file mode 100644 index 000000000..fe5ae79d1 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/uk.js @@ -0,0 +1,17 @@ +/** + * Ukrainian translation for bootstrap-datepicker + * Igor Polynets + */ +export default { + uk: { + days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота"], + daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб"], + daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], + months: ["Cічень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], + monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], + today: "Сьогодні", + clear: "Очистити", + format: "dd.mm.yyyy", + weekStart: 1 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/uz-cyrl.js b/src/ui/static/js/datepicker/i18n/locales/uz-cyrl.js new file mode 100644 index 000000000..b5a7cac58 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/uz-cyrl.js @@ -0,0 +1,18 @@ +/** + * Uzbek cyrillic translation for bootstrap-datepicker + * Kakhramonov Javlonbek + */ +export default { + 'uz-cyrl': { + days: ["Якшанба", "Душанба", "Сешанба", "Чоршанба", "Пайшанба", "Жума", "Шанба"], + daysShort: ["Якш", "Ду", "Се", "Чор", "Пай", "Жу", "Ша"], + daysMin: ["Як", "Ду", "Се", "Чо", "Па", "Жу", "Ша"], + months: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"], + monthsShort: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"], + today: "Бугун", + clear: "Ўчириш", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Ойлар' + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/uz-latn.js b/src/ui/static/js/datepicker/i18n/locales/uz-latn.js new file mode 100644 index 000000000..9b689dbe2 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/uz-latn.js @@ -0,0 +1,18 @@ +/** + * Uzbek latin translation for bootstrap-datepicker + * Kakhramonov Javlonbek + */ +export default { + 'uz-latn': { + days: ["Yakshanba", "Dushanba", "Seshanba", "Chorshanba", "Payshanba", "Juma", "Shanba"], + daysShort: ["Yak", "Du", "Se", "Chor", "Pay", "Ju", "Sha"], + daysMin: ["Ya", "Du", "Se", "Cho", "Pa", "Ju", "Sha"], + months: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "Iyun", "Iyul", "Avgust", "Sentabr", "Oktabr", "Noyabr", "Dekabr"], + monthsShort: ["Yan", "Fev", "Mar", "Apr", "May", "Iyn", "Iyl", "Avg", "Sen", "Okt", "Noy", "Dek"], + today: "Bugun", + clear: "O'chirish", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Oylar' + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/vi.js b/src/ui/static/js/datepicker/i18n/locales/vi.js new file mode 100644 index 000000000..ffb8da93d --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/vi.js @@ -0,0 +1,16 @@ +/** + * Vietnamese translation for bootstrap-datepicker + * An Vo + */ +export default { + vi: { + days: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy"], + daysShort: ["CN", "Thứ 2", "Thứ 3", "Thứ 4", "Thứ 5", "Thứ 6", "Thứ 7"], + daysMin: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"], + months: ["Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"], + monthsShort: ["Th1", "Th2", "Th3", "Th4", "Th5", "Th6", "Th7", "Th8", "Th9", "Th10", "Th11", "Th12"], + today: "Hôm nay", + clear: "Xóa", + format: "dd/mm/yyyy" + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/zh-CN.js b/src/ui/static/js/datepicker/i18n/locales/zh-CN.js new file mode 100644 index 000000000..4aadcd14b --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/zh-CN.js @@ -0,0 +1,19 @@ +/** + * Simplified Chinese translation for bootstrap-datepicker + * Yuan Cheung + */ +export default { + 'zh-CN': { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], + daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], + daysMin: ["日", "一", "二", "三", "四", "五", "六"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今天", + monthsTitle: "选择月份", + clear: "清除", + format: "yyyy-mm-dd", + titleFormat: "y年mm月", + weekStart: 1 + } +}; diff --git a/src/ui/static/js/datepicker/i18n/locales/zh-TW.js b/src/ui/static/js/datepicker/i18n/locales/zh-TW.js new file mode 100644 index 000000000..762334b16 --- /dev/null +++ b/src/ui/static/js/datepicker/i18n/locales/zh-TW.js @@ -0,0 +1,20 @@ +/** + * Traditional Chinese translation for bootstrap-datepicker + * Rung-Sheng Jang + * FrankWu Fix more appropriate use of Traditional Chinese habit + */ +export default { + 'zh-TW': { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], + daysShort: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"], + daysMin: ["日", "一", "二", "三", "四", "五", "六"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今天", + monthsTitle: "月份", + format: "yyyy/mm/dd", + weekStart: 0, + titleFormat: "y年mm月", + clear: "清除" + } +}; diff --git a/src/ui/static/js/datepicker/lib/date-format.js b/src/ui/static/js/datepicker/lib/date-format.js new file mode 100644 index 000000000..09ef250be --- /dev/null +++ b/src/ui/static/js/datepicker/lib/date-format.js @@ -0,0 +1,185 @@ +import {stripTime, today} from './date.js'; +import {lastItemOf} from './utils.js'; + +// pattern for format parts +export const reFormatTokens = /dd?|DD?|mm?|MM?|yy?(?:yy)?/; +// pattern for non date parts +export const reNonDateParts = /[\s!-/:-@[-`{-~年月日]+/; +// cache for persed formats +let knownFormats = {}; +// parse funtions for date parts +const parseFns = { + y(date, year) { + return new Date(date).setFullYear(parseInt(year, 10)); + }, + m(date, month, locale) { + const newDate = new Date(date); + let monthIndex = parseInt(month, 10) - 1; + + if (isNaN(monthIndex)) { + if (!month) { + return NaN; + } + + const monthName = month.toLowerCase(); + const compareNames = name => name.toLowerCase().startsWith(monthName); + // compare with both short and full names because some locales have periods + // in the short names (not equal to the first X letters of the full names) + monthIndex = locale.monthsShort.findIndex(compareNames); + if (monthIndex < 0) { + monthIndex = locale.months.findIndex(compareNames); + } + if (monthIndex < 0) { + return NaN; + } + } + + newDate.setMonth(monthIndex); + return newDate.getMonth() !== normalizeMonth(monthIndex) + ? newDate.setDate(0) + : newDate.getTime(); + }, + d(date, day) { + return new Date(date).setDate(parseInt(day, 10)); + }, +}; +// format functions for date parts +const formatFns = { + d(date) { + return date.getDate(); + }, + dd(date) { + return padZero(date.getDate(), 2); + }, + D(date, locale) { + return locale.daysShort[date.getDay()]; + }, + DD(date, locale) { + return locale.days[date.getDay()]; + }, + m(date) { + return date.getMonth() + 1; + }, + mm(date) { + return padZero(date.getMonth() + 1, 2); + }, + M(date, locale) { + return locale.monthsShort[date.getMonth()]; + }, + MM(date, locale) { + return locale.months[date.getMonth()]; + }, + y(date) { + return date.getFullYear(); + }, + yy(date) { + return padZero(date.getFullYear(), 2).slice(-2); + }, + yyyy(date) { + return padZero(date.getFullYear(), 4); + }, +}; + +// get month index in normal range (0 - 11) from any number +function normalizeMonth(monthIndex) { + return monthIndex > -1 ? monthIndex % 12 : normalizeMonth(monthIndex + 12); +} + +function padZero(num, length) { + return num.toString().padStart(length, '0'); +} + +function parseFormatString(format) { + if (typeof format !== 'string') { + throw new Error("Invalid date format."); + } + if (format in knownFormats) { + return knownFormats[format]; + } + + // sprit the format string into parts and seprators + const separators = format.split(reFormatTokens); + const parts = format.match(new RegExp(reFormatTokens, 'g')); + if (separators.length === 0 || !parts) { + throw new Error("Invalid date format."); + } + + // collect format functions used in the format + const partFormatters = parts.map(token => formatFns[token]); + + // collect parse function keys used in the format + // iterate over parseFns' keys in order to keep the order of the keys. + const partParserKeys = Object.keys(parseFns).reduce((keys, key) => { + const token = parts.find(part => part[0] !== 'D' && part[0].toLowerCase() === key); + if (token) { + keys.push(key); + } + return keys; + }, []); + + return knownFormats[format] = { + parser(dateStr, locale) { + const dateParts = dateStr.split(reNonDateParts).reduce((dtParts, part, index) => { + if (part.length > 0 && parts[index]) { + const token = parts[index][0]; + if (token === 'M') { + dtParts.m = part; + } else if (token !== 'D') { + dtParts[token] = part; + } + } + return dtParts; + }, {}); + + // iterate over partParserkeys so that the parsing is made in the oder + // of year, month and day to prevent the day parser from correcting last + // day of month wrongly + return partParserKeys.reduce((origDate, key) => { + const newDate = parseFns[key](origDate, dateParts[key], locale); + // ingnore the part failed to parse + return isNaN(newDate) ? origDate : newDate; + }, today()); + }, + formatter(date, locale) { + let dateStr = partFormatters.reduce((str, fn, index) => { + return str += `${separators[index]}${fn(date, locale)}`; + }, ''); + // separators' length is always parts' length + 1, + return dateStr += lastItemOf(separators); + }, + }; +} + +export function parseDate(dateStr, format, locale) { + if (dateStr instanceof Date || typeof dateStr === 'number') { + const date = stripTime(dateStr); + return isNaN(date) ? undefined : date; + } + if (!dateStr) { + return undefined; + } + if (dateStr === 'today') { + return today(); + } + + if (format && format.toValue) { + const date = format.toValue(dateStr, format, locale); + return isNaN(date) ? undefined : stripTime(date); + } + + return parseFormatString(format).parser(dateStr, locale); +} + +export function formatDate(date, format, locale) { + if (isNaN(date) || (!date && date !== 0)) { + return ''; + } + + const dateObj = typeof date === 'number' ? new Date(date) : date; + + if (format.toDisplay) { + return format.toDisplay(dateObj, format, locale); + } + + return parseFormatString(format).formatter(dateObj, locale); +} diff --git a/src/ui/static/js/datepicker/lib/date.js b/src/ui/static/js/datepicker/lib/date.js new file mode 100644 index 000000000..4282901c2 --- /dev/null +++ b/src/ui/static/js/datepicker/lib/date.js @@ -0,0 +1,100 @@ +export function stripTime(timeValue) { + return new Date(timeValue).setHours(0, 0, 0, 0); +} + +export function today() { + return new Date().setHours(0, 0, 0, 0); +} + +// Get the time value of the start of given date or year, month and day +export function dateValue(...args) { + switch (args.length) { + case 0: + return today(); + case 1: + return stripTime(args[0]); + } + + // use setFullYear() to keep 2-digit year from being mapped to 1900-1999 + const newDate = new Date(0); + newDate.setFullYear(...args); + return newDate.setHours(0, 0, 0, 0); +} + +export function addDays(date, amount) { + const newDate = new Date(date); + return newDate.setDate(newDate.getDate() + amount); +} + +export function addWeeks(date, amount) { + return addDays(date, amount * 7); +} + +export function addMonths(date, amount) { + // If the day of the date is not in the new month, the last day of the new + // month will be returned. e.g. Jan 31 + 1 month → Feb 28 (not Mar 03) + const newDate = new Date(date); + const monthsToSet = newDate.getMonth() + amount; + let expectedMonth = monthsToSet % 12; + if (expectedMonth < 0) { + expectedMonth += 12; + } + + const time = newDate.setMonth(monthsToSet); + return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time; +} + +export function addYears(date, amount) { + // If the date is Feb 29 and the new year is not a leap year, Feb 28 of the + // new year will be returned. + const newDate = new Date(date); + const expectedMonth = newDate.getMonth(); + const time = newDate.setFullYear(newDate.getFullYear() + amount); + return expectedMonth === 1 && newDate.getMonth() === 2 ? newDate.setDate(0) : time; +} + +// Calculate the distance bettwen 2 days of the week +function dayDiff(day, from) { + return (day - from + 7) % 7; +} + +// Get the date of the specified day of the week of given base date +export function dayOfTheWeekOf(baseDate, dayOfWeek, weekStart = 0) { + const baseDay = new Date(baseDate).getDay(); + return addDays(baseDate, dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart)); +} + +// Get the ISO week of a date +export function getWeek(date) { + // start of ISO week is Monday + const thuOfTheWeek = dayOfTheWeekOf(date, 4, 1); + // 1st week == the week where the 4th of January is in + const firstThu = dayOfTheWeekOf(new Date(thuOfTheWeek).setMonth(0, 4), 4, 1); + return Math.round((thuOfTheWeek - firstThu) / 604800000) + 1; +} + +// Get the start year of the period of years that includes given date +// years: length of the year period +export function startOfYearPeriod(date, years) { + /* @see https://en.wikipedia.org/wiki/Year_zero#ISO_8601 */ + const year = new Date(date).getFullYear(); + return Math.floor(year / years) * years; +} + +// Convert date to the first/last date of the month/year of the date +export function regularizeDate(date, timeSpan, useLastDate) { + if (timeSpan !== 1 && timeSpan !== 2) { + return date; + } + const newDate = new Date(date); + if (timeSpan === 1) { + useLastDate + ? newDate.setMonth(newDate.getMonth() + 1, 0) + : newDate.setDate(1); + } else { + useLastDate + ? newDate.setFullYear(newDate.getFullYear() + 1, 0, 0) + : newDate.setMonth(0, 1); + } + return newDate.setHours(0, 0, 0, 0); +} diff --git a/src/ui/static/js/datepicker/lib/dom.js b/src/ui/static/js/datepicker/lib/dom.js new file mode 100644 index 000000000..c32fe7515 --- /dev/null +++ b/src/ui/static/js/datepicker/lib/dom.js @@ -0,0 +1,63 @@ +const range = document.createRange(); + +export function parseHTML(html) { + return range.createContextualFragment(html); +} + +export function getParent(el) { + return el.parentElement + || (el.parentNode instanceof ShadowRoot ? el.parentNode.host : undefined); +} + +export function isActiveElement(el) { + return el.getRootNode().activeElement === el; +} + +// equivalent to jQuery's :visble +export function isVisible(el) { + return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); +} + +export function hideElement(el) { + if (el.style.display === 'none') { + return; + } + // back up the existing display setting in data-style-display + if (el.style.display) { + el.dataset.styleDisplay = el.style.display; + } + el.style.display = 'none'; +} + +export function showElement(el) { + if (el.style.display !== 'none') { + return; + } + if (el.dataset.styleDisplay) { + // restore backed-up dispay property + el.style.display = el.dataset.styleDisplay; + delete el.dataset.styleDisplay; + } else { + el.style.display = ''; + } +} + +export function emptyChildNodes(el) { + if (el.firstChild) { + el.removeChild(el.firstChild); + emptyChildNodes(el); + } +} + +export function replaceChildNodes(el, newChildNodes) { + emptyChildNodes(el); + if (newChildNodes instanceof DocumentFragment) { + el.appendChild(newChildNodes); + } else if (typeof newChildNodes === 'string') { + el.appendChild(parseHTML(newChildNodes)); + } else if (typeof newChildNodes.forEach === 'function') { + newChildNodes.forEach((node) => { + el.appendChild(node); + }); + } +} diff --git a/src/ui/static/js/datepicker/lib/event.js b/src/ui/static/js/datepicker/lib/event.js new file mode 100644 index 000000000..e2922644a --- /dev/null +++ b/src/ui/static/js/datepicker/lib/event.js @@ -0,0 +1,71 @@ +const listenerRegistry = new WeakMap(); +const {addEventListener, removeEventListener} = EventTarget.prototype; + +// Register event listeners to a key object +// listeners: array of listener definitions; +// - each definition must be a flat array of event target and the arguments +// used to call addEventListener() on the target +export function registerListeners(keyObj, listeners) { + let registered = listenerRegistry.get(keyObj); + if (!registered) { + registered = []; + listenerRegistry.set(keyObj, registered); + } + listeners.forEach((listener) => { + addEventListener.call(...listener); + registered.push(listener); + }); +} + +export function unregisterListeners(keyObj) { + let listeners = listenerRegistry.get(keyObj); + if (!listeners) { + return; + } + listeners.forEach((listener) => { + removeEventListener.call(...listener); + }); + listenerRegistry.delete(keyObj); +} + +// Event.composedPath() polyfill for Edge +// based on https://gist.github.com/kleinfreund/e9787d73776c0e3750dcfcdc89f100ec +if (!Event.prototype.composedPath) { + const getComposedPath = (node, path = []) => { + path.push(node); + + let parent; + if (node.parentNode) { + parent = node.parentNode; + } else if (node.host) { // ShadowRoot + parent = node.host; + } else if (node.defaultView) { // Document + parent = node.defaultView; + } + return parent ? getComposedPath(parent, path) : path; + }; + + Event.prototype.composedPath = function () { + return getComposedPath(this.target); + }; +} + +function findFromPath(path, criteria, currentTarget) { + const [node, ...rest] = path; + if (criteria(node)) { + return node; + } + if (node === currentTarget || node.tagName === 'HTML' || rest.length === 0) { + // stop when reaching currentTarget or + return; + } + return findFromPath(rest, criteria, currentTarget); +} + +// Search for the actual target of a delegated event +export function findElementInEventPath(ev, selector) { + const criteria = typeof selector === 'function' + ? selector + : el => el instanceof Element && el.matches(selector); + return findFromPath(ev.composedPath(), criteria, ev.currentTarget); +} diff --git a/src/ui/static/js/datepicker/lib/utils.js b/src/ui/static/js/datepicker/lib/utils.js new file mode 100644 index 000000000..5ad8a796c --- /dev/null +++ b/src/ui/static/js/datepicker/lib/utils.js @@ -0,0 +1,61 @@ +export function hasProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +export function lastItemOf(arr) { + return arr[arr.length - 1]; +} + +// push only the items not included in the array +export function pushUnique(arr, ...items) { + items.forEach((item) => { + if (arr.includes(item)) { + return; + } + arr.push(item); + }); + return arr; +} + +export function stringToArray(str, separator) { + // convert empty string to an empty array + return str ? str.split(separator) : []; +} + +export function isInRange(testVal, min, max) { + const minOK = min === undefined || testVal >= min; + const maxOK = max === undefined || testVal <= max; + return minOK && maxOK; +} + +export function limitToRange(val, min, max) { + if (val < min) { + return min; + } + if (val > max) { + return max; + } + return val; +} + +export function createTagRepeat(tagName, repeat, attributes = {}, index = 0, html = '') { + const openTagSrc = Object.keys(attributes).reduce((src, attr) => { + let val = attributes[attr]; + if (typeof val === 'function') { + val = val(index); + } + return `${src} ${attr}="${val}"`; + }, tagName); + html += `<${openTagSrc}>`; + + const next = index + 1; + return next < repeat + ? createTagRepeat(tagName, repeat, attributes, next, html) + : html; +} + +// Remove the spacing surrounding tags for HTML parser not to create text nodes +// before/after elements +export function optimizeTemplateHTML(html) { + return html.replace(/>\s+/g, '>').replace(/\s+ + */ +(function () { + Datepicker.locales['ar-DZ'] = { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], + months: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + monthsShort: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + today: "هذا اليوم", + rtl: true, + monthsTitle: "أشهر", + clear: "إزالة", + format: "yyyy/mm/dd", + weekStart: 0 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ar-tn.js b/src/ui/static/js/datepicker/locales/ar-tn.js new file mode 100644 index 000000000..d94df17a9 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ar-tn.js @@ -0,0 +1,15 @@ +/** + * Arabic-Tunisia translation for bootstrap-datepicker + * Souhaieb Besbes + */ +(function () { + Datepicker.locales['ar-tn'] = { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], + months: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + monthsShort: ["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويليه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"], + today: "هذا اليوم", + rtl: true + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ar.js b/src/ui/static/js/datepicker/locales/ar.js new file mode 100644 index 000000000..608fe0d3e --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ar.js @@ -0,0 +1,15 @@ +/** + * Arabic translation for bootstrap-datepicker + * Mohammed Alshehri + */ +(function () { + Datepicker.locales.ar = { + days: ["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت", "الأحد"], + daysShort: ["أحد", "اثنين", "ثلاثاء", "أربعاء", "خميس", "جمعة", "سبت", "أحد"], + daysMin: ["ح", "ن", "ث", "ع", "خ", "ج", "س", "ح"], + months: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + monthsShort: ["يناير", "فبراير", "مارس", "أبريل", "مايو", "يونيو", "يوليو", "أغسطس", "سبتمبر", "أكتوبر", "نوفمبر", "ديسمبر"], + today: "هذا اليوم", + rtl: true + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/az.js b/src/ui/static/js/datepicker/locales/az.js new file mode 100644 index 000000000..ae3d4def8 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/az.js @@ -0,0 +1,14 @@ +// Azerbaijani +(function () { + Datepicker.locales.az = { + days: ["Bazar", "Bazar ertəsi", "Çərşənbə axşamı", "Çərşənbə", "Cümə axşamı", "Cümə", "Şənbə"], + daysShort: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş."], + daysMin: ["B.", "B.e", "Ç.a", "Ç.", "C.a", "C.", "Ş."], + months: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr"], + monthsShort: ["Yan", "Fev", "Mar", "Apr", "May", "İyun", "İyul", "Avq", "Sen", "Okt", "Noy", "Dek"], + today: "Bu gün", + weekStart: 1, + clear: "Təmizlə", + monthsTitle: 'Aylar' + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/bg.js b/src/ui/static/js/datepicker/locales/bg.js new file mode 100644 index 000000000..81d649efd --- /dev/null +++ b/src/ui/static/js/datepicker/locales/bg.js @@ -0,0 +1,14 @@ +/** + * Bulgarian translation for bootstrap-datepicker + * Apostol Apostolov + */ +(function () { + Datepicker.locales.bg = { + days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота"], + daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб"], + daysMin: ["Н", "П", "В", "С", "Ч", "П", "С"], + months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "днес" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/bm.js b/src/ui/static/js/datepicker/locales/bm.js new file mode 100644 index 000000000..57550b8fb --- /dev/null +++ b/src/ui/static/js/datepicker/locales/bm.js @@ -0,0 +1,18 @@ +/** + * Bamanankan (bm) translation for bootstrap-datepicker + * Fatou Fall + */ +(function () { + Datepicker.locales.bm = { + days: ["Kari","Ntɛnɛn","Tarata","Araba","Alamisa","Juma","Sibiri"], + daysShort: ["Kar","Ntɛ","Tar","Ara","Ala","Jum","Sib"], + daysMin: ["Ka","Nt","Ta","Ar","Al","Ju","Si"], + months: ["Zanwuyekalo","Fewuruyekalo","Marisikalo","Awirilikalo","Mɛkalo","Zuwɛnkalo","Zuluyekalo","Utikalo","Sɛtanburukalo","ɔkutɔburukalo","Nowanburukalo","Desanburukalo"], + monthsShort: ["Zan","Few","Mar","Awi","Mɛ","Zuw","Zul","Uti","Sɛt","ɔku","Now","Des"], + today: "Bi", + monthsTitle: "Kalo", + clear: "Ka jɔsi", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/bn.js b/src/ui/static/js/datepicker/locales/bn.js new file mode 100644 index 000000000..6143362af --- /dev/null +++ b/src/ui/static/js/datepicker/locales/bn.js @@ -0,0 +1,19 @@ +/** + * Bengali (Bangla) translation for bootstrap-datepicker + * Karim Khan + * Orif N. Jr. + */ +(function () { + Datepicker.locales.bn = { + days: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], + daysShort: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], + daysMin: ["রবি","সোম","মঙ্গল","বুধ","বৃহস্পতি","শুক্র","শনি"], + months: ["জানুয়ারী","ফেব্রুয়ারি","মার্চ","এপ্রিল","মে","জুন","জুলাই","অগাস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর"], + monthsShort: ["জানুয়ারী","ফেব্রুয়ারি","মার্চ","এপ্রিল","মে","জুন","জুলাই","অগাস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর"], + today: "আজ", + monthsTitle: "মাস", + clear: "পরিষ্কার", + weekStart: 0, + format: "mm/dd/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/br.js b/src/ui/static/js/datepicker/locales/br.js new file mode 100644 index 000000000..f6419a589 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/br.js @@ -0,0 +1,18 @@ +/** + * Breton translation for bootstrap-datepicker + * Gwenn Meynier + */ +(function () { + Datepicker.locales.br = { + days: ["Sul", "Lun", "Meurzh", "Merc'her", "Yaou", "Gwener", "Sadorn"], + daysShort: ["Sul", "Lun", "Meu.", "Mer.", "Yao.", "Gwe.", "Sad."], + daysMin: ["Su", "L", "Meu", "Mer", "Y", "G", "Sa"], + months: ["Genver", "C'hwevrer", "Meurzh", "Ebrel", "Mae", "Mezheven", "Gouere", "Eost", "Gwengolo", "Here", "Du", "Kerzu"], + monthsShort: ["Genv.", "C'hw.", "Meur.", "Ebre.", "Mae", "Mezh.", "Goue.", "Eost", "Gwen.", "Here", "Du", "Kerz."], + today: "Hiziv", + monthsTitle: "Miz", + clear: "Dilemel", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/bs.js b/src/ui/static/js/datepicker/locales/bs.js new file mode 100644 index 000000000..306f163d3 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/bs.js @@ -0,0 +1,15 @@ +/** + * Bosnian translation for bootstrap-datepicker + */ +(function () { + Datepicker.locales.bs = { + days: ["Nedjelja","Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"], + daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Juni", "Juli", "August", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Danas", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ca.js b/src/ui/static/js/datepicker/locales/ca.js new file mode 100644 index 000000000..20c30beac --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ca.js @@ -0,0 +1,18 @@ +/** + * Catalan translation for bootstrap-datepicker + * J. Garcia + */ +(function () { + Datepicker.locales.ca = { + days: ["diumenge", "dilluns", "dimarts", "dimecres", "dijous", "divendres", "dissabte"], + daysShort: ["dg.", "dl.", "dt.", "dc.", "dj.", "dv.", "ds."], + daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds"], + months: ["gener", "febrer", "març", "abril", "maig", "juny", "juliol", "agost", "setembre", "octubre", "novembre", "desembre"], + monthsShort: ["gen.", "febr.", "març", "abr.", "maig", "juny", "jul.", "ag.", "set.", "oct.", "nov.", "des."], + today: "Avui", + monthsTitle: "Mesos", + clear: "Esborra", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/cs.js b/src/ui/static/js/datepicker/locales/cs.js new file mode 100644 index 000000000..7531dda83 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/cs.js @@ -0,0 +1,19 @@ +/** + * Czech translation for bootstrap-datepicker + * Matěj Koubík + * Fixes by Michal Remiš + */ +(function () { + Datepicker.locales.cs = { + days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota"], + daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob"], + daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So"], + months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], + monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], + today: "Dnes", + clear: "Vymazat", + monthsTitle: "Měsíc", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/cy.js b/src/ui/static/js/datepicker/locales/cy.js new file mode 100644 index 000000000..7c609992f --- /dev/null +++ b/src/ui/static/js/datepicker/locales/cy.js @@ -0,0 +1,14 @@ +/** + * Welsh translation for bootstrap-datepicker + * S. Morris + */ +(function () { + Datepicker.locales.cy = { + days: ["Sul", "Llun", "Mawrth", "Mercher", "Iau", "Gwener", "Sadwrn"], + daysShort: ["Sul", "Llu", "Maw", "Mer", "Iau", "Gwe", "Sad"], + daysMin: ["Su", "Ll", "Ma", "Me", "Ia", "Gwe", "Sa"], + months: ["Ionawr", "Chewfror", "Mawrth", "Ebrill", "Mai", "Mehefin", "Gorfennaf", "Awst", "Medi", "Hydref", "Tachwedd", "Rhagfyr"], + monthsShort: ["Ion", "Chw", "Maw", "Ebr", "Mai", "Meh", "Gor", "Aws", "Med", "Hyd", "Tach", "Rha"], + today: "Heddiw" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/da.js b/src/ui/static/js/datepicker/locales/da.js new file mode 100644 index 000000000..fb7a18961 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/da.js @@ -0,0 +1,19 @@ +/** + * Danish translation for bootstrap-datepicker + * Christian Pedersen + * Ivan Mylyanyk + */ +(function () { + Datepicker.locales.da = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø"], + months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "I Dag", + weekStart: 1, + clear: "Nulstil", + format: "dd/mm/yyyy", + monthsTitle: "Måneder" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/de.js b/src/ui/static/js/datepicker/locales/de.js new file mode 100644 index 000000000..60c87be51 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/de.js @@ -0,0 +1,18 @@ +/** + * German translation for bootstrap-datepicker + * Sam Zurcher + */ +(function () { + Datepicker.locales.de = { + days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], + daysShort: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], + daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], + months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], + monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], + today: "Heute", + monthsTitle: "Monate", + clear: "Löschen", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/el.js b/src/ui/static/js/datepicker/locales/el.js new file mode 100644 index 000000000..a65a21dc6 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/el.js @@ -0,0 +1,16 @@ +/** + * Greek translation for bootstrap-datepicker + */ +(function () { + Datepicker.locales.el = { + days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"], + daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"], + daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα"], + months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], + monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], + today: "Σήμερα", + clear: "Καθαρισμός", + weekStart: 1, + format: "d/m/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/en-AU.js b/src/ui/static/js/datepicker/locales/en-AU.js new file mode 100644 index 000000000..6d8455619 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/en-AU.js @@ -0,0 +1,18 @@ +/** + * Australian English translation for bootstrap-datepicker + * Steve Chapman + */ +(function () { + Datepicker.locales['en-AU'] = { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "d/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/en-CA.js b/src/ui/static/js/datepicker/locales/en-CA.js new file mode 100644 index 000000000..3a35c32d2 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/en-CA.js @@ -0,0 +1,18 @@ +/** + * Canadian English translation for bootstrap-datepicker + * Mike Nacey + */ +(function () { + Datepicker.locales['en-CA'] = { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 0, + format: "yyyy-mm-dd" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/en-GB.js b/src/ui/static/js/datepicker/locales/en-GB.js new file mode 100644 index 000000000..da848f97f --- /dev/null +++ b/src/ui/static/js/datepicker/locales/en-GB.js @@ -0,0 +1,18 @@ +/** + * British English translation for bootstrap-datepicker + * Xavier Dutreilh + */ +(function () { + Datepicker.locales['en-GB'] = { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/en-IE.js b/src/ui/static/js/datepicker/locales/en-IE.js new file mode 100644 index 000000000..1a41302cf --- /dev/null +++ b/src/ui/static/js/datepicker/locales/en-IE.js @@ -0,0 +1,17 @@ +/** + * Irish English translation for bootstrap-datepicker + */ +(function () { + Datepicker.locales['en-IE'] = { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/en-NZ.js b/src/ui/static/js/datepicker/locales/en-NZ.js new file mode 100644 index 000000000..dd34ac41d --- /dev/null +++ b/src/ui/static/js/datepicker/locales/en-NZ.js @@ -0,0 +1,17 @@ +/** + * New Zealand English translation for bootstrap-datepicker + */ +(function () { + Datepicker.locales['en-NZ'] = { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "d/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/en-ZA.js b/src/ui/static/js/datepicker/locales/en-ZA.js new file mode 100644 index 000000000..6455097d1 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/en-ZA.js @@ -0,0 +1,17 @@ +/** + * South African English translation for bootstrap-datepicker + */ +(function () { + Datepicker.locales['en-ZA'] = { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today", + monthsTitle: "Months", + clear: "Clear", + weekStart: 1, + format: "yyyy/mm/d" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/eo.js b/src/ui/static/js/datepicker/locales/eo.js new file mode 100644 index 000000000..f68306559 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/eo.js @@ -0,0 +1,17 @@ +/** + * Esperanto translation for bootstrap-datepicker + * Emmanuel Debanne + */ +(function () { + Datepicker.locales.eo = { + days: ["dimanĉo", "lundo", "mardo", "merkredo", "ĵaŭdo", "vendredo", "sabato"], + daysShort: ["dim.", "lun.", "mar.", "mer.", "ĵaŭ.", "ven.", "sam."], + daysMin: ["d", "l", "ma", "me", "ĵ", "v", "s"], + months: ["januaro", "februaro", "marto", "aprilo", "majo", "junio", "julio", "aŭgusto", "septembro", "oktobro", "novembro", "decembro"], + monthsShort: ["jan.", "feb.", "mar.", "apr.", "majo", "jun.", "jul.", "aŭg.", "sep.", "okt.", "nov.", "dec."], + today: "Hodiaŭ", + clear: "Nuligi", + weekStart: 1, + format: "yyyy-mm-dd" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/es.js b/src/ui/static/js/datepicker/locales/es.js new file mode 100644 index 000000000..d2be3f872 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/es.js @@ -0,0 +1,18 @@ +/** + * Spanish translation for bootstrap-datepicker + * Bruno Bonamin + */ +(function () { + Datepicker.locales.es = { + days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"], + daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"], + daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa"], + months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], + monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], + today: "Hoy", + monthsTitle: "Meses", + clear: "Borrar", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/et.js b/src/ui/static/js/datepicker/locales/et.js new file mode 100644 index 000000000..35a71def0 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/et.js @@ -0,0 +1,18 @@ +/** + * Estonian translation for bootstrap-datepicker + * Ando Roots + * Fixes by Illimar Tambek < + */ +(function () { + Datepicker.locales.et = { + days: ["Pühapäev", "Esmaspäev", "Teisipäev", "Kolmapäev", "Neljapäev", "Reede", "Laupäev"], + daysShort: ["Pühap", "Esmasp", "Teisip", "Kolmap", "Neljap", "Reede", "Laup"], + daysMin: ["P", "E", "T", "K", "N", "R", "L"], + months: ["Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember"], + monthsShort: ["Jaan", "Veebr", "Märts", "Apr", "Mai", "Juuni", "Juuli", "Aug", "Sept", "Okt", "Nov", "Dets"], + today: "Täna", + clear: "Tühjenda", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/eu.js b/src/ui/static/js/datepicker/locales/eu.js new file mode 100644 index 000000000..fd664f209 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/eu.js @@ -0,0 +1,18 @@ +/** + * Basque translation for bootstrap-datepicker + * Arkaitz Etxeberria + */ +(function () { + Datepicker.locales.eu = { + days: ['Igandea', 'Astelehena', 'Asteartea', 'Asteazkena', 'Osteguna', 'Ostirala', 'Larunbata'], + daysShort: ['Ig', 'Al', 'Ar', 'Az', 'Og', 'Ol', 'Lr'], + daysMin: ['Ig', 'Al', 'Ar', 'Az', 'Og', 'Ol', 'Lr'], + months: ['Urtarrila', 'Otsaila', 'Martxoa', 'Apirila', 'Maiatza', 'Ekaina', 'Uztaila', 'Abuztua', 'Iraila', 'Urria', 'Azaroa', 'Abendua'], + monthsShort: ['Urt', 'Ots', 'Mar', 'Api', 'Mai', 'Eka', 'Uzt', 'Abu', 'Ira', 'Urr', 'Aza', 'Abe'], + today: "Gaur", + monthsTitle: "Hilabeteak", + clear: "Ezabatu", + weekStart: 1, + format: "yyyy/mm/dd" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/fa.js b/src/ui/static/js/datepicker/locales/fa.js new file mode 100644 index 000000000..3e1e43e83 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/fa.js @@ -0,0 +1,17 @@ +/** + * Persian translation for bootstrap-datepicker + * Mostafa Rokooie + */ +(function () { + Datepicker.locales.fa = { + days: ["یک‌شنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنج‌شنبه", "جمعه", "شنبه", "یک‌شنبه"], + daysShort: ["یک", "دو", "سه", "چهار", "پنج", "جمعه", "شنبه", "یک"], + daysMin: ["ی", "د", "س", "چ", "پ", "ج", "ش", "ی"], + months: ["ژانویه", "فوریه", "مارس", "آوریل", "مه", "ژوئن", "ژوئیه", "اوت", "سپتامبر", "اکتبر", "نوامبر", "دسامبر"], + monthsShort: ["ژان", "فور", "مار", "آور", "مه", "ژون", "ژوی", "اوت", "سپت", "اکت", "نوا", "دسا"], + today: "امروز", + clear: "پاک کن", + weekStart: 1, + format: "yyyy/mm/dd" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/fi.js b/src/ui/static/js/datepicker/locales/fi.js new file mode 100644 index 000000000..bfd8cd052 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/fi.js @@ -0,0 +1,17 @@ +/** + * Finnish translation for bootstrap-datepicker + * Jaakko Salonen + */ +(function () { + Datepicker.locales.fi = { + days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"], + daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau"], + daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la"], + months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], + monthsShort: ["tammi", "helmi", "maalis", "huhti", "touko", "kesä", "heinä", "elo", "syys", "loka", "marras", "joulu"], + today: "tänään", + clear: "Tyhjennä", + weekStart: 1, + format: "d.m.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/fo.js b/src/ui/static/js/datepicker/locales/fo.js new file mode 100644 index 000000000..18d19491b --- /dev/null +++ b/src/ui/static/js/datepicker/locales/fo.js @@ -0,0 +1,15 @@ +/** + * Faroese translation for bootstrap-datepicker + * Theodor Johannesen + */ +(function () { + Datepicker.locales.fo = { + days: ["Sunnudagur", "Mánadagur", "Týsdagur", "Mikudagur", "Hósdagur", "Fríggjadagur", "Leygardagur"], + daysShort: ["Sun", "Mán", "Týs", "Mik", "Hós", "Frí", "Ley"], + daysMin: ["Su", "Má", "Tý", "Mi", "Hó", "Fr", "Le"], + months: ["Januar", "Februar", "Marts", "Apríl", "Mei", "Juni", "Juli", "August", "Septembur", "Oktobur", "Novembur", "Desembur"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], + today: "Í Dag", + clear: "Reinsa" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/fr-CH.js b/src/ui/static/js/datepicker/locales/fr-CH.js new file mode 100644 index 000000000..278a638b6 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/fr-CH.js @@ -0,0 +1,21 @@ +/** + * French (Switzerland) translation for bootstrap-datepicker + * Christoph Jossi + * Based on + * French translation for bootstrap-datepicker + * Nico Mollet + */ +(function () { + Datepicker.locales['fr-CH'] = { + days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"], + daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"], + daysMin: ["D", "L", "Ma", "Me", "J", "V", "S"], + months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], + monthsShort: ["Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Déc"], + today: "Aujourd'hui", + monthsTitle: "Mois", + clear: "Effacer", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/fr.js b/src/ui/static/js/datepicker/locales/fr.js new file mode 100644 index 000000000..86323f884 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/fr.js @@ -0,0 +1,18 @@ +/** + * French translation for bootstrap-datepicker + * Nico Mollet + */ +(function () { + Datepicker.locales.fr = { + days: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"], + daysShort: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."], + daysMin: ["d", "l", "ma", "me", "j", "v", "s"], + months: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"], + monthsShort: ["janv.", "févr.", "mars", "avril", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."], + today: "Aujourd'hui", + monthsTitle: "Mois", + clear: "Effacer", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/gl.js b/src/ui/static/js/datepicker/locales/gl.js new file mode 100644 index 000000000..1b52b5a4a --- /dev/null +++ b/src/ui/static/js/datepicker/locales/gl.js @@ -0,0 +1,16 @@ +/** + * Galician translation + */ +(function () { + Datepicker.locales.gl = { + days: ["Domingo", "Luns", "Martes", "Mércores", "Xoves", "Venres", "Sábado"], + daysShort: ["Dom", "Lun", "Mar", "Mér", "Xov", "Ven", "Sáb"], + daysMin: ["Do", "Lu", "Ma", "Me", "Xo", "Ve", "Sa"], + months: ["Xaneiro", "Febreiro", "Marzo", "Abril", "Maio", "Xuño", "Xullo", "Agosto", "Setembro", "Outubro", "Novembro", "Decembro"], + monthsShort: ["Xan", "Feb", "Mar", "Abr", "Mai", "Xun", "Xul", "Ago", "Sep", "Out", "Nov", "Dec"], + today: "Hoxe", + clear: "Limpar", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/he.js b/src/ui/static/js/datepicker/locales/he.js new file mode 100644 index 000000000..4c1138f7a --- /dev/null +++ b/src/ui/static/js/datepicker/locales/he.js @@ -0,0 +1,15 @@ +/** + * Hebrew translation for bootstrap-datepicker + * Sagie Maoz + */ +(function () { + Datepicker.locales.he = { + days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], + daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], + monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], + today: "היום", + rtl: true + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/hi.js b/src/ui/static/js/datepicker/locales/hi.js new file mode 100644 index 000000000..48e41cc35 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/hi.js @@ -0,0 +1,18 @@ +/** + * Hindi translation for bootstrap-datepicker + * Visar Uruqi + */ +(function () { + Datepicker.locales.hi = { + days: ["रविवार", "सोमवार", "मंगलवार", "बुधवार", "गुरुवार", "शुक्रवार", "शनिवार"], + daysShort: ["सूर्य", "सोम", "मंगल", "बुध", "गुरु", "शुक्र", "शनि"], + daysMin: ["र", "सो", "मं", "बु", "गु", "शु", "श"], + months: ["जनवरी", "फ़रवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितम्बर", "अक्टूबर", "नवंबर", "दिसम्बर"], + monthsShort: ["जन", "फ़रवरी", "मार्च", "अप्रैल", "मई", "जून", "जुलाई", "अगस्त", "सितं", "अक्टूबर", "नवं", "दिसम्बर"], + today: "आज", + monthsTitle: "महीने", + clear: "साफ", + weekStart: 1, + format: "dd / mm / yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/hr.js b/src/ui/static/js/datepicker/locales/hr.js new file mode 100644 index 000000000..18544a0e2 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/hr.js @@ -0,0 +1,13 @@ +/** + * Croatian localisation + */ +(function () { + Datepicker.locales.hr = { + days: ["Nedjelja", "Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"], + daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su"], + months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], + monthsShort: ["Sij", "Velj", "Ožu", "Tra", "Svi", "Lip", "Srp", "Kol", "Ruj", "Lis", "Stu", "Pro"], + today: "Danas" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/hu.js b/src/ui/static/js/datepicker/locales/hu.js new file mode 100644 index 000000000..5eaffa61d --- /dev/null +++ b/src/ui/static/js/datepicker/locales/hu.js @@ -0,0 +1,18 @@ +/** + * Hungarian translation for bootstrap-datepicker + * Sotus László + */ +(function () { + Datepicker.locales.hu = { + days: ["vasárnap", "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat"], + daysShort: ["vas", "hét", "ked", "sze", "csü", "pén", "szo"], + daysMin: ["V", "H", "K", "Sze", "Cs", "P", "Szo"], + months: ["január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december"], + monthsShort: ["jan", "feb", "már", "ápr", "máj", "jún", "júl", "aug", "sze", "okt", "nov", "dec"], + today: "ma", + weekStart: 1, + clear: "töröl", + titleFormat: "y. MM", + format: "yyyy.mm.dd" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/hy.js b/src/ui/static/js/datepicker/locales/hy.js new file mode 100644 index 000000000..dd662d0df --- /dev/null +++ b/src/ui/static/js/datepicker/locales/hy.js @@ -0,0 +1,18 @@ +/** + * Armenian translation for bootstrap-datepicker + * Hayk Chamyan + */ +(function () { + Datepicker.locales.hy = { + days: ["Կիրակի", "Երկուշաբթի", "Երեքշաբթի", "Չորեքշաբթի", "Հինգշաբթի", "Ուրբաթ", "Շաբաթ"], + daysShort: ["Կիր", "Երկ", "Երե", "Չոր", "Հին", "Ուրբ", "Շաբ"], + daysMin: ["Կի", "Եկ", "Եք", "Չո", "Հի", "Ու", "Շա"], + months: ["Հունվար", "Փետրվար", "Մարտ", "Ապրիլ", "Մայիս", "Հունիս", "Հուլիս", "Օգոստոս", "Սեպտեմբեր", "Հոկտեմբեր", "Նոյեմբեր", "Դեկտեմբեր"], + monthsShort: ["Հնվ", "Փետ", "Մար", "Ապր", "Մայ", "Հուն", "Հուլ", "Օգս", "Սեպ", "Հոկ", "Նոյ", "Դեկ"], + today: "Այսօր", + clear: "Ջնջել", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Ամիսնէր' + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/id.js b/src/ui/static/js/datepicker/locales/id.js new file mode 100644 index 000000000..0f0c2b9fa --- /dev/null +++ b/src/ui/static/js/datepicker/locales/id.js @@ -0,0 +1,19 @@ +/** + * Bahasa translation for bootstrap-datepicker + * Azwar Akbar + * Ardeman + */ +(function () { + Datepicker.locales.id = { + days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"], + daysShort: ["Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab"], + daysMin: ["Mg", "Sn", "Sl", "Rb", "Km", "Jm", "Sb"], + months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agt", "Sep", "Okt", "Nov", "Des"], + today: "Hari Ini", + monthsTitle: "Bulan", + clear: "Kosongkan", + weekStart: 0, + format: "dd-mm-yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/is.js b/src/ui/static/js/datepicker/locales/is.js new file mode 100644 index 000000000..18f818dc4 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/is.js @@ -0,0 +1,14 @@ +/** + * Icelandic translation for bootstrap-datepicker + * Hinrik Örn Sigurðsson + */ +(function () { + Datepicker.locales.is = { + days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur"], + daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau"], + daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La"], + months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], + today: "Í Dag" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/it-CH.js b/src/ui/static/js/datepicker/locales/it-CH.js new file mode 100644 index 000000000..b1081cd4a --- /dev/null +++ b/src/ui/static/js/datepicker/locales/it-CH.js @@ -0,0 +1,20 @@ +/** + * Italian (Switzerland) translation for bootstrap-datepicker + * Christoph Jossi + * Based on + * Italian translation for bootstrap-datepicker + * Enrico Rubboli + */ +(function () { + Datepicker.locales['it-CH'] = { + days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"], + daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"], + daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa"], + months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], + today: "Oggi", + clear: "Cancella", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/it.js b/src/ui/static/js/datepicker/locales/it.js new file mode 100644 index 000000000..70d98ab70 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/it.js @@ -0,0 +1,18 @@ +/** + * Italian translation for bootstrap-datepicker + * Enrico Rubboli + */ +(function () { + Datepicker.locales.it = { + days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"], + daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"], + daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa"], + months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], + today: "Oggi", + monthsTitle: "Mesi", + clear: "Cancella", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ja.js b/src/ui/static/js/datepicker/locales/ja.js new file mode 100644 index 000000000..f1c1b3030 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ja.js @@ -0,0 +1,17 @@ +/** + * Japanese translation for bootstrap-datepicker + * Norio Suzuki + */ +(function () { + Datepicker.locales.ja = { + days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜"], + daysShort: ["日", "月", "火", "水", "木", "金", "土"], + daysMin: ["日", "月", "火", "水", "木", "金", "土"], + months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今日", + format: "yyyy/mm/dd", + titleFormat: "y年mm月", + clear: "クリア" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ka.js b/src/ui/static/js/datepicker/locales/ka.js new file mode 100644 index 000000000..b0cd474a4 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ka.js @@ -0,0 +1,17 @@ +/** + * Georgian translation for bootstrap-datepicker + * Levan Melikishvili + */ +(function () { + Datepicker.locales.ka = { + days: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი"], + daysShort: ["კვი", "ორშ", "სამ", "ოთხ", "ხუთ", "პარ", "შაბ"], + daysMin: ["კვ", "ორ", "სა", "ოთ", "ხუ", "პა", "შა"], + months: ["იანვარი", "თებერვალი", "მარტი", "აპრილი", "მაისი", "ივნისი", "ივლისი", "აგვისტო", "სექტემბერი", "ოქტომბერი", "ნოემბერი", "დეკემბერი"], + monthsShort: ["იან", "თებ", "მარ", "აპრ", "მაი", "ივნ", "ივლ", "აგვ", "სექ", "ოქტ", "ნოე", "დეკ"], + today: "დღეს", + clear: "გასუფთავება", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/kk.js b/src/ui/static/js/datepicker/locales/kk.js new file mode 100644 index 000000000..9b85f8cf9 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/kk.js @@ -0,0 +1,15 @@ +/** + * Kazakh translation for bootstrap-datepicker + * Yerzhan Tolekov + */ +(function () { + Datepicker.locales.kk = { + days: ["Жексенбі", "Дүйсенбі", "Сейсенбі", "Сәрсенбі", "Бейсенбі", "Жұма", "Сенбі"], + daysShort: ["Жек", "Дүй", "Сей", "Сәр", "Бей", "Жұм", "Сен"], + daysMin: ["Жк", "Дс", "Сс", "Ср", "Бс", "Жм", "Сн"], + months: ["Қаңтар", "Ақпан", "Наурыз", "Сәуір", "Мамыр", "Маусым", "Шілде", "Тамыз", "Қыркүйек", "Қазан", "Қараша", "Желтоқсан"], + monthsShort: ["Қаң", "Ақп", "Нау", "Сәу", "Мам", "Мау", "Шіл", "Там", "Қыр", "Қаз", "Қар", "Жел"], + today: "Бүгін", + weekStart: 1 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/km.js b/src/ui/static/js/datepicker/locales/km.js new file mode 100644 index 000000000..71e294cd3 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/km.js @@ -0,0 +1,15 @@ +/** + * Khmer translation for bootstrap-datepicker + * This is the Updated Version of: https: //github.com/uxsolutions/bootstrap-datepicker/blob/71308d42cce9524284c50c6fac50422d1790ac0f/js/locales/bootstrap-datepicker.kh.js + */ +(function () { + Datepicker.locales.km = { + days: ["អាទិត្យ", "ចន្ទ", "អង្គារ", "ពុធ", "ព្រហស្បតិ៍", "សុក្រ", "សៅរ៍"], + daysShort: ["អា.ទិ", "ចន្ទ", "អង្គារ", "ពុធ", "ព្រ.ហ", "សុក្រ", "សៅរ៍"], + daysMin: ["អា.ទិ", "ចន្ទ", "អង្គារ", "ពុធ", "ព្រ.ហ", "សុក្រ", "សៅរ៍"], + months: ["មករា", "កុម្ភះ", "មិនា", "មេសា", "ឧសភា", "មិថុនា", "កក្កដា", "សីហា", "កញ្ញា", "តុលា", "វិច្ឆិកា", "ធ្នូ"], + monthsShort: ["មករា", "កុម្ភះ", "មិនា", "មេសា", "ឧសភា", "មិថុនា", "កក្កដា", "សីហា", "កញ្ញា", "តុលា", "វិច្ឆិកា", "ធ្នូ"], + today: "ថ្ងៃនេះ", + clear: "សំអាត" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ko.js b/src/ui/static/js/datepicker/locales/ko.js new file mode 100644 index 000000000..3be9400b9 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ko.js @@ -0,0 +1,18 @@ +/** + * Korean translation for bootstrap-datepicker + * This is a port from https: //github.com/moment/moment/blob/develop/src/locale/ko.js + */ +(function () { + Datepicker.locales.ko = { + days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"], + daysShort: ["일", "월", "화", "수", "목", "금", "토"], + daysMin: ["일", "월", "화", "수", "목", "금", "토"], + months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + today: "오늘", + clear: "삭제", + format: "yyyy-mm-dd", + titleFormat: "y년mm월", + weekStart: 0 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/lt.js b/src/ui/static/js/datepicker/locales/lt.js new file mode 100644 index 000000000..894e8cbc5 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/lt.js @@ -0,0 +1,19 @@ +/** + * Lithuanian translation for bootstrap-datepicker + * Šarūnas Gliebus + */ + +(function () { + Datepicker.locales.lt = { + days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis"], + daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š"], + daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št"], + months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], + monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], + today: "Šiandien", + monthsTitle: "Mėnesiai", + clear: "Išvalyti", + weekStart: 1, + format: "yyyy-mm-dd" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/lv.js b/src/ui/static/js/datepicker/locales/lv.js new file mode 100644 index 000000000..109014b9a --- /dev/null +++ b/src/ui/static/js/datepicker/locales/lv.js @@ -0,0 +1,18 @@ +/** + * Latvian translation for bootstrap-datepicker + * Artis Avotins + */ + +(function () { + Datepicker.locales.lv = { + days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena"], + daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S"], + daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"], + months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec"], + monthsTitle: "Mēneši", + today: "Šodien", + clear: "Nodzēst", + weekStart: 1 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/me.js b/src/ui/static/js/datepicker/locales/me.js new file mode 100644 index 000000000..6ecc09729 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/me.js @@ -0,0 +1,17 @@ +/** + * Montenegrin translation for bootstrap-datepicker + * Miodrag Nikač + */ +(function () { + Datepicker.locales.me = { + days: ["Nedjelja","Ponedjeljak", "Utorak", "Srijeda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub"], + daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danas", + weekStart: 1, + clear: "Izbriši", + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/mk.js b/src/ui/static/js/datepicker/locales/mk.js new file mode 100644 index 000000000..df87e2d18 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/mk.js @@ -0,0 +1,15 @@ +/** + * Macedonian translation for bootstrap-datepicker + * Marko Aleksic + */ +(function () { + Datepicker.locales.mk = { + days: ["Недела", "Понеделник", "Вторник", "Среда", "Четврток", "Петок", "Сабота"], + daysShort: ["Нед", "Пон", "Вто", "Сре", "Чет", "Пет", "Саб"], + daysMin: ["Не", "По", "Вт", "Ср", "Че", "Пе", "Са"], + months: ["Јануари", "Февруари", "Март", "Април", "Мај", "Јуни", "Јули", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Јан", "Фев", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "Денес", + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/mn.js b/src/ui/static/js/datepicker/locales/mn.js new file mode 100644 index 000000000..c080280be --- /dev/null +++ b/src/ui/static/js/datepicker/locales/mn.js @@ -0,0 +1,17 @@ +/** + * Mongolian translation for bootstrap-datepicker + * Andrey Torsunov + */ +(function () { + Datepicker.locales.mn = { + days: ["Ням", "Даваа", "Мягмар", "Лхагва", "Пүрэв", "Баасан", "Бямба"], + daysShort: ["Ням", "Дав", "Мяг", "Лха", "Пүр", "Баа", "Бям"], + daysMin: ["Ня", "Да", "Мя", "Лх", "Пү", "Ба", "Бя"], + months: ["Хулгана", "Үхэр", "Бар", "Туулай", "Луу", "Могой", "Морь", "Хонь", "Бич", "Тахиа", "Нохой", "Гахай"], + monthsShort: ["Хул", "Үхэ", "Бар", "Туу", "Луу", "Мог", "Мор", "Хон", "Бич", "Тах", "Нох", "Гах"], + today: "Өнөөдөр", + clear: "Тодорхой", + format: "yyyy.mm.dd", + weekStart: 1 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/mr.js b/src/ui/static/js/datepicker/locales/mr.js new file mode 100644 index 000000000..67289df2a --- /dev/null +++ b/src/ui/static/js/datepicker/locales/mr.js @@ -0,0 +1,18 @@ +/** + * Marathi translation for bootstrap-datepicker + * Sushant Pimple + */ +(function () { + Datepicker.locales.mr = { + days: ["रविवार", "सोमवार", "मंगळवार", "बुधवार", "गुरुवार", "शुक्रवार", "शनिवार"], + daysShort: ["रवि", "सोम", "मंगळ", "बुध", "गुरु", "शुक्र", "शनि"], + daysMin: ["र", "सो", "मं", "बु", "गु", "शु", "श"], + months: ["जानेवारी", "फेब्रुवारी", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टेंबर", "ऑक्टोबर", "नोव्हेंबर", "डिसेंबर"], + monthsShort: ["जाने.", "फेब्रु.", "मार्च", "एप्रिल", "मे", "जून", "जुलै", "ऑगस्ट", "सप्टें.", "ऑक्टो.", "नोव्हें.", "डिसें."], + today: "आज", + monthsTitle: "महीने", + clear: "हटवा", + weekStart: 1, + format: "dd / mm / yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ms.js b/src/ui/static/js/datepicker/locales/ms.js new file mode 100644 index 000000000..20283bd4d --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ms.js @@ -0,0 +1,15 @@ +/** + * Malay translation for bootstrap-datepicker + * Ateman Faiz + */ +(function () { + Datepicker.locales.ms = { + days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu"], + daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab"], + daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa"], + months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], + today: "Hari Ini", + clear: "Bersihkan" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/nl-BE.js b/src/ui/static/js/datepicker/locales/nl-BE.js new file mode 100644 index 000000000..6cf3d5654 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/nl-BE.js @@ -0,0 +1,18 @@ +/** + * Belgium-Dutch translation for bootstrap-datepicker + * Julien Poulin + */ +(function () { + Datepicker.locales['nl-BE'] = { + days: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"], + daysShort: ["zo", "ma", "di", "wo", "do", "vr", "za"], + daysMin: ["zo", "ma", "di", "wo", "do", "vr", "za"], + months: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"], + monthsShort: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"], + today: "Vandaag", + monthsTitle: "Maanden", + clear: "Leegmaken", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/nl.js b/src/ui/static/js/datepicker/locales/nl.js new file mode 100644 index 000000000..1bc12ea12 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/nl.js @@ -0,0 +1,18 @@ +/** + * Dutch translation for bootstrap-datepicker + * Reinier Goltstein + */ +(function () { + Datepicker.locales.nl = { + days: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"], + daysShort: ["zo", "ma", "di", "wo", "do", "vr", "za"], + daysMin: ["zo", "ma", "di", "wo", "do", "vr", "za"], + months: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"], + monthsShort: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"], + today: "Vandaag", + monthsTitle: "Maanden", + clear: "Wissen", + weekStart: 1, + format: "dd-mm-yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/no.js b/src/ui/static/js/datepicker/locales/no.js new file mode 100644 index 000000000..d9c55fe4b --- /dev/null +++ b/src/ui/static/js/datepicker/locales/no.js @@ -0,0 +1,18 @@ +/** + * Norwegian translation for bootstrap-datepicker + * George Gooding + */ +(function () { + Datepicker.locales.no = { + days: ['søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag'], + daysShort: ['søn', 'man', 'tir', 'ons', 'tor', 'fre', 'lør'], + daysMin: ['sø', 'ma', 'ti', 'on', 'to', 'fr', 'lø'], + months: ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'], + monthsShort: ['jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'], + today: 'i dag', + monthsTitle: 'Måneder', + clear: 'Nullstill', + weekStart: 1, + format: 'dd.mm.yyyy' + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/oc.js b/src/ui/static/js/datepicker/locales/oc.js new file mode 100644 index 000000000..c1d600743 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/oc.js @@ -0,0 +1,17 @@ +/** + * Occitan translation for bootstrap-datepicker + */ +(function () { + Datepicker.locales.oc = { + days: ["Dimenge", "Diluns", "Dimars", "Dimècres", "Dijòus", "Divendres", "Dissabte"], + daysShort: ["Dim", "Dil", "Dmr", "Dmc", "Dij", "Div", "Dis"], + daysMin: ["dg", "dl", "dr", "dc", "dj", "dv", "ds"], + months: ["Genièr", "Febrièr", "Març", "Abrial", "Mai", "Junh", "Julhet", "Agost", "Setembre", "Octobre", "Novembre", "Decembre"], + monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Dec"], + today: "Uèi", + monthsTitle: "Meses", + clear: "Escafar", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/pl.js b/src/ui/static/js/datepicker/locales/pl.js new file mode 100644 index 000000000..55444afd7 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/pl.js @@ -0,0 +1,17 @@ +/** + * Polish translation for bootstrap-datepicker + * Robert + */ +(function () { + Datepicker.locales.pl = { + days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"], + daysShort: ["Niedz.", "Pon.", "Wt.", "Śr.", "Czw.", "Piąt.", "Sob."], + daysMin: ["Ndz.", "Pn.", "Wt.", "Śr.", "Czw.", "Pt.", "Sob."], + months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], + monthsShort: ["Sty.", "Lut.", "Mar.", "Kwi.", "Maj", "Cze.", "Lip.", "Sie.", "Wrz.", "Paź.", "Lis.", "Gru."], + today: "Dzisiaj", + weekStart: 1, + clear: "Wyczyść", + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/pt-BR.js b/src/ui/static/js/datepicker/locales/pt-BR.js new file mode 100644 index 000000000..fb855c904 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/pt-BR.js @@ -0,0 +1,17 @@ +/** + * Brazilian translation for bootstrap-datepicker + * Cauan Cabral + */ +(function () { + Datepicker.locales['pt-BR'] = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje", + monthsTitle: "Meses", + clear: "Limpar", + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/pt.js b/src/ui/static/js/datepicker/locales/pt.js new file mode 100644 index 000000000..f25cf9b48 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/pt.js @@ -0,0 +1,18 @@ +/** + * Portuguese translation for bootstrap-datepicker + * Original code: Cauan Cabral + * Tiago Melo + */ +(function () { + Datepicker.locales.pt = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje", + monthsTitle: "Meses", + clear: "Limpar", + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ro.js b/src/ui/static/js/datepicker/locales/ro.js new file mode 100644 index 000000000..0b98838e8 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ro.js @@ -0,0 +1,17 @@ +/** + * Romanian translation for bootstrap-datepicker + * Cristian Vasile + */ +(function () { + Datepicker.locales.ro = { + days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă"], + daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm"], + daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ"], + months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], + monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Astăzi", + clear: "Șterge", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ru.js b/src/ui/static/js/datepicker/locales/ru.js new file mode 100644 index 000000000..f85cc51ea --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ru.js @@ -0,0 +1,18 @@ +/** + * Russian translation for bootstrap-datepicker + * Victor Taranenko + */ +(function () { + Datepicker.locales.ru = { + days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"], + daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб"], + daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], + months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], + monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], + today: "Сегодня", + clear: "Очистить", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Месяцы' + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/si.js b/src/ui/static/js/datepicker/locales/si.js new file mode 100644 index 000000000..04bf43f0c --- /dev/null +++ b/src/ui/static/js/datepicker/locales/si.js @@ -0,0 +1,18 @@ +/** + * Sinhala translation for bootstrap-datepicker + * Chanaka Fernando + */ +(function () { + Datepicker.locales.si = { + days: ["ඉරිදා", "සඳුදා", "අඟහරුවාදා", "බදාදා", "බ්‍රහස්පතින්දා", "සිකුරාදා", "සෙනසුරාදා"], + daysShort: ["ඉරි", "සඳු", "අඟ", "බදා", "බ්‍රහ", "සිකු", "සෙන"], + daysMin: ["ඉ", "ස", "අ", "බ", "බ්‍ර", "සි", "සෙ"], + months: ["ජනවාරි", "පෙබරවාරි", "මාර්තු", "අප්‍රේල්", "මැයි", "ජුනි", "ජූලි", "අගෝස්තු", "සැප්තැම්බර්", "ඔක්තෝබර්", "නොවැම්බර්", "දෙසැම්බර්"], + monthsShort: ["ජන", "පෙබ", "මාර්", "අප්‍රේ", "මැයි", "ජුනි", "ජූලි", "අගෝ", "සැප්", "ඔක්", "නොවැ", "දෙසැ"], + today: "අද", + monthsTitle: "මාස", + clear: "මකන්න", + weekStart: 0, + format: "yyyy-mm-dd" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/sk.js b/src/ui/static/js/datepicker/locales/sk.js new file mode 100644 index 000000000..0f813abf3 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/sk.js @@ -0,0 +1,18 @@ +/** + * Slovak translation for bootstrap-datepicker + * Marek Lichtner + * Fixes by Michal Remiš + */ +(function () { + Datepicker.locales.sk = { + days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"], + daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob"], + daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pia", "So"], + months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Dnes", + clear: "Vymazať", + weekStart: 1, + format: "d.m.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/sl.js b/src/ui/static/js/datepicker/locales/sl.js new file mode 100644 index 000000000..6fae7fd23 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/sl.js @@ -0,0 +1,15 @@ +/** + * Slovene translation for bootstrap-datepicker + * Gregor Rudolf + */ +(function () { + Datepicker.locales.sl = { + days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota"], + daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob"], + daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So"], + months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danes", + weekStart: 1 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/sq.js b/src/ui/static/js/datepicker/locales/sq.js new file mode 100644 index 000000000..32b2f1d6b --- /dev/null +++ b/src/ui/static/js/datepicker/locales/sq.js @@ -0,0 +1,18 @@ +/** + * Albanian translation for bootstrap-datepicker + * Tomor Pupovci + */ +(function () { + Datepicker.locales.sq = { + days: ["E Diel", "E Hënë", "E Martē", "E Mërkurë", "E Enjte", "E Premte", "E Shtunë"], + daysShort: ["Die", "Hën", "Mar", "Mër", "Enj", "Pre", "Shtu"], + daysMin: ["Di", "Hë", "Ma", "Më", "En", "Pr", "Sht"], + months: ["Janar", "Shkurt", "Mars", "Prill", "Maj", "Qershor", "Korrik", "Gusht", "Shtator", "Tetor", "Nëntor", "Dhjetor"], + monthsShort: ["Jan", "Shk", "Mar", "Pri", "Maj", "Qer", "Korr", "Gu", "Sht", "Tet", "Nën", "Dhjet"], + monthsTitle: "Muaj", + today: "Sot", + weekStart: 1, + format: "dd/mm/yyyy", + clear: "Pastro" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/sr-latn.js b/src/ui/static/js/datepicker/locales/sr-latn.js new file mode 100644 index 000000000..65281d434 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/sr-latn.js @@ -0,0 +1,16 @@ +/** + * Serbian latin translation for bootstrap-datepicker + * Bojan Milosavlević + */ +(function () { + Datepicker.locales['sr-latn'] = { + days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota"], + daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub"], + daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danas", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/sr.js b/src/ui/static/js/datepicker/locales/sr.js new file mode 100644 index 000000000..275edd7d4 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/sr.js @@ -0,0 +1,16 @@ +/** + * Serbian cyrillic translation for bootstrap-datepicker + * Bojan Milosavlević + */ +(function () { + Datepicker.locales.sr = { + days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота"], + daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб"], + daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су"], + months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], + monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], + today: "Данас", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/sv.js b/src/ui/static/js/datepicker/locales/sv.js new file mode 100644 index 000000000..955ff67d0 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/sv.js @@ -0,0 +1,17 @@ +/** + * Swedish translation for bootstrap-datepicker + * Patrik Ragnarsson + */ +(function () { + Datepicker.locales.sv = { + days: ["söndag", "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag"], + daysShort: ["sön", "mån", "tis", "ons", "tor", "fre", "lör"], + daysMin: ["sö", "må", "ti", "on", "to", "fr", "lö"], + months: ["januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"], + monthsShort: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"], + today: "Idag", + format: "yyyy-mm-dd", + weekStart: 1, + clear: "Rensa" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/sw.js b/src/ui/static/js/datepicker/locales/sw.js new file mode 100644 index 000000000..e67b01f76 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/sw.js @@ -0,0 +1,15 @@ +/** + * Swahili translation for bootstrap-datepicker + * Edwin Mugendi + * Source: http: //scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku + */ +(function () { + Datepicker.locales.sw = { + days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi"], + daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1"], + daysMin: ["2", "3", "4", "5", "A", "I", "1"], + months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], + monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], + today: "Leo" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/ta.js b/src/ui/static/js/datepicker/locales/ta.js new file mode 100644 index 000000000..ff3389286 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/ta.js @@ -0,0 +1,18 @@ +/** + * Tamil translation for bootstrap-datepicker + * Abubacker Siddik A + */ +(function () { + Datepicker.locales.ta = { + days: ["ஞாயிறு", "திங்கள்", "செவ்வாய்", "புதன்", "வியாழன்", "வெள்ளி", "சனி"], + daysShort: ["ஞாயி", "திங்", "செவ்", "புத", "வியா", "வெள்", "சனி"], + daysMin: ["ஞா", "தி", "செ", "பு", "வி", "வெ", "ச"], + months: ["ஜனவரி", "பிப்ரவரி", "மார்ச்", "ஏப்ரல்", "மே", "ஜூன்", "ஜூலை", "ஆகஸ்டு", "செப்டம்பர்", "அக்டோபர்", "நவம்பர்", "டிசம்பர்"], + monthsShort: ["ஜன", "பிப்", "மார்", "ஏப்", "மே", "ஜூன்", "ஜூலை", "ஆக", "செப்", "அக்", "நவ", "டிச"], + today: "இன்று", + monthsTitle: "மாதங்கள்", + clear: "நீக்கு", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/tg.js b/src/ui/static/js/datepicker/locales/tg.js new file mode 100644 index 000000000..497c83717 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/tg.js @@ -0,0 +1,19 @@ +/** + * Tajik (cyrillic) translation for bootstrap-datepicker + * Bakhtiyor Bahritidinov + * Orif N. Jr. + */ +(function () { + Datepicker.locales.tg = { + days: ["Якшанбе", "Душанбе", "Сешанбе", "Чоршанбе", "Панҷшанбе", "Ҷумъа", "Шанбе"], + daysShort: ["Яшб", "Дшб", "Сшб", "Чшб", "Пшб", "Ҷум", "Шнб"], + daysMin: ["Яш", "Дш", "Сш", "Чш", "Пш", "Ҷм", "Шб"], + months: ["Январ", "Феврал", "Март", "Апрел", "Май", "Июн", "Июл", "Август", "Сентябр", "Октябр", "Ноябр", "Декабр"], + monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], + today: "Имрӯз", + monthsTitle: "Моҳҳо", + clear: "Тоза намудан", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/th.js b/src/ui/static/js/datepicker/locales/th.js new file mode 100644 index 000000000..bdeb7904e --- /dev/null +++ b/src/ui/static/js/datepicker/locales/th.js @@ -0,0 +1,14 @@ +/** + * Thai translation for bootstrap-datepicker + * Suchau Jiraprapot + */ +(function () { + Datepicker.locales.th = { + days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], + daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], + monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], + today: "วันนี้" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/tk.js b/src/ui/static/js/datepicker/locales/tk.js new file mode 100644 index 000000000..4c8affd4a --- /dev/null +++ b/src/ui/static/js/datepicker/locales/tk.js @@ -0,0 +1,18 @@ +/** + * Turkmen translation for bootstrap-datepicker + * N'Bayramberdiyev + */ +(function () { + Datepicker.locales.tk = { + days: ["Ýekşenbe", "Duşenbe", "Sişenbe", "Çarşenbe", "Penşenbe", "Anna", "Şenbe"], + daysShort: ["Ýek", "Duş", "Siş", "Çar", "Pen", "Ann", "Şen"], + daysMin: ["Ýe", "Du", "Si", "Ça", "Pe", "An", "Şe"], + months: ["Ýanwar", "Fewral", "Mart", "Aprel", "Maý", "Iýun", "Iýul", "Awgust", "Sentýabr", "Oktýabr", "Noýabr", "Dekabr"], + monthsShort: ["Ýan", "Few", "Mar", "Apr", "Maý", "Iýn", "Iýl", "Awg", "Sen", "Okt", "Noý", "Dek"], + today: "Bu gün", + monthsTitle: "Aýlar", + clear: "Aýyr", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/tr.js b/src/ui/static/js/datepicker/locales/tr.js new file mode 100644 index 000000000..5a97ed774 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/tr.js @@ -0,0 +1,17 @@ +/** + * Turkish translation for bootstrap-datepicker + * Serkan Algur + */ +(function () { + Datepicker.locales.tr = { + days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"], + daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts"], + daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct"], + months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], + monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], + today: "Bugün", + clear: "Temizle", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/uk.js b/src/ui/static/js/datepicker/locales/uk.js new file mode 100644 index 000000000..382103527 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/uk.js @@ -0,0 +1,17 @@ +/** + * Ukrainian translation for bootstrap-datepicker + * Igor Polynets + */ +(function () { + Datepicker.locales.uk = { + days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота"], + daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб"], + daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"], + months: ["Cічень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], + monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], + today: "Сьогодні", + clear: "Очистити", + format: "dd.mm.yyyy", + weekStart: 1 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/uz-cyrl.js b/src/ui/static/js/datepicker/locales/uz-cyrl.js new file mode 100644 index 000000000..3dd8dde79 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/uz-cyrl.js @@ -0,0 +1,18 @@ +/** + * Uzbek cyrillic translation for bootstrap-datepicker + * Kakhramonov Javlonbek + */ +(function () { + Datepicker.locales['uz-cyrl'] = { + days: ["Якшанба", "Душанба", "Сешанба", "Чоршанба", "Пайшанба", "Жума", "Шанба"], + daysShort: ["Якш", "Ду", "Се", "Чор", "Пай", "Жу", "Ша"], + daysMin: ["Як", "Ду", "Се", "Чо", "Па", "Жу", "Ша"], + months: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"], + monthsShort: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"], + today: "Бугун", + clear: "Ўчириш", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Ойлар' + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/uz-latn.js b/src/ui/static/js/datepicker/locales/uz-latn.js new file mode 100644 index 000000000..8f18dac68 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/uz-latn.js @@ -0,0 +1,18 @@ +/** + * Uzbek latin translation for bootstrap-datepicker + * Kakhramonov Javlonbek + */ +(function () { + Datepicker.locales['uz-latn'] = { + days: ["Yakshanba", "Dushanba", "Seshanba", "Chorshanba", "Payshanba", "Juma", "Shanba"], + daysShort: ["Yak", "Du", "Se", "Chor", "Pay", "Ju", "Sha"], + daysMin: ["Ya", "Du", "Se", "Cho", "Pa", "Ju", "Sha"], + months: ["Yanvar", "Fevral", "Mart", "Aprel", "May", "Iyun", "Iyul", "Avgust", "Sentabr", "Oktabr", "Noyabr", "Dekabr"], + monthsShort: ["Yan", "Fev", "Mar", "Apr", "May", "Iyn", "Iyl", "Avg", "Sen", "Okt", "Noy", "Dek"], + today: "Bugun", + clear: "O'chirish", + format: "dd.mm.yyyy", + weekStart: 1, + monthsTitle: 'Oylar' + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/vi.js b/src/ui/static/js/datepicker/locales/vi.js new file mode 100644 index 000000000..90b5cb8a6 --- /dev/null +++ b/src/ui/static/js/datepicker/locales/vi.js @@ -0,0 +1,16 @@ +/** + * Vietnamese translation for bootstrap-datepicker + * An Vo + */ +(function () { + Datepicker.locales.vi = { + days: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy"], + daysShort: ["CN", "Thứ 2", "Thứ 3", "Thứ 4", "Thứ 5", "Thứ 6", "Thứ 7"], + daysMin: ["CN", "T2", "T3", "T4", "T5", "T6", "T7"], + months: ["Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"], + monthsShort: ["Th1", "Th2", "Th3", "Th4", "Th5", "Th6", "Th7", "Th8", "Th9", "Th10", "Th11", "Th12"], + today: "Hôm nay", + clear: "Xóa", + format: "dd/mm/yyyy" + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/zh-CN.js b/src/ui/static/js/datepicker/locales/zh-CN.js new file mode 100644 index 000000000..adec7d20c --- /dev/null +++ b/src/ui/static/js/datepicker/locales/zh-CN.js @@ -0,0 +1,19 @@ +/** + * Simplified Chinese translation for bootstrap-datepicker + * Yuan Cheung + */ +(function () { + Datepicker.locales['zh-CN'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], + daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], + daysMin: ["日", "一", "二", "三", "四", "五", "六"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今天", + monthsTitle: "选择月份", + clear: "清除", + format: "yyyy-mm-dd", + titleFormat: "y年mm月", + weekStart: 1 + }; +}()); diff --git a/src/ui/static/js/datepicker/locales/zh-TW.js b/src/ui/static/js/datepicker/locales/zh-TW.js new file mode 100644 index 000000000..379f7d89e --- /dev/null +++ b/src/ui/static/js/datepicker/locales/zh-TW.js @@ -0,0 +1,20 @@ +/** + * Traditional Chinese translation for bootstrap-datepicker + * Rung-Sheng Jang + * FrankWu Fix more appropriate use of Traditional Chinese habit + */ +(function () { + Datepicker.locales['zh-TW'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"], + daysShort: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"], + daysMin: ["日", "一", "二", "三", "四", "五", "六"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今天", + monthsTitle: "月份", + format: "yyyy/mm/dd", + weekStart: 0, + titleFormat: "y年mm月", + clear: "清除" + }; +}()); diff --git a/src/ui/static/js/datepicker/main.js b/src/ui/static/js/datepicker/main.js new file mode 100644 index 000000000..7b589db91 --- /dev/null +++ b/src/ui/static/js/datepicker/main.js @@ -0,0 +1,4 @@ +import Datepicker from './Datepicker.js'; +import DateRangePicker from './DateRangePicker.js'; + +export {Datepicker, DateRangePicker}; diff --git a/src/ui/static/js/datepicker/options/defaultOptions.js b/src/ui/static/js/datepicker/options/defaultOptions.js new file mode 100644 index 000000000..d037ede4b --- /dev/null +++ b/src/ui/static/js/datepicker/options/defaultOptions.js @@ -0,0 +1,38 @@ +// config options updatable by setOptions() and their default values +const defaultOptions = { + autohide: false, + beforeShowDay: null, + beforeShowDecade: null, + beforeShowMonth: null, + beforeShowYear: null, + calendarWeeks: false, + clearBtn: false, + dateDelimiter: ',', + datesDisabled: [], + daysOfWeekDisabled: [], + daysOfWeekHighlighted: [], + defaultViewDate: undefined, // placeholder, defaults to today() by the program + disableTouchKeyboard: false, + format: 'mm/dd/yyyy', + language: 'en', + maxDate: null, + maxNumberOfDates: 1, + maxView: 3, + minDate: null, + nextArrow: '»', + orientation: 'auto', + pickLevel: 0, + prevArrow: '«', + showDaysOfWeek: true, + showOnClick: true, + showOnFocus: true, + startView: 0, + title: '', + todayBtn: false, + todayBtnMode: 0, + todayHighlight: false, + updateOnBlur: true, + weekStart: 0, +}; + +export default defaultOptions; diff --git a/src/ui/static/js/datepicker/options/processOptions.js b/src/ui/static/js/datepicker/options/processOptions.js new file mode 100644 index 000000000..007b83676 --- /dev/null +++ b/src/ui/static/js/datepicker/options/processOptions.js @@ -0,0 +1,288 @@ +import {hasProperty, pushUnique} from '../lib/utils.js'; +import {dateValue, regularizeDate} from '../lib/date.js'; +import {reFormatTokens, parseDate} from '../lib/date-format.js'; +import {parseHTML} from '../lib/dom.js'; +import defaultOptions from './defaultOptions.js'; + +const { + language: defaultLang, + format: defaultFormat, + weekStart: defaultWeekStart, +} = defaultOptions; + +// Reducer function to filter out invalid day-of-week from the input +function sanitizeDOW(dow, day) { + return dow.length < 6 && day >= 0 && day < 7 + ? pushUnique(dow, day) + : dow; +} + +function calcEndOfWeek(startOfWeek) { + return (startOfWeek + 6) % 7; +} + +// validate input date. if invalid, fallback to the original value +function validateDate(value, format, locale, origValue) { + const date = parseDate(value, format, locale); + return date !== undefined ? date : origValue; +} + +// Validate viewId. if invalid, fallback to the original value +function validateViewId(value, origValue, max = 3) { + const viewId = parseInt(value, 10); + return viewId >= 0 && viewId <= max ? viewId : origValue; +} + +// Create Datepicker configuration to set +export default function processOptions(options, datepicker) { + const inOpts = Object.assign({}, options); + const config = {}; + const locales = datepicker.constructor.locales; + const rangeSideIndex = datepicker.rangeSideIndex; + let { + format, + language, + locale, + maxDate, + maxView, + minDate, + pickLevel, + startView, + weekStart, + } = datepicker.config || {}; + + if (inOpts.language) { + let lang; + if (inOpts.language !== language) { + if (locales[inOpts.language]) { + lang = inOpts.language; + } else { + // Check if langauge + region tag can fallback to the one without + // region (e.g. fr-CA → fr) + lang = inOpts.language.split('-')[0]; + if (locales[lang] === undefined) { + lang = false; + } + } + } + delete inOpts.language; + if (lang) { + language = config.language = lang; + + // update locale as well when updating language + const origLocale = locale || locales[defaultLang]; + // use default language's properties for the fallback + locale = Object.assign({ + format: defaultFormat, + weekStart: defaultWeekStart + }, locales[defaultLang]); + if (language !== defaultLang) { + Object.assign(locale, locales[language]); + } + config.locale = locale; + // if format and/or weekStart are the same as old locale's defaults, + // update them to new locale's defaults + if (format === origLocale.format) { + format = config.format = locale.format; + } + if (weekStart === origLocale.weekStart) { + weekStart = config.weekStart = locale.weekStart; + config.weekEnd = calcEndOfWeek(locale.weekStart); + } + } + } + + if (inOpts.format) { + const hasToDisplay = typeof inOpts.format.toDisplay === 'function'; + const hasToValue = typeof inOpts.format.toValue === 'function'; + const validFormatString = reFormatTokens.test(inOpts.format); + if ((hasToDisplay && hasToValue) || validFormatString) { + format = config.format = inOpts.format; + } + delete inOpts.format; + } + + //*** pick level ***// + let newPickLevel = pickLevel; + if (inOpts.pickLevel !== undefined) { + newPickLevel = validateViewId(inOpts.pickLevel, 2); + delete inOpts.pickLevel; + } + if (newPickLevel !== pickLevel) { + if (newPickLevel > pickLevel) { + // complement current minDate/madDate so that the existing range will be + // expanded to fit the new level later + if (inOpts.minDate === undefined) { + inOpts.minDate = minDate; + } + if (inOpts.maxDate === undefined) { + inOpts.maxDate = maxDate; + } + } + // complement datesDisabled so that it will be reset later + if (!inOpts.datesDisabled) { + inOpts.datesDisabled = []; + } + pickLevel = config.pickLevel = newPickLevel; + } + + //*** dates ***// + // while min and maxDate for "no limit" in the options are better to be null + // (especially when updating), the ones in the config have to be undefined + // because null is treated as 0 (= unix epoch) when comparing with time value + let minDt = minDate; + let maxDt = maxDate; + if (inOpts.minDate !== undefined) { + const defaultMinDt = dateValue(0, 0, 1); + minDt = inOpts.minDate === null + ? defaultMinDt // set 0000-01-01 to prevent negative values for year + : validateDate(inOpts.minDate, format, locale, minDt); + if (minDt !== defaultMinDt) { + minDt = regularizeDate(minDt, pickLevel, false); + } + delete inOpts.minDate; + } + if (inOpts.maxDate !== undefined) { + maxDt = inOpts.maxDate === null + ? undefined + : validateDate(inOpts.maxDate, format, locale, maxDt); + if (maxDt !== undefined) { + maxDt = regularizeDate(maxDt, pickLevel, true); + } + delete inOpts.maxDate; + } + if (maxDt < minDt) { + minDate = config.minDate = maxDt; + maxDate = config.maxDate = minDt; + } else { + if (minDate !== minDt) { + minDate = config.minDate = minDt; + } + if (maxDate !== maxDt) { + maxDate = config.maxDate = maxDt; + } + } + + if (inOpts.datesDisabled) { + config.datesDisabled = inOpts.datesDisabled.reduce((dates, dt) => { + const date = parseDate(dt, format, locale); + return date !== undefined + ? pushUnique(dates, regularizeDate(date, pickLevel, rangeSideIndex)) + : dates; + }, []); + delete inOpts.datesDisabled; + } + if (inOpts.defaultViewDate !== undefined) { + const viewDate = parseDate(inOpts.defaultViewDate, format, locale); + if (viewDate !== undefined) { + config.defaultViewDate = viewDate; + } + delete inOpts.defaultViewDate; + } + + //*** days of week ***// + if (inOpts.weekStart !== undefined) { + const wkStart = Number(inOpts.weekStart) % 7; + if (!isNaN(wkStart)) { + weekStart = config.weekStart = wkStart; + config.weekEnd = calcEndOfWeek(wkStart); + } + delete inOpts.weekStart; + } + if (inOpts.daysOfWeekDisabled) { + config.daysOfWeekDisabled = inOpts.daysOfWeekDisabled.reduce(sanitizeDOW, []); + delete inOpts.daysOfWeekDisabled; + } + if (inOpts.daysOfWeekHighlighted) { + config.daysOfWeekHighlighted = inOpts.daysOfWeekHighlighted.reduce(sanitizeDOW, []); + delete inOpts.daysOfWeekHighlighted; + } + + //*** multi date ***// + if (inOpts.maxNumberOfDates !== undefined) { + const maxNumberOfDates = parseInt(inOpts.maxNumberOfDates, 10); + if (maxNumberOfDates >= 0) { + config.maxNumberOfDates = maxNumberOfDates; + config.multidate = maxNumberOfDates !== 1; + } + delete inOpts.maxNumberOfDates; + } + if (inOpts.dateDelimiter) { + config.dateDelimiter = String(inOpts.dateDelimiter); + delete inOpts.dateDelimiter; + } + + //*** view ***// + let newMaxView = maxView; + if (inOpts.maxView !== undefined) { + newMaxView = validateViewId(inOpts.maxView, maxView); + delete inOpts.maxView; + } + // ensure max view >= pick level + newMaxView = pickLevel > newMaxView ? pickLevel : newMaxView; + if (newMaxView !== maxView) { + maxView = config.maxView = newMaxView; + } + + let newStartView = startView; + if (inOpts.startView !== undefined) { + newStartView = validateViewId(inOpts.startView, newStartView); + delete inOpts.startView; + } + // ensure pick level <= start view <= max view + if (newStartView < pickLevel) { + newStartView = pickLevel; + } else if (newStartView > maxView) { + newStartView = maxView; + } + if (newStartView !== startView) { + config.startView = newStartView; + } + + //*** template ***// + if (inOpts.prevArrow) { + const prevArrow = parseHTML(inOpts.prevArrow); + if (prevArrow.childNodes.length > 0) { + config.prevArrow = prevArrow.childNodes; + } + delete inOpts.prevArrow; + } + if (inOpts.nextArrow) { + const nextArrow = parseHTML(inOpts.nextArrow); + if (nextArrow.childNodes.length > 0) { + config.nextArrow = nextArrow.childNodes; + } + delete inOpts.nextArrow; + } + + //*** misc ***// + if (inOpts.disableTouchKeyboard !== undefined) { + config.disableTouchKeyboard = 'ontouchstart' in document && !!inOpts.disableTouchKeyboard; + delete inOpts.disableTouchKeyboard; + } + if (inOpts.orientation) { + const orientation = inOpts.orientation.toLowerCase().split(/\s+/g); + config.orientation = { + x: orientation.find(x => (x === 'left' || x === 'right')) || 'auto', + y: orientation.find(y => (y === 'top' || y === 'bottom')) || 'auto', + }; + delete inOpts.orientation; + } + if (inOpts.todayBtnMode !== undefined) { + switch(inOpts.todayBtnMode) { + case 0: + case 1: + config.todayBtnMode = inOpts.todayBtnMode; + } + delete inOpts.todayBtnMode; + } + + //*** copy the rest ***// + Object.keys(inOpts).forEach((key) => { + if (inOpts[key] !== undefined && hasProperty(defaultOptions, key)) { + config[key] = inOpts[key]; + } + }); + + return config; +} diff --git a/src/ui/static/js/datepicker/picker/Picker.js b/src/ui/static/js/datepicker/picker/Picker.js new file mode 100644 index 000000000..cbcfaaf71 --- /dev/null +++ b/src/ui/static/js/datepicker/picker/Picker.js @@ -0,0 +1,389 @@ +import {hasProperty, lastItemOf, isInRange, limitToRange} from '../lib/utils.js'; +import {today} from '../lib/date.js'; +import {parseHTML, getParent, showElement, hideElement, emptyChildNodes} from '../lib/dom.js'; +import {registerListeners} from '../lib/event.js'; +import pickerTemplate from './templates/pickerTemplate.js'; +import DaysView from './views/DaysView.js'; +import MonthsView from './views/MonthsView.js'; +import YearsView from './views/YearsView.js'; +import {triggerDatepickerEvent} from '../events/functions.js'; +import { + onClickTodayBtn, + onClickClearBtn, + onClickViewSwitch, + onClickPrevBtn, + onClickNextBtn, + onClickView, + onMousedownPicker, +} from '../events/pickerListeners.js'; + +const orientClasses = ['left', 'top', 'right', 'bottom'].reduce((obj, key) => { + obj[key] = `datepicker-orient-${key}`; + return obj; +}, {}); +const toPx = num => num ? `${num}px` : num; + +function processPickerOptions(picker, options) { + if (options.title !== undefined) { + if (options.title) { + picker.controls.title.textContent = options.title; + showElement(picker.controls.title); + } else { + picker.controls.title.textContent = ''; + hideElement(picker.controls.title); + } + } + if (options.prevArrow) { + const prevBtn = picker.controls.prevBtn; + emptyChildNodes(prevBtn); + options.prevArrow.forEach((node) => { + prevBtn.appendChild(node.cloneNode(true)); + }); + } + if (options.nextArrow) { + const nextBtn = picker.controls.nextBtn; + emptyChildNodes(nextBtn); + options.nextArrow.forEach((node) => { + nextBtn.appendChild(node.cloneNode(true)); + }); + } + if (options.locale) { + picker.controls.todayBtn.textContent = options.locale.today; + picker.controls.clearBtn.textContent = options.locale.clear; + } + if (options.todayBtn !== undefined) { + if (options.todayBtn) { + showElement(picker.controls.todayBtn); + } else { + hideElement(picker.controls.todayBtn); + } + } + if (hasProperty(options, 'minDate') || hasProperty(options, 'maxDate')) { + const {minDate, maxDate} = picker.datepicker.config; + picker.controls.todayBtn.disabled = !isInRange(today(), minDate, maxDate); + } + if (options.clearBtn !== undefined) { + if (options.clearBtn) { + showElement(picker.controls.clearBtn); + } else { + hideElement(picker.controls.clearBtn); + } + } +} + +// Compute view date to reset, which will be... +// - the last item of the selected dates or defaultViewDate if no selection +// - limitted to minDate or maxDate if it exceeds the range +function computeResetViewDate(datepicker) { + const {dates, config} = datepicker; + const viewDate = dates.length > 0 ? lastItemOf(dates) : config.defaultViewDate; + return limitToRange(viewDate, config.minDate, config.maxDate); +} + +// Change current view's view date +function setViewDate(picker, newDate) { + const oldViewDate = new Date(picker.viewDate); + const newViewDate = new Date(newDate); + const {id, year, first, last} = picker.currentView; + const viewYear = newViewDate.getFullYear(); + + picker.viewDate = newDate; + if (viewYear !== oldViewDate.getFullYear()) { + triggerDatepickerEvent(picker.datepicker, 'changeYear'); + } + if (newViewDate.getMonth() !== oldViewDate.getMonth()) { + triggerDatepickerEvent(picker.datepicker, 'changeMonth'); + } + + // return whether the new date is in different period on time from the one + // displayed in the current view + // when true, the view needs to be re-rendered on the next UI refresh. + switch (id) { + case 0: + return newDate < first || newDate > last; + case 1: + return viewYear !== year; + default: + return viewYear < first || viewYear > last; + } +} + +function getTextDirection(el) { + return window.getComputedStyle(el).direction; +} + +// find the closet scrollable ancestor elemnt under the body +function findScrollParents(el) { + const parent = getParent(el); + if (parent === document.body || !parent) { + return; + } + + // checking overflow only is enough because computed overflow cannot be + // visible or a combination of visible and other when either axis is set + // to other than visible. + // (Setting one axis to other than 'visible' while the other is 'visible' + // results in the other axis turning to 'auto') + return window.getComputedStyle(parent).overflow !== 'visible' + ? parent + : findScrollParents(parent); +} + +// Class representing the picker UI +export default class Picker { + constructor(datepicker) { + const {config} = this.datepicker = datepicker; + + const template = pickerTemplate.replace(/%buttonClass%/g, config.buttonClass); + const element = this.element = parseHTML(template).firstChild; + const [header, main, footer] = element.firstChild.children; + const title = header.firstElementChild; + const [prevBtn, viewSwitch, nextBtn] = header.lastElementChild.children; + const [todayBtn, clearBtn] = footer.firstChild.children; + const controls = { + title, + prevBtn, + viewSwitch, + nextBtn, + todayBtn, + clearBtn, + }; + this.main = main; + this.controls = controls; + + const elementClass = datepicker.inline ? 'inline' : 'dropdown'; + element.classList.add(`datepicker-${elementClass}`); + + processPickerOptions(this, config); + this.viewDate = computeResetViewDate(datepicker); + + // set up event listeners + registerListeners(datepicker, [ + [element, 'mousedown', onMousedownPicker], + [main, 'click', onClickView.bind(null, datepicker)], + [controls.viewSwitch, 'click', onClickViewSwitch.bind(null, datepicker)], + [controls.prevBtn, 'click', onClickPrevBtn.bind(null, datepicker)], + [controls.nextBtn, 'click', onClickNextBtn.bind(null, datepicker)], + [controls.todayBtn, 'click', onClickTodayBtn.bind(null, datepicker)], + [controls.clearBtn, 'click', onClickClearBtn.bind(null, datepicker)], + ]); + + // set up views + this.views = [ + new DaysView(this), + new MonthsView(this), + new YearsView(this, {id: 2, name: 'years', cellClass: 'year', step: 1}), + new YearsView(this, {id: 3, name: 'decades', cellClass: 'decade', step: 10}), + ]; + this.currentView = this.views[config.startView]; + + this.currentView.render(); + this.main.appendChild(this.currentView.element); + if (config.container) { + config.container.appendChild(this.element); + } else { + datepicker.inputField.after(this.element); + } + } + + setOptions(options) { + processPickerOptions(this, options); + this.views.forEach((view) => { + view.init(options, false); + }); + this.currentView.render(); + } + + detach() { + this.element.remove(); + } + + show() { + if (this.active) { + return; + } + + const {datepicker, element} = this; + if (datepicker.inline) { + element.classList.add('active'); + } else { + // ensure picker's direction matches input's + const inputDirection = getTextDirection(datepicker.inputField); + if (inputDirection !== getTextDirection(getParent(element))) { + element.dir = inputDirection; + } else if (element.dir) { + element.removeAttribute('dir'); + } + + element.style.visiblity = 'hidden'; + element.classList.add('active'); + this.place(); + element.style.visiblity = ''; + + if (datepicker.config.disableTouchKeyboard) { + datepicker.inputField.blur(); + } + } + this.active = true; + triggerDatepickerEvent(datepicker, 'show'); + } + + hide() { + if (!this.active) { + return; + } + this.datepicker.exitEditMode(); + this.element.classList.remove('active'); + this.active = false; + triggerDatepickerEvent(this.datepicker, 'hide'); + } + + place() { + const {classList, offsetParent, style} = this.element; + const {config, inputField} = this.datepicker; + const { + width: calendarWidth, + height: calendarHeight, + } = this.element.getBoundingClientRect(); + const { + left: inputLeft, + top: inputTop, + right: inputRight, + bottom: inputBottom, + width: inputWidth, + height: inputHeight + } = inputField.getBoundingClientRect(); + let {x: orientX, y: orientY} = config.orientation; + let left = inputLeft; + let top = inputTop; + + // caliculate offsetLeft/Top of inputField + if (offsetParent === document.body || !offsetParent) { + left += window.scrollX; + top += window.scrollY; + } else { + const offsetParentRect = offsetParent.getBoundingClientRect(); + left -= offsetParentRect.left - offsetParent.scrollLeft; + top -= offsetParentRect.top - offsetParent.scrollTop; + } + + // caliculate the boundaries of the visible area that contains inputField + const scrollParent = findScrollParents(inputField); + let scrollAreaLeft = 0; + let scrollAreaTop = 0; + let { + clientWidth: scrollAreaRight, + clientHeight: scrollAreaBottom, + } = document.documentElement; + + if (scrollParent) { + const scrollParentRect = scrollParent.getBoundingClientRect(); + if (scrollParentRect.top > 0) { + scrollAreaTop = scrollParentRect.top; + } + if (scrollParentRect.left > 0) { + scrollAreaLeft = scrollParentRect.left; + } + if (scrollParentRect.right < scrollAreaRight) { + scrollAreaRight = scrollParentRect.right; + } + if (scrollParentRect.bottom < scrollAreaBottom) { + scrollAreaBottom = scrollParentRect.bottom; + } + } + + // determine the horizontal orientation and left position + let adjustment = 0; + if (orientX === 'auto') { + if (inputLeft < scrollAreaLeft) { + orientX = 'left'; + adjustment = scrollAreaLeft - inputLeft; + } else if (inputLeft + calendarWidth > scrollAreaRight) { + orientX = 'right'; + if (scrollAreaRight < inputRight) { + adjustment = scrollAreaRight - inputRight; + } + } else if (getTextDirection(inputField) === 'rtl') { + orientX = inputRight - calendarWidth < scrollAreaLeft ? 'left' : 'right'; + } else { + orientX = 'left'; + } + } + if (orientX === 'right') { + left += inputWidth - calendarWidth; + } + left += adjustment; + + // determine the vertical orientation and top position + if (orientY === 'auto') { + if (inputTop - calendarHeight > scrollAreaTop) { + orientY = inputBottom + calendarHeight > scrollAreaBottom ? 'top' : 'bottom'; + } else { + orientY = 'bottom'; + } + } + if (orientY === 'top') { + top -= calendarHeight; + } else { + top += inputHeight; + } + + classList.remove(...Object.values(orientClasses)); + classList.add(orientClasses[orientX], orientClasses[orientY]); + + style.left = toPx(left); + style.top = toPx(top); + } + + setViewSwitchLabel(labelText) { + this.controls.viewSwitch.textContent = labelText; + } + + setPrevBtnDisabled(disabled) { + this.controls.prevBtn.disabled = disabled; + } + + setNextBtnDisabled(disabled) { + this.controls.nextBtn.disabled = disabled; + } + + changeView(viewId) { + const oldView = this.currentView; + const newView = this.views[viewId]; + if (newView.id !== oldView.id) { + this.currentView = newView; + this._renderMethod = 'render'; + triggerDatepickerEvent(this.datepicker, 'changeView'); + this.main.replaceChild(newView.element, oldView.element); + } + return this; + } + + // Change the focused date (view date) + changeFocus(newViewDate) { + this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refreshFocus'; + this.views.forEach((view) => { + view.updateFocus(); + }); + return this; + } + + // Apply the change of the selected dates + update() { + const newViewDate = computeResetViewDate(this.datepicker); + this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refresh'; + this.views.forEach((view) => { + view.updateFocus(); + view.updateSelection(); + }); + return this; + } + + // Refresh the picker UI + render(quickRender = true) { + const renderMethod = (quickRender && this._renderMethod) || 'render'; + delete this._renderMethod; + + this.currentView[renderMethod](); + } +} diff --git a/src/ui/static/js/datepicker/picker/templates/calendarWeeksTemplate.js b/src/ui/static/js/datepicker/picker/templates/calendarWeeksTemplate.js new file mode 100644 index 000000000..ca70ae727 --- /dev/null +++ b/src/ui/static/js/datepicker/picker/templates/calendarWeeksTemplate.js @@ -0,0 +1,8 @@ +import {createTagRepeat, optimizeTemplateHTML} from '../../lib/utils.js'; + +const calendarWeeksTemplate = optimizeTemplateHTML(`
+
+
${createTagRepeat('span', 6, {class: 'week'})}
+
`); + +export default calendarWeeksTemplate; diff --git a/src/ui/static/js/datepicker/picker/templates/daysTemplate.js b/src/ui/static/js/datepicker/picker/templates/daysTemplate.js new file mode 100644 index 000000000..c51c6d46d --- /dev/null +++ b/src/ui/static/js/datepicker/picker/templates/daysTemplate.js @@ -0,0 +1,8 @@ +import {createTagRepeat, optimizeTemplateHTML} from '../../lib/utils.js'; + +const daysTemplate = optimizeTemplateHTML(`
+
${createTagRepeat('span', 7, {class: 'dow'})}
+
${createTagRepeat('span', 42)}
+
`); + +export default daysTemplate; diff --git a/src/ui/static/js/datepicker/picker/templates/pickerTemplate.js b/src/ui/static/js/datepicker/picker/templates/pickerTemplate.js new file mode 100644 index 000000000..b389a4eb0 --- /dev/null +++ b/src/ui/static/js/datepicker/picker/templates/pickerTemplate.js @@ -0,0 +1,23 @@ +import {optimizeTemplateHTML} from '../../lib/utils.js'; + +const pickerTemplate = optimizeTemplateHTML(`
+
+
+
+
+ + + +
+
+
+ +
+
`); + +export default pickerTemplate; diff --git a/src/ui/static/js/datepicker/picker/views/DaysView.js b/src/ui/static/js/datepicker/picker/views/DaysView.js new file mode 100644 index 000000000..de3c33617 --- /dev/null +++ b/src/ui/static/js/datepicker/picker/views/DaysView.js @@ -0,0 +1,238 @@ +import {hasProperty, pushUnique} from '../../lib/utils.js'; +import {today, dateValue, addDays, addWeeks, dayOfTheWeekOf, getWeek} from '../../lib/date.js'; +import {formatDate} from '../../lib/date-format.js'; +import {parseHTML, showElement, hideElement} from '../../lib/dom.js'; +import daysTemplate from '../templates/daysTemplate.js'; +import calendarWeeksTemplate from '../templates/calendarWeeksTemplate.js'; +import View from './View.js'; + +export default class DaysView extends View { + constructor(picker) { + super(picker, { + id: 0, + name: 'days', + cellClass: 'day', + }); + } + + init(options, onConstruction = true) { + if (onConstruction) { + const inner = parseHTML(daysTemplate).firstChild; + this.dow = inner.firstChild; + this.grid = inner.lastChild; + this.element.appendChild(inner); + } + super.init(options); + } + + setOptions(options) { + let updateDOW; + + if (hasProperty(options, 'minDate')) { + this.minDate = options.minDate; + } + if (hasProperty(options, 'maxDate')) { + this.maxDate = options.maxDate; + } + if (options.datesDisabled) { + this.datesDisabled = options.datesDisabled; + } + if (options.daysOfWeekDisabled) { + this.daysOfWeekDisabled = options.daysOfWeekDisabled; + updateDOW = true; + } + if (options.daysOfWeekHighlighted) { + this.daysOfWeekHighlighted = options.daysOfWeekHighlighted; + } + if (options.todayHighlight !== undefined) { + this.todayHighlight = options.todayHighlight; + } + if (options.weekStart !== undefined) { + this.weekStart = options.weekStart; + this.weekEnd = options.weekEnd; + updateDOW = true; + } + if (options.locale) { + const locale = this.locale = options.locale; + this.dayNames = locale.daysMin; + this.switchLabelFormat = locale.titleFormat; + updateDOW = true; + } + if (options.beforeShowDay !== undefined) { + this.beforeShow = typeof options.beforeShowDay === 'function' + ? options.beforeShowDay + : undefined; + } + + if (options.calendarWeeks !== undefined) { + if (options.calendarWeeks && !this.calendarWeeks) { + const weeksElem = parseHTML(calendarWeeksTemplate).firstChild; + this.calendarWeeks = { + element: weeksElem, + dow: weeksElem.firstChild, + weeks: weeksElem.lastChild, + }; + this.element.insertBefore(weeksElem, this.element.firstChild); + } else if (this.calendarWeeks && !options.calendarWeeks) { + this.element.removeChild(this.calendarWeeks.element); + this.calendarWeeks = null; + } + } + if (options.showDaysOfWeek !== undefined) { + if (options.showDaysOfWeek) { + showElement(this.dow); + if (this.calendarWeeks) { + showElement(this.calendarWeeks.dow); + } + } else { + hideElement(this.dow); + if (this.calendarWeeks) { + hideElement(this.calendarWeeks.dow); + } + } + } + + // update days-of-week when locale, daysOfweekDisabled or weekStart is changed + if (updateDOW) { + Array.from(this.dow.children).forEach((el, index) => { + const dow = (this.weekStart + index) % 7; + el.textContent = this.dayNames[dow]; + el.className = this.daysOfWeekDisabled.includes(dow) ? 'dow disabled' : 'dow'; + }); + } + } + + // Apply update on the focused date to view's settings + updateFocus() { + const viewDate = new Date(this.picker.viewDate); + const viewYear = viewDate.getFullYear(); + const viewMonth = viewDate.getMonth(); + const firstOfMonth = dateValue(viewYear, viewMonth, 1); + const start = dayOfTheWeekOf(firstOfMonth, this.weekStart, this.weekStart); + + this.first = firstOfMonth; + this.last = dateValue(viewYear, viewMonth + 1, 0); + this.start = start; + this.focused = this.picker.viewDate; + } + + // Apply update on the selected dates to view's settings + updateSelection() { + const {dates, rangepicker} = this.picker.datepicker; + this.selected = dates; + if (rangepicker) { + this.range = rangepicker.dates; + } + } + + // Update the entire view UI + render() { + // update today marker on ever render + this.today = this.todayHighlight ? today() : undefined; + // refresh disabled dates on every render in order to clear the ones added + // by beforeShow hook at previous render + this.disabled = [...this.datesDisabled]; + + const switchLabel = formatDate(this.focused, this.switchLabelFormat, this.locale); + this.picker.setViewSwitchLabel(switchLabel); + this.picker.setPrevBtnDisabled(this.first <= this.minDate); + this.picker.setNextBtnDisabled(this.last >= this.maxDate); + + if (this.calendarWeeks) { + // start of the UTC week (Monday) of the 1st of the month + const startOfWeek = dayOfTheWeekOf(this.first, 1, 1); + Array.from(this.calendarWeeks.weeks.children).forEach((el, index) => { + el.textContent = getWeek(addWeeks(startOfWeek, index)); + }); + } + Array.from(this.grid.children).forEach((el, index) => { + const classList = el.classList; + const current = addDays(this.start, index); + const date = new Date(current); + const day = date.getDay(); + + el.className = `datepicker-cell ${this.cellClass}`; + el.dataset.date = current; + el.textContent = date.getDate(); + + if (current < this.first) { + classList.add('prev'); + } else if (current > this.last) { + classList.add('next'); + } + if (this.today === current) { + classList.add('today'); + } + if (current < this.minDate || current > this.maxDate || this.disabled.includes(current)) { + classList.add('disabled'); + } + if (this.daysOfWeekDisabled.includes(day)) { + classList.add('disabled'); + pushUnique(this.disabled, current); + } + if (this.daysOfWeekHighlighted.includes(day)) { + classList.add('highlighted'); + } + if (this.range) { + const [rangeStart, rangeEnd] = this.range; + if (current > rangeStart && current < rangeEnd) { + classList.add('range'); + } + if (current === rangeStart) { + classList.add('range-start'); + } + if (current === rangeEnd) { + classList.add('range-end'); + } + } + if (this.selected.includes(current)) { + classList.add('selected'); + } + if (current === this.focused) { + classList.add('focused'); + } + + if (this.beforeShow) { + this.performBeforeHook(el, current, current); + } + }); + } + + // Update the view UI by applying the changes of selected and focused items + refresh() { + const [rangeStart, rangeEnd] = this.range || []; + this.grid + .querySelectorAll('.range, .range-start, .range-end, .selected, .focused') + .forEach((el) => { + el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused'); + }); + Array.from(this.grid.children).forEach((el) => { + const current = Number(el.dataset.date); + const classList = el.classList; + if (current > rangeStart && current < rangeEnd) { + classList.add('range'); + } + if (current === rangeStart) { + classList.add('range-start'); + } + if (current === rangeEnd) { + classList.add('range-end'); + } + if (this.selected.includes(current)) { + classList.add('selected'); + } + if (current === this.focused) { + classList.add('focused'); + } + }); + } + + // Update the view UI by applying the change of focused item + refreshFocus() { + const index = Math.round((this.focused - this.start) / 86400000); + this.grid.querySelectorAll('.focused').forEach((el) => { + el.classList.remove('focused'); + }); + this.grid.children[index].classList.add('focused'); + } +} diff --git a/src/ui/static/js/datepicker/picker/views/MonthsView.js b/src/ui/static/js/datepicker/picker/views/MonthsView.js new file mode 100644 index 000000000..af4f6432c --- /dev/null +++ b/src/ui/static/js/datepicker/picker/views/MonthsView.js @@ -0,0 +1,210 @@ +import {hasProperty, pushUnique, createTagRepeat} from '../../lib/utils.js'; +import {dateValue} from '../../lib/date.js'; +import {parseHTML} from '../../lib/dom.js'; +import View from './View.js'; + +function computeMonthRange(range, thisYear) { + if (!range || !range[0] || !range[1]) { + return; + } + + const [[startY, startM], [endY, endM]] = range; + if (startY > thisYear || endY < thisYear) { + return; + } + return [ + startY === thisYear ? startM : -1, + endY === thisYear ? endM : 12, + ]; +} + +export default class MonthsView extends View { + constructor(picker) { + super(picker, { + id: 1, + name: 'months', + cellClass: 'month', + }); + } + + init(options, onConstruction = true) { + if (onConstruction) { + this.grid = this.element; + this.element.classList.add('months', 'datepicker-grid'); + this.grid.appendChild(parseHTML(createTagRepeat('span', 12, {'data-month': ix => ix}))); + } + super.init(options); + } + + setOptions(options) { + if (options.locale) { + this.monthNames = options.locale.monthsShort; + } + if (hasProperty(options, 'minDate')) { + if (options.minDate === undefined) { + this.minYear = this.minMonth = this.minDate = undefined; + } else { + const minDateObj = new Date(options.minDate); + this.minYear = minDateObj.getFullYear(); + this.minMonth = minDateObj.getMonth(); + this.minDate = minDateObj.setDate(1); + } + } + if (hasProperty(options, 'maxDate')) { + if (options.maxDate === undefined) { + this.maxYear = this.maxMonth = this.maxDate = undefined; + } else { + const maxDateObj = new Date(options.maxDate); + this.maxYear = maxDateObj.getFullYear(); + this.maxMonth = maxDateObj.getMonth(); + this.maxDate = dateValue(this.maxYear, this.maxMonth + 1, 0); + } + } + if (this.isMinView) { + if (options.datesDisabled) { + this.datesDisabled = options.datesDisabled; + } + } else { + this.datesDisabled = []; + } + if (options.beforeShowMonth !== undefined) { + this.beforeShow = typeof options.beforeShowMonth === 'function' + ? options.beforeShowMonth + : undefined; + } + } + + // Update view's settings to reflect the viewDate set on the picker + updateFocus() { + const viewDate = new Date(this.picker.viewDate); + this.year = viewDate.getFullYear(); + this.focused = viewDate.getMonth(); + } + + // Update view's settings to reflect the selected dates + updateSelection() { + const {dates, rangepicker} = this.picker.datepicker; + this.selected = dates.reduce((selected, timeValue) => { + const date = new Date(timeValue); + const year = date.getFullYear(); + const month = date.getMonth(); + if (selected[year] === undefined) { + selected[year] = [month]; + } else { + pushUnique(selected[year], month); + } + return selected; + }, {}); + if (rangepicker && rangepicker.dates) { + this.range = rangepicker.dates.map(timeValue => { + const date = new Date(timeValue); + return isNaN(date) ? undefined : [date.getFullYear(), date.getMonth()]; + }); + } + } + + // Update the entire view UI + render() { + // refresh disabled months on every render in order to clear the ones added + // by beforeShow hook at previous render + // this.disabled = [...this.datesDisabled]; + this.disabled = this.datesDisabled.reduce((arr, disabled) => { + const dt = new Date(disabled); + if (this.year === dt.getFullYear()) { + arr.push(dt.getMonth()); + } + return arr; + }, []); + + this.picker.setViewSwitchLabel(this.year); + this.picker.setPrevBtnDisabled(this.year <= this.minYear); + this.picker.setNextBtnDisabled(this.year >= this.maxYear); + + const selected = this.selected[this.year] || []; + const yrOutOfRange = this.year < this.minYear || this.year > this.maxYear; + const isMinYear = this.year === this.minYear; + const isMaxYear = this.year === this.maxYear; + const range = computeMonthRange(this.range, this.year); + + Array.from(this.grid.children).forEach((el, index) => { + const classList = el.classList; + const date = dateValue(this.year, index, 1); + + el.className = `datepicker-cell ${this.cellClass}`; + if (this.isMinView) { + el.dataset.date = date; + } + // reset text on every render to clear the custom content set + // by beforeShow hook at previous render + el.textContent = this.monthNames[index]; + + if ( + yrOutOfRange + || isMinYear && index < this.minMonth + || isMaxYear && index > this.maxMonth + || this.disabled.includes(index) + ) { + classList.add('disabled'); + } + if (range) { + const [rangeStart, rangeEnd] = range; + if (index > rangeStart && index < rangeEnd) { + classList.add('range'); + } + if (index === rangeStart) { + classList.add('range-start'); + } + if (index === rangeEnd) { + classList.add('range-end'); + } + } + if (selected.includes(index)) { + classList.add('selected'); + } + if (index === this.focused) { + classList.add('focused'); + } + + if (this.beforeShow) { + this.performBeforeHook(el, index, date); + } + }); + } + + // Update the view UI by applying the changes of selected and focused items + refresh() { + const selected = this.selected[this.year] || []; + const [rangeStart, rangeEnd] = computeMonthRange(this.range, this.year) || []; + this.grid + .querySelectorAll('.range, .range-start, .range-end, .selected, .focused') + .forEach((el) => { + el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused'); + }); + Array.from(this.grid.children).forEach((el, index) => { + const classList = el.classList; + if (index > rangeStart && index < rangeEnd) { + classList.add('range'); + } + if (index === rangeStart) { + classList.add('range-start'); + } + if (index === rangeEnd) { + classList.add('range-end'); + } + if (selected.includes(index)) { + classList.add('selected'); + } + if (index === this.focused) { + classList.add('focused'); + } + }); + } + + // Update the view UI by applying the change of focused item + refreshFocus() { + this.grid.querySelectorAll('.focused').forEach((el) => { + el.classList.remove('focused'); + }); + this.grid.children[this.focused].classList.add('focused'); + } +} \ No newline at end of file diff --git a/src/ui/static/js/datepicker/picker/views/View.js b/src/ui/static/js/datepicker/picker/views/View.js new file mode 100644 index 000000000..fe9123136 --- /dev/null +++ b/src/ui/static/js/datepicker/picker/views/View.js @@ -0,0 +1,55 @@ +import {pushUnique} from '../../lib/utils.js'; +import {parseHTML, replaceChildNodes} from '../../lib/dom.js'; + +// Base class of the view classes +export default class View { + constructor(picker, config) { + Object.assign(this, config, { + picker, + element: parseHTML(`
`).firstChild, + selected: [], + }); + this.init(this.picker.datepicker.config); + } + + init(options) { + if (options.pickLevel !== undefined) { + this.isMinView = this.id === options.pickLevel; + } + this.setOptions(options); + this.updateFocus(); + this.updateSelection(); + } + + // Execute beforeShow() callback and apply the result to the element + // args: + // - current - current value on the iteration on view rendering + // - timeValue - time value of the date to pass to beforeShow() + performBeforeHook(el, current, timeValue) { + let result = this.beforeShow(new Date(timeValue)); + switch (typeof result) { + case 'boolean': + result = {enabled: result}; + break; + case 'string': + result = {classes: result}; + } + + if (result) { + if (result.enabled === false) { + el.classList.add('disabled'); + pushUnique(this.disabled, current); + } + if (result.classes) { + const extraClasses = result.classes.split(/\s+/); + el.classList.add(...extraClasses); + if (extraClasses.includes('disabled')) { + pushUnique(this.disabled, current); + } + } + if (result.content) { + replaceChildNodes(el, result.content); + } + } + } +} diff --git a/src/ui/static/js/datepicker/picker/views/YearsView.js b/src/ui/static/js/datepicker/picker/views/YearsView.js new file mode 100644 index 000000000..5faed1f91 --- /dev/null +++ b/src/ui/static/js/datepicker/picker/views/YearsView.js @@ -0,0 +1,176 @@ +import {hasProperty, pushUnique, createTagRepeat} from '../../lib/utils.js'; +import {dateValue, startOfYearPeriod} from '../../lib/date.js'; +import {parseHTML} from '../../lib/dom.js'; +import View from './View.js'; + +function toTitleCase(word) { + return [...word].reduce((str, ch, ix) => str += ix ? ch : ch.toUpperCase(), ''); +} + +// Class representing the years and decades view elements +export default class YearsView extends View { + constructor(picker, config) { + super(picker, config); + } + + init(options, onConstruction = true) { + if (onConstruction) { + this.navStep = this.step * 10; + this.beforeShowOption = `beforeShow${toTitleCase(this.cellClass)}`; + this.grid = this.element; + this.element.classList.add(this.name, 'datepicker-grid'); + this.grid.appendChild(parseHTML(createTagRepeat('span', 12))); + } + super.init(options); + } + + setOptions(options) { + if (hasProperty(options, 'minDate')) { + if (options.minDate === undefined) { + this.minYear = this.minDate = undefined; + } else { + this.minYear = startOfYearPeriod(options.minDate, this.step); + this.minDate = dateValue(this.minYear, 0, 1); + } + } + if (hasProperty(options, 'maxDate')) { + if (options.maxDate === undefined) { + this.maxYear = this.maxDate = undefined; + } else { + this.maxYear = startOfYearPeriod(options.maxDate, this.step); + this.maxDate = dateValue(this.maxYear, 11, 31); + } + } + if (this.isMinView) { + if (options.datesDisabled) { + this.datesDisabled = options.datesDisabled; + } + } else { + this.datesDisabled = []; + } + if (options[this.beforeShowOption] !== undefined) { + const beforeShow = options[this.beforeShowOption]; + this.beforeShow = typeof beforeShow === 'function' ? beforeShow : undefined; + } + } + + // Update view's settings to reflect the viewDate set on the picker + updateFocus() { + const viewDate = new Date(this.picker.viewDate); + const first = startOfYearPeriod(viewDate, this.navStep); + const last = first + 9 * this.step; + + this.first = first; + this.last = last; + this.start = first - this.step; + this.focused = startOfYearPeriod(viewDate, this.step); + } + + // Update view's settings to reflect the selected dates + updateSelection() { + const {dates, rangepicker} = this.picker.datepicker; + this.selected = dates.reduce((years, timeValue) => { + return pushUnique(years, startOfYearPeriod(timeValue, this.step)); + }, []); + if (rangepicker && rangepicker.dates) { + this.range = rangepicker.dates.map(timeValue => { + if (timeValue !== undefined) { + return startOfYearPeriod(timeValue, this.step); + } + }); + } + } + + // Update the entire view UI + render() { + // refresh disabled years on every render in order to clear the ones added + // by beforeShow hook at previous render + // this.disabled = [...this.datesDisabled]; + this.disabled = this.datesDisabled.map(disabled => new Date(disabled).getFullYear()); + + this.picker.setViewSwitchLabel(`${this.first}-${this.last}`); + this.picker.setPrevBtnDisabled(this.first <= this.minYear); + this.picker.setNextBtnDisabled(this.last >= this.maxYear); + + Array.from(this.grid.children).forEach((el, index) => { + const classList = el.classList; + const current = this.start + (index * this.step); + const date = dateValue(current, 0, 1); + + el.className = `datepicker-cell ${this.cellClass}`; + if (this.isMinView) { + el.dataset.date = date; + } + el.textContent = el.dataset.year = current; + + if (index === 0) { + classList.add('prev'); + } else if (index === 11) { + classList.add('next'); + } + if (current < this.minYear || current > this.maxYear || this.disabled.includes(current)) { + classList.add('disabled'); + } + if (this.range) { + const [rangeStart, rangeEnd] = this.range; + if (current > rangeStart && current < rangeEnd) { + classList.add('range'); + } + if (current === rangeStart) { + classList.add('range-start'); + } + if (current === rangeEnd) { + classList.add('range-end'); + } + } + if (this.selected.includes(current)) { + classList.add('selected'); + } + if (current === this.focused) { + classList.add('focused'); + } + + if (this.beforeShow) { + this.performBeforeHook(el, current, date); + } + }); + } + + // Update the view UI by applying the changes of selected and focused items + refresh() { + const [rangeStart, rangeEnd] = this.range || []; + this.grid + .querySelectorAll('.range, .range-start, .range-end, .selected, .focused') + .forEach((el) => { + el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused'); + }); + Array.from(this.grid.children).forEach((el) => { + const current = Number(el.textContent); + const classList = el.classList; + if (current > rangeStart && current < rangeEnd) { + classList.add('range'); + } + if (current === rangeStart) { + classList.add('range-start'); + } + if (current === rangeEnd) { + classList.add('range-end'); + } + if (this.selected.includes(current)) { + classList.add('selected'); + } + if (current === this.focused) { + classList.add('focused'); + } + }); + } + + // Update the view UI by applying the change of focused item + refreshFocus() { + const index = Math.round((this.focused - this.start) / this.step); + this.grid.querySelectorAll('.focused').forEach((el) => { + el.classList.remove('focused'); + }); + this.grid.children[index].classList.add('focused'); + } +} diff --git a/src/ui/static/js/dropzone/dropzone-min.js b/src/ui/static/js/dropzone/dropzone-min.js index cfced1204..e14ac2316 100644 --- a/src/ui/static/js/dropzone/dropzone-min.js +++ b/src/ui/static/js/dropzone/dropzone-min.js @@ -1,2 +1,2881 @@ -!function(){function e(e){return e&&e.__esModule?e.default:e}function t(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){for(var i=0;i1?t-1:0),n=1;n'),this.element.appendChild(e));var l=e.getElementsByTagName("span")[0];return l&&(null!=l.textContent?l.textContent=this.options.dictFallbackMessage:null!=l.innerText&&(l.innerText=this.options.dictFallbackMessage)),this.element.appendChild(this.getFallbackForm())},resize:function(e,t,i,n){var r={srcX:0,srcY:0,srcWidth:e.width,srcHeight:e.height},a=e.width/e.height;null==t&&null==i?(t=r.srcWidth,i=r.srcHeight):null==t?t=i*a:null==i&&(i=t/a);var o=(t=Math.min(t,r.srcWidth))/(i=Math.min(i,r.srcHeight));if(r.srcWidth>t||r.srcHeight>i)if("crop"===n)a>o?(r.srcHeight=e.height,r.srcWidth=r.srcHeight*o):(r.srcWidth=e.width,r.srcHeight=r.srcWidth/o);else{if("contain"!==n)throw new Error("Unknown resizeMethod '".concat(n,"'"));a>o?i=t/a:t=i*a}return r.srcX=(e.width-r.srcWidth)/2,r.srcY=(e.height-r.srcHeight)/2,r.trgWidth=t,r.trgHeight=i,r},transformFile:function(e,t){return(this.options.resizeWidth||this.options.resizeHeight)&&e.type.match(/image.*/)?this.resizeImage(e,this.options.resizeWidth,this.options.resizeHeight,this.options.resizeMethod,t):t(e)},previewTemplate:e('
'),drop:function(e){return this.element.classList.remove("dz-drag-hover")},dragstart:function(e){},dragend:function(e){return this.element.classList.remove("dz-drag-hover")},dragenter:function(e){return this.element.classList.add("dz-drag-hover")},dragover:function(e){return this.element.classList.add("dz-drag-hover")},dragleave:function(e){return this.element.classList.remove("dz-drag-hover")},paste:function(e){},reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(e){if(this.element===this.previewsContainer&&this.element.classList.add("dz-started"),this.previewsContainer&&!this.options.disablePreviews){var t=this;e.previewElement=f.createElement(this.options.previewTemplate.trim()),e.previewTemplate=e.previewElement,this.previewsContainer.appendChild(e.previewElement);var i=!0,n=!1,r=void 0;try{for(var a,o=e.previewElement.querySelectorAll("[data-dz-name]")[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){var l=a.value;l.textContent=e.name}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}var s=!0,u=!1,c=void 0;try{for(var d,h=e.previewElement.querySelectorAll("[data-dz-size]")[Symbol.iterator]();!(s=(d=h.next()).done);s=!0)(l=d.value).innerHTML=this.filesize(e.size)}catch(e){u=!0,c=e}finally{try{s||null==h.return||h.return()}finally{if(u)throw c}}this.options.addRemoveLinks&&(e._removeLink=f.createElement(''.concat(this.options.dictRemoveFile,"")),e.previewElement.appendChild(e._removeLink));var p=function(i){var n=t;if(i.preventDefault(),i.stopPropagation(),e.status===f.UPLOADING)return f.confirm(t.options.dictCancelUploadConfirmation,(function(){return n.removeFile(e)}));var r=t;return t.options.dictRemoveFileConfirmation?f.confirm(t.options.dictRemoveFileConfirmation,(function(){return r.removeFile(e)})):t.removeFile(e)},m=!0,v=!1,y=void 0;try{for(var g,b=e.previewElement.querySelectorAll("[data-dz-remove]")[Symbol.iterator]();!(m=(g=b.next()).done);m=!0){g.value.addEventListener("click",p)}}catch(e){v=!0,y=e}finally{try{m||null==b.return||b.return()}finally{if(v)throw y}}}},removedfile:function(e){return null!=e.previewElement&&null!=e.previewElement.parentNode&&e.previewElement.parentNode.removeChild(e.previewElement),this._updateMaxFilesReachedClass()},thumbnail:function(e,t){if(e.previewElement){e.previewElement.classList.remove("dz-file-preview");var i=!0,n=!1,r=void 0;try{for(var a,o=e.previewElement.querySelectorAll("[data-dz-thumbnail]")[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){var l=a.value;l.alt=e.name,l.src=t}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}return setTimeout((function(){return e.previewElement.classList.add("dz-image-preview")}),1)}},error:function(e,t){if(e.previewElement){e.previewElement.classList.add("dz-error"),"string"!=typeof t&&t.error&&(t=t.error);var i=!0,n=!1,r=void 0;try{for(var a,o=e.previewElement.querySelectorAll("[data-dz-errormessage]")[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){a.value.textContent=t}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}}},errormultiple:function(){},processing:function(e){if(e.previewElement&&(e.previewElement.classList.add("dz-processing"),e._removeLink))return e._removeLink.innerHTML=this.options.dictCancelUpload},processingmultiple:function(){},uploadprogress:function(e,t,i){var n=!0,r=!1,a=void 0;if(e.previewElement)try{for(var o,l=e.previewElement.querySelectorAll("[data-dz-uploadprogress]")[Symbol.iterator]();!(n=(o=l.next()).done);n=!0){var s=o.value;"PROGRESS"===s.nodeName?s.value=t:s.style.width="".concat(t,"%")}}catch(e){r=!0,a=e}finally{try{n||null==l.return||l.return()}finally{if(r)throw a}}},totaluploadprogress:function(){},sending:function(){},sendingmultiple:function(){},success:function(e){if(e.previewElement)return e.previewElement.classList.add("dz-success")},successmultiple:function(){},canceled:function(e){return this.emit("error",e,this.options.dictUploadCanceled)},canceledmultiple:function(){},complete:function(e){if(e._removeLink&&(e._removeLink.innerHTML=this.options.dictRemoveFile),e.previewElement)return e.previewElement.classList.add("dz-complete")},completemultiple:function(){},maxfilesexceeded:function(){},maxfilesreached:function(){},queuecomplete:function(){},addedfiles:function(){}},f=function(n){"use strict";function o(n,r){var l,c,d,h;if(i(this,o),(l=s(this,(c=o,a(c)).call(this))).element=n,l.clickableElements=[],l.listeners=[],l.files=[],"string"==typeof l.element&&(l.element=document.querySelector(l.element)),!l.element||null==l.element.nodeType)throw new Error("Invalid dropzone element.");if(l.element.dropzone)throw new Error("Dropzone already attached.");o.instances.push(t(l)),l.element.dropzone=t(l);var f=null!=(h=o.optionsForElement(l.element))?h:{};if(l.options=e(u)(!0,{},p,f,null!=r?r:{}),l.options.previewTemplate=l.options.previewTemplate.replace(/\n*/g,""),l.options.forceFallback||!o.isBrowserSupported())return s(l,l.options.fallback.call(t(l)));if(null==l.options.url&&(l.options.url=l.element.getAttribute("action")),!l.options.url)throw new Error("No URL provided.");if(l.options.acceptedFiles&&l.options.acceptedMimeTypes)throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");if(l.options.uploadMultiple&&l.options.chunking)throw new Error("You cannot set both: uploadMultiple and chunking.");if(l.options.binaryBody&&l.options.uploadMultiple)throw new Error("You cannot set both: binaryBody and uploadMultiple.");return l.options.acceptedMimeTypes&&(l.options.acceptedFiles=l.options.acceptedMimeTypes,delete l.options.acceptedMimeTypes),null!=l.options.renameFilename&&(l.options.renameFile=function(e){return l.options.renameFilename.call(t(l),e.name,e)}),"string"==typeof l.options.method&&(l.options.method=l.options.method.toUpperCase()),(d=l.getExistingFallback())&&d.parentNode&&d.parentNode.removeChild(d),!1!==l.options.previewsContainer&&(l.options.previewsContainer?l.previewsContainer=o.getElement(l.options.previewsContainer,"previewsContainer"):l.previewsContainer=l.element),l.options.clickable&&(!0===l.options.clickable?l.clickableElements=[l.element]:l.clickableElements=o.getElements(l.options.clickable,"clickable")),l.init(),l}return l(o,n),r(o,[{key:"getAcceptedFiles",value:function(){return this.files.filter((function(e){return e.accepted})).map((function(e){return e}))}},{key:"getRejectedFiles",value:function(){return this.files.filter((function(e){return!e.accepted})).map((function(e){return e}))}},{key:"getFilesWithStatus",value:function(e){return this.files.filter((function(t){return t.status===e})).map((function(e){return e}))}},{key:"getQueuedFiles",value:function(){return this.getFilesWithStatus(o.QUEUED)}},{key:"getUploadingFiles",value:function(){return this.getFilesWithStatus(o.UPLOADING)}},{key:"getAddedFiles",value:function(){return this.getFilesWithStatus(o.ADDED)}},{key:"getActiveFiles",value:function(){return this.files.filter((function(e){return e.status===o.UPLOADING||e.status===o.QUEUED})).map((function(e){return e}))}},{key:"init",value:function(){var e=this,t=this,i=this,n=this,r=this,a=this,l=this,s=this,u=this,c=this,d=this;if("form"===this.element.tagName&&this.element.setAttribute("enctype","multipart/form-data"),this.element.classList.contains("dropzone")&&!this.element.querySelector(".dz-message")&&this.element.appendChild(o.createElement('
"))),this.clickableElements.length){var h=this,p=function(){var e=h;h.hiddenFileInput&&h.hiddenFileInput.parentNode.removeChild(h.hiddenFileInput),h.hiddenFileInput=document.createElement("input"),h.hiddenFileInput.setAttribute("type","file"),(null===h.options.maxFiles||h.options.maxFiles>1)&&h.hiddenFileInput.setAttribute("multiple","multiple"),h.hiddenFileInput.className="dz-hidden-input",null!==h.options.acceptedFiles&&h.hiddenFileInput.setAttribute("accept",h.options.acceptedFiles),null!==h.options.capture&&h.hiddenFileInput.setAttribute("capture",h.options.capture),h.hiddenFileInput.setAttribute("tabindex","-1"),h.hiddenFileInput.style.visibility="hidden",h.hiddenFileInput.style.position="absolute",h.hiddenFileInput.style.top="0",h.hiddenFileInput.style.left="0",h.hiddenFileInput.style.height="0",h.hiddenFileInput.style.width="0",o.getElement(h.options.hiddenInputContainer,"hiddenInputContainer").appendChild(h.hiddenFileInput),h.hiddenFileInput.addEventListener("change",(function(){var t=e.hiddenFileInput.files,i=!0,n=!1,r=void 0;if(t.length)try{for(var a,o=t[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){var l=a.value;e.addFile(l)}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}e.emit("addedfiles",t),p()}))};p()}this.URL=null!==window.URL?window.URL:window.webkitURL;var f=!0,m=!1,v=void 0;try{for(var y,g=this.events[Symbol.iterator]();!(f=(y=g.next()).done);f=!0){var b=y.value;this.on(b,this.options[b])}}catch(e){m=!0,v=e}finally{try{f||null==g.return||g.return()}finally{if(m)throw v}}this.on("uploadprogress",(function(){return e.updateTotalUploadProgress()})),this.on("removedfile",(function(){return t.updateTotalUploadProgress()})),this.on("canceled",(function(e){return i.emit("complete",e)})),this.on("complete",(function(e){var t=n;if(0===n.getAddedFiles().length&&0===n.getUploadingFiles().length&&0===n.getQueuedFiles().length)return setTimeout((function(){return t.emit("queuecomplete")}),0)}));var k=function(e){if(function(e){if(e.dataTransfer.types)for(var t=0;t")),i+='');var n=o.createElement(i);return"FORM"!==this.element.tagName?(t=o.createElement('
'))).appendChild(n):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method)),null!=t?t:n}},{key:"getExistingFallback",value:function(){var e=function(e){var t=!0,i=!1,n=void 0;try{for(var r,a=e[Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var o=r.value;if(/(^| )fallback($| )/.test(o.className))return o}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}},t=!0,i=!1,n=void 0;try{for(var r,a=["div","form"][Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var o,l=r.value;if(o=e(this.element.getElementsByTagName(l)))return o}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}}},{key:"setupEventListeners",value:function(){return this.listeners.map((function(e){return function(){var t=[];for(var i in e.events){var n=e.events[i];t.push(e.element.addEventListener(i,n,!1))}return t}()}))}},{key:"removeEventListeners",value:function(){return this.listeners.map((function(e){return function(){var t=[];for(var i in e.events){var n=e.events[i];t.push(e.element.removeEventListener(i,n,!1))}return t}()}))}},{key:"disable",value:function(){var e=this;return this.clickableElements.forEach((function(e){return e.classList.remove("dz-clickable")})),this.removeEventListeners(),this.disabled=!0,this.files.map((function(t){return e.cancelUpload(t)}))}},{key:"enable",value:function(){return delete this.disabled,this.clickableElements.forEach((function(e){return e.classList.add("dz-clickable")})),this.setupEventListeners()}},{key:"filesize",value:function(e){var t=0,i="b";if(e>0){for(var n=["tb","gb","mb","kb","b"],r=0;r=Math.pow(this.options.filesizeBase,4-r)/10){t=e/Math.pow(this.options.filesizeBase,4-r),i=a;break}}t=Math.round(10*t)/10}return"".concat(t," ").concat(this.options.dictFileSizeUnits[i])}},{key:"_updateMaxFilesReachedClass",value:function(){return null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(this.getAcceptedFiles().length===this.options.maxFiles&&this.emit("maxfilesreached",this.files),this.element.classList.add("dz-max-files-reached")):this.element.classList.remove("dz-max-files-reached")}},{key:"drop",value:function(e){if(e.dataTransfer){this.emit("drop",e);for(var t=[],i=0;i0){var n=!0,r=!1,o=void 0;try{for(var l,s=i[Symbol.iterator]();!(n=(l=s.next()).done);n=!0){var u=l.value,c=e;u.isFile?u.file((function(e){if(!c.options.ignoreHiddenFiles||"."!==e.name.substring(0,1))return e.fullPath="".concat(t,"/").concat(e.name),c.addFile(e)})):u.isDirectory&&e._addFilesFromDirectory(u,"".concat(t,"/").concat(u.name))}}catch(e){r=!0,o=e}finally{try{n||null==s.return||s.return()}finally{if(r)throw o}}a()}return null}),r)};return a()}},{key:"accept",value:function(e,t){this.options.maxFilesize&&e.size>1048576*this.options.maxFilesize?t(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(e.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):o.isValidFile(e,this.options.acceptedFiles)?null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(t(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles)),this.emit("maxfilesexceeded",e)):this.options.accept.call(this,e,t):t(this.options.dictInvalidFileType)}},{key:"addFile",value:function(e){var t=this;e.upload={uuid:o.uuidv4(),progress:0,total:e.size,bytesSent:0,filename:this._renameFile(e)},this.files.push(e),e.status=o.ADDED,this.emit("addedfile",e),this._enqueueThumbnail(e),this.accept(e,(function(i){i?(e.accepted=!1,t._errorProcessing([e],i)):(e.accepted=!0,t.options.autoQueue&&t.enqueueFile(e)),t._updateMaxFilesReachedClass()}))}},{key:"enqueueFiles",value:function(e){var t=!0,i=!1,n=void 0;try{for(var r,a=e[Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var o=r.value;this.enqueueFile(o)}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}return null}},{key:"enqueueFile",value:function(e){if(e.status!==o.ADDED||!0!==e.accepted)throw new Error("This file can't be queued because it has already been processed or was rejected.");var t=this;if(e.status=o.QUEUED,this.options.autoProcessQueue)return setTimeout((function(){return t.processQueue()}),0)}},{key:"_enqueueThumbnail",value:function(e){if(this.options.createImageThumbnails&&e.type.match(/image.*/)&&e.size<=1048576*this.options.maxThumbnailFilesize){var t=this;return this._thumbnailQueue.push(e),setTimeout((function(){return t._processThumbnailQueue()}),0)}}},{key:"_processThumbnailQueue",value:function(){var e=this;if(!this._processingThumbnail&&0!==this._thumbnailQueue.length){this._processingThumbnail=!0;var t=this._thumbnailQueue.shift();return this.createThumbnail(t,this.options.thumbnailWidth,this.options.thumbnailHeight,this.options.thumbnailMethod,!0,(function(i){return e.emit("thumbnail",t,i),e._processingThumbnail=!1,e._processThumbnailQueue()}))}}},{key:"removeFile",value:function(e){if(e.status===o.UPLOADING&&this.cancelUpload(e),this.files=m(this.files,e),this.emit("removedfile",e),0===this.files.length)return this.emit("reset")}},{key:"removeAllFiles",value:function(e){null==e&&(e=!1);var t=!0,i=!1,n=void 0;try{for(var r,a=this.files.slice()[Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var l=r.value;(l.status!==o.UPLOADING||e)&&this.removeFile(l)}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}return null}},{key:"resizeImage",value:function(e,t,i,n,r){var a=this;return this.createThumbnail(e,t,i,n,!0,(function(t,i){if(null==i)return r(e);var n=a.options.resizeMimeType;null==n&&(n=e.type);var l=i.toDataURL(n,a.options.resizeQuality);return"image/jpeg"!==n&&"image/jpg"!==n||(l=g.restore(e.dataURL,l)),r(o.dataURItoBlob(l))}))}},{key:"createThumbnail",value:function(e,t,i,n,r,a){var o=this,l=new FileReader;l.onload=function(){e.dataURL=l.result,"image/svg+xml"!==e.type?o.createThumbnailFromUrl(e,t,i,n,r,a):null!=a&&a(l.result)},l.readAsDataURL(e)}},{key:"displayExistingFile",value:function(e,t,i,n,r){var a=void 0===r||r;if(this.emit("addedfile",e),this.emit("complete",e),a){var o=this;e.dataURL=t,this.createThumbnailFromUrl(e,this.options.thumbnailWidth,this.options.thumbnailHeight,this.options.thumbnailMethod,this.options.fixOrientation,(function(t){o.emit("thumbnail",e,t),i&&i()}),n)}else this.emit("thumbnail",e,t),i&&i()}},{key:"createThumbnailFromUrl",value:function(e,t,i,n,r,a,o){var l=this,s=document.createElement("img");return o&&(s.crossOrigin=o),r="from-image"!=getComputedStyle(document.body).imageOrientation&&r,s.onload=function(){var o=l,u=function(e){return e(1)};return"undefined"!=typeof EXIF&&null!==EXIF&&r&&(u=function(e){return EXIF.getData(s,(function(){return e(EXIF.getTag(this,"Orientation"))}))}),u((function(r){e.width=s.width,e.height=s.height;var l=o.options.resize.call(o,e,t,i,n),u=document.createElement("canvas"),c=u.getContext("2d");switch(u.width=l.trgWidth,u.height=l.trgHeight,r>4&&(u.width=l.trgHeight,u.height=l.trgWidth),r){case 2:c.translate(u.width,0),c.scale(-1,1);break;case 3:c.translate(u.width,u.height),c.rotate(Math.PI);break;case 4:c.translate(0,u.height),c.scale(1,-1);break;case 5:c.rotate(.5*Math.PI),c.scale(1,-1);break;case 6:c.rotate(.5*Math.PI),c.translate(0,-u.width);break;case 7:c.rotate(.5*Math.PI),c.translate(u.height,-u.width),c.scale(-1,1);break;case 8:c.rotate(-.5*Math.PI),c.translate(-u.height,0)}y(c,s,null!=l.srcX?l.srcX:0,null!=l.srcY?l.srcY:0,l.srcWidth,l.srcHeight,null!=l.trgX?l.trgX:0,null!=l.trgY?l.trgY:0,l.trgWidth,l.trgHeight);var d=u.toDataURL("image/png");if(null!=a)return a(d,u)}))},null!=a&&(s.onerror=a),s.src=e.dataURL}},{key:"processQueue",value:function(){var e=this.options.parallelUploads,t=this.getUploadingFiles().length,i=t;if(!(t>=e)){var n=this.getQueuedFiles();if(n.length>0){if(this.options.uploadMultiple)return this.processFiles(n.slice(0,e-t));for(;i1?t-1:0),n=1;nt.options.chunkSize),e[0].upload.totalChunkCount=Math.ceil(n.size/t.options.chunkSize)}if(e[0].upload.chunked){var r=t,a=t,l=e[0];n=i[0];l.upload.chunks=[];var s=function(){for(var t=0;void 0!==l.upload.chunks[t];)t++;if(!(t>=l.upload.totalChunkCount)){0;var i=t*r.options.chunkSize,a=Math.min(i+r.options.chunkSize,n.size),s={name:r._getParamName(0),data:n.webkitSlice?n.webkitSlice(i,a):n.slice(i,a),filename:l.upload.filename,chunkIndex:t};l.upload.chunks[t]={file:l,index:t,dataBlock:s,status:o.UPLOADING,progress:0,retries:0},r._uploadData(e,[s])}};if(l.upload.finishedChunkUpload=function(t,i){var n=a,r=!0;t.status=o.SUCCESS,t.dataBlock=null,t.response=t.xhr.responseText,t.responseHeaders=t.xhr.getAllResponseHeaders(),t.xhr=null;for(var u=0;u=o;l?a++:a--)r[a]=t.charCodeAt(a);return new Blob([n],{type:i})};var m=function(e,t){return e.filter((function(e){return e!==t})).map((function(e){return e}))},v=function(e){return e.replace(/[\-_](\w)/g,(function(e){return e.charAt(1).toUpperCase()}))};f.createElement=function(e){var t=document.createElement("div");return t.innerHTML=e,t.childNodes[0]},f.elementInside=function(e,t){if(e===t)return!0;for(;e=e.parentNode;)if(e===t)return!0;return!1},f.getElement=function(e,t){var i;if("string"==typeof e?i=document.querySelector(e):null!=e.nodeType&&(i=e),null==i)throw new Error("Invalid `".concat(t,"` option provided. Please provide a CSS selector or a plain HTML element."));return i},f.getElements=function(e,t){var i,n;if(e instanceof Array){n=[];try{var r=!0,a=!1,o=void 0;try{for(var l=e[Symbol.iterator]();!(r=(s=l.next()).done);r=!0)i=s.value,n.push(this.getElement(i,t))}catch(e){a=!0,o=e}finally{try{r||null==l.return||l.return()}finally{if(a)throw o}}}catch(e){n=null}}else if("string"==typeof e){n=[];r=!0,a=!1,o=void 0;try{var s;for(l=document.querySelectorAll(e)[Symbol.iterator]();!(r=(s=l.next()).done);r=!0)i=s.value,n.push(i)}catch(e){a=!0,o=e}finally{try{r||null==l.return||l.return()}finally{if(a)throw o}}}else null!=e.nodeType&&(n=[e]);if(null==n||!n.length)throw new Error("Invalid `".concat(t,"` option provided. Please provide a CSS selector, a plain HTML element or a list of those."));return n},f.confirm=function(e,t,i){return window.confirm(e)?t():null!=i?i():void 0},f.isValidFile=function(e,t){if(!t)return!0;t=t.split(",");var i=e.type,n=i.replace(/\/.*$/,""),r=!0,a=!1,o=void 0;try{for(var l,s=t[Symbol.iterator]();!(r=(l=s.next()).done);r=!0){var u=l.value;if("."===(u=u.trim()).charAt(0)){if(-1!==e.name.toLowerCase().indexOf(u.toLowerCase(),e.name.length-u.length))return!0}else if(/\/\*$/.test(u)){if(n===u.replace(/\/.*$/,""))return!0}else if(i===u)return!0}}catch(e){a=!0,o=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw o}}return!1},"undefined"!=typeof jQuery&&null!==jQuery&&(jQuery.fn.dropzone=function(e){return this.each((function(){return new f(this,e)}))}),f.ADDED="added",f.QUEUED="queued",f.ACCEPTED=f.QUEUED,f.UPLOADING="uploading",f.PROCESSING=f.UPLOADING,f.CANCELED="canceled",f.ERROR="error",f.SUCCESS="success";var y=function(e,t,i,n,r,a,o,l,s,u){var c=function(e){e.naturalWidth;var t=e.naturalHeight,i=document.createElement("canvas");i.width=1,i.height=t;var n=i.getContext("2d");n.drawImage(e,0,0);for(var r=n.getImageData(1,0,1,t).data,a=0,o=t,l=t;l>a;)0===r[4*(l-1)+3]?o=l:a=l,l=o+a>>1;var s=l/t;return 0===s?1:s}(t);return e.drawImage(t,i,n,r,a,o,l,s,u/c)},g=function(){"use strict";function e(){i(this,e)}return r(e,null,[{key:"initClass",value:function(){this.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}},{key:"encode64",value:function(e){for(var t="",i=void 0,n=void 0,r="",a=void 0,o=void 0,l=void 0,s="",u=0;a=(i=e[u++])>>2,o=(3&i)<<4|(n=e[u++])>>4,l=(15&n)<<2|(r=e[u++])>>6,s=63&r,isNaN(n)?l=s=64:isNaN(r)&&(s=64),t=t+this.KEY_STR.charAt(a)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(l)+this.KEY_STR.charAt(s),i=n=r="",a=o=l=s="",ue.length)break}return i}},{key:"decode64",value:function(e){var t=void 0,i=void 0,n="",r=void 0,a=void 0,o="",l=0,s=[];for(/[^A-Za-z0-9\+\/\=]/g.exec(e)&&console.warn("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding."),e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");t=this.KEY_STR.indexOf(e.charAt(l++))<<2|(r=this.KEY_STR.indexOf(e.charAt(l++)))>>4,i=(15&r)<<4|(a=this.KEY_STR.indexOf(e.charAt(l++)))>>2,n=(3&a)<<6|(o=this.KEY_STR.indexOf(e.charAt(l++))),s.push(t),64!==a&&s.push(i),64!==o&&s.push(n),t=i=n="",r=a=o="",l 1 ? t - 1 : 0), n = 1; + n < t; + n++ + ) + i[n - 1] = arguments[n]; + this._callbacks = this._callbacks || {}; + var r = this._callbacks[e], + a = !0, + o = !1, + l = void 0; + if (r) + try { + for ( + var s, u = r[Symbol.iterator](); + !(a = (s = u.next()).done); + a = !0 + ) { + var c = s.value; + c.apply(this, i); + } + } catch (e) { + (o = !0), (l = e); + } finally { + try { + a || null == u.return || u.return(); + } finally { + if (o) throw l; + } + } + return ( + this.element && + this.element.dispatchEvent( + this.makeEvent("dropzone:" + e, { args: i }) + ), + this + ); + }, + }, + { + key: "makeEvent", + value: function (e, t) { + var i = { bubbles: !0, cancelable: !0, detail: t }; + if ("function" == typeof window.CustomEvent) + return new CustomEvent(e, i); + var n = document.createEvent("CustomEvent"); + return n.initCustomEvent(e, i.bubbles, i.cancelable, i.detail), n; + }, + }, + { + key: "off", + value: function (e, t) { + if (!this._callbacks || 0 === arguments.length) + return (this._callbacks = {}), this; + var i = this._callbacks[e]; + if (!i) return this; + if (1 === arguments.length) return delete this._callbacks[e], this; + for (var n = 0; n < i.length; n++) { + var r = i[n]; + if (r === t) { + i.splice(n, 1); + break; + } + } + return this; + }, + }, + ]), + e + ); + })(); + var p = { + url: null, + method: "post", + withCredentials: !1, + timeout: null, + parallelUploads: 2, + uploadMultiple: !1, + chunking: !1, + forceChunking: !1, + chunkSize: 2097152, + parallelChunkUploads: !1, + retryChunks: !1, + retryChunksLimit: 3, + maxFilesize: 256, + paramName: "file", + createImageThumbnails: !0, + maxThumbnailFilesize: 10, + thumbnailWidth: 120, + thumbnailHeight: 120, + thumbnailMethod: "crop", + resizeWidth: null, + resizeHeight: null, + resizeMimeType: null, + resizeQuality: 0.8, + resizeMethod: "contain", + filesizeBase: 1e3, + maxFiles: null, + headers: null, + defaultHeaders: !0, + clickable: !0, + ignoreHiddenFiles: !0, + acceptedFiles: null, + acceptedMimeTypes: null, + autoProcessQueue: !0, + autoQueue: !0, + addRemoveLinks: !1, + previewsContainer: null, + disablePreviews: !1, + hiddenInputContainer: "body", + capture: null, + renameFilename: null, + renameFile: null, + forceFallback: !1, + dictDefaultMessage: "Click or drop files", + dictFallbackMessage: + "Your browser does not support drag'n'drop file uploads.", + dictFallbackText: + "Please use the fallback form below to upload your files like in the olden days.", + dictFileTooBig: + "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", + dictInvalidFileType: "You can't upload files of this type.", + dictResponseError: "Server responded with {{statusCode}} code.", + dictCancelUpload: "Cancel upload", + dictUploadCanceled: "Upload canceled.", + dictCancelUploadConfirmation: + "Are you sure you want to cancel this upload?", + dictRemoveFile: "Remove file", + dictRemoveFileConfirmation: null, + dictMaxFilesExceeded: "You can not upload any more files.", + dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" }, + init: function () {}, + params: function (e, t, i) { + if (i) + return { + dzuuid: i.file.upload.uuid, + dzchunkindex: i.index, + dztotalfilesize: i.file.size, + dzchunksize: this.options.chunkSize, + dztotalchunkcount: i.file.upload.totalChunkCount, + dzchunkbyteoffset: i.index * this.options.chunkSize, + }; + }, + accept: function (e, t) { + return t(); + }, + chunksUploaded: function (e, t) { + t(); + }, + binaryBody: !1, + fallback: function () { + var e; + this.element.className = "".concat( + this.element.className, + " dz-browser-not-supported" + ); + var t = !0, + i = !1, + n = void 0; + try { + for ( + var r, + a = this.element.getElementsByTagName("div")[Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + var o = r.value; + if (/(^| )dz-message($| )/.test(o.className)) { + (e = o), (o.className = "dz-message"); + break; + } + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + e || + ((e = f.createElement('
')), + this.element.appendChild(e)); + var l = e.getElementsByTagName("span")[0]; + return ( + l && + (null != l.textContent + ? (l.textContent = this.options.dictFallbackMessage) + : null != l.innerText && + (l.innerText = this.options.dictFallbackMessage)), + this.element.appendChild(this.getFallbackForm()) + ); + }, + resize: function (e, t, i, n) { + var r = { srcX: 0, srcY: 0, srcWidth: e.width, srcHeight: e.height }, + a = e.width / e.height; + null == t && null == i + ? ((t = r.srcWidth), (i = r.srcHeight)) + : null == t + ? (t = i * a) + : null == i && (i = t / a); + var o = (t = Math.min(t, r.srcWidth)) / (i = Math.min(i, r.srcHeight)); + if (r.srcWidth > t || r.srcHeight > i) + if ("crop" === n) + a > o + ? ((r.srcHeight = e.height), (r.srcWidth = r.srcHeight * o)) + : ((r.srcWidth = e.width), (r.srcHeight = r.srcWidth / o)); + else { + if ("contain" !== n) + throw new Error("Unknown resizeMethod '".concat(n, "'")); + a > o ? (i = t / a) : (t = i * a); + } + return ( + (r.srcX = (e.width - r.srcWidth) / 2), + (r.srcY = (e.height - r.srcHeight) / 2), + (r.trgWidth = t), + (r.trgHeight = i), + r + ); + }, + transformFile: function (e, t) { + return (this.options.resizeWidth || this.options.resizeHeight) && + e.type.match(/image.*/) + ? this.resizeImage( + e, + this.options.resizeWidth, + this.options.resizeHeight, + this.options.resizeMethod, + t + ) + : t(e); + }, + previewTemplate: e( + '
' + ), + drop: function (e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragstart: function (e) {}, + dragend: function (e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragenter: function (e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragover: function (e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragleave: function (e) { + return this.element.classList.remove("dz-drag-hover"); + }, + paste: function (e) {}, + reset: function () { + return this.element.classList.remove("dz-started"); + }, + addedfile: function (e) { + if ( + (this.element === this.previewsContainer && + this.element.classList.add("dz-started"), + this.previewsContainer && !this.options.disablePreviews) + ) { + var t = this; + (e.previewElement = f.createElement( + this.options.previewTemplate.trim() + )), + (e.previewTemplate = e.previewElement), + this.previewsContainer.appendChild(e.previewElement); + var i = !0, + n = !1, + r = void 0; + try { + for ( + var a, + o = e.previewElement + .querySelectorAll("[data-dz-name]") + [Symbol.iterator](); + !(i = (a = o.next()).done); + i = !0 + ) { + var l = a.value; + l.textContent = e.name; + } + } catch (e) { + (n = !0), (r = e); + } finally { + try { + i || null == o.return || o.return(); + } finally { + if (n) throw r; + } + } + var s = !0, + u = !1, + c = void 0; + try { + for ( + var d, + h = e.previewElement + .querySelectorAll("[data-dz-size]") + [Symbol.iterator](); + !(s = (d = h.next()).done); + s = !0 + ) + (l = d.value).innerHTML = this.filesize(e.size); + } catch (e) { + (u = !0), (c = e); + } finally { + try { + s || null == h.return || h.return(); + } finally { + if (u) throw c; + } + } + this.options.addRemoveLinks && + ((e._removeLink = f.createElement( + ''.concat( + this.options.dictRemoveFile, + "" + ) + )), + e.previewElement.appendChild(e._removeLink)); + var p = function (i) { + var n = t; + if ( + (i.preventDefault(), + i.stopPropagation(), + e.status === f.UPLOADING) + ) + return f.confirm( + t.options.dictCancelUploadConfirmation, + function () { + return n.removeFile(e); + } + ); + var r = t; + return t.options.dictRemoveFileConfirmation + ? f.confirm(t.options.dictRemoveFileConfirmation, function () { + return r.removeFile(e); + }) + : t.removeFile(e); + }, + m = !0, + v = !1, + y = void 0; + try { + for ( + var g, + b = e.previewElement + .querySelectorAll("[data-dz-remove]") + [Symbol.iterator](); + !(m = (g = b.next()).done); + m = !0 + ) { + g.value.addEventListener("click", p); + } + } catch (e) { + (v = !0), (y = e); + } finally { + try { + m || null == b.return || b.return(); + } finally { + if (v) throw y; + } + } + } + }, + removedfile: function (e) { + return ( + null != e.previewElement && + null != e.previewElement.parentNode && + e.previewElement.parentNode.removeChild(e.previewElement), + this._updateMaxFilesReachedClass() + ); + }, + thumbnail: function (e, t) { + if (e.previewElement) { + e.previewElement.classList.remove("dz-file-preview"); + var i = !0, + n = !1, + r = void 0; + try { + for ( + var a, + o = e.previewElement + .querySelectorAll("[data-dz-thumbnail]") + [Symbol.iterator](); + !(i = (a = o.next()).done); + i = !0 + ) { + var l = a.value; + (l.alt = e.name), (l.src = t); + } + } catch (e) { + (n = !0), (r = e); + } finally { + try { + i || null == o.return || o.return(); + } finally { + if (n) throw r; + } + } + return setTimeout(function () { + return e.previewElement.classList.add("dz-image-preview"); + }, 1); + } + }, + error: function (e, t) { + if (e.previewElement) { + e.previewElement.classList.add("dz-error"), + "string" != typeof t && t.error && (t = t.error); + var i = !0, + n = !1, + r = void 0; + try { + for ( + var a, + o = e.previewElement + .querySelectorAll("[data-dz-errormessage]") + [Symbol.iterator](); + !(i = (a = o.next()).done); + i = !0 + ) { + a.value.textContent = t; + } + } catch (e) { + (n = !0), (r = e); + } finally { + try { + i || null == o.return || o.return(); + } finally { + if (n) throw r; + } + } + } + }, + errormultiple: function () {}, + processing: function (e) { + if ( + e.previewElement && + (e.previewElement.classList.add("dz-processing"), e._removeLink) + ) + return (e._removeLink.innerHTML = this.options.dictCancelUpload); + }, + processingmultiple: function () {}, + uploadprogress: function (e, t, i) { + var n = !0, + r = !1, + a = void 0; + if (e.previewElement) + try { + for ( + var o, + l = e.previewElement + .querySelectorAll("[data-dz-uploadprogress]") + [Symbol.iterator](); + !(n = (o = l.next()).done); + n = !0 + ) { + var s = o.value; + "PROGRESS" === s.nodeName + ? (s.value = t) + : (s.style.width = "".concat(t, "%")); + } + } catch (e) { + (r = !0), (a = e); + } finally { + try { + n || null == l.return || l.return(); + } finally { + if (r) throw a; + } + } + }, + totaluploadprogress: function () {}, + sending: function () {}, + sendingmultiple: function () {}, + success: function (e) { + if (e.previewElement) + return e.previewElement.classList.add("dz-success"); + }, + successmultiple: function () {}, + canceled: function (e) { + return this.emit("error", e, this.options.dictUploadCanceled); + }, + canceledmultiple: function () {}, + complete: function (e) { + if ( + (e._removeLink && + (e._removeLink.innerHTML = this.options.dictRemoveFile), + e.previewElement) + ) + return e.previewElement.classList.add("dz-complete"); + }, + completemultiple: function () {}, + maxfilesexceeded: function () {}, + maxfilesreached: function () {}, + queuecomplete: function () {}, + addedfiles: function () {}, + }, + f = (function (n) { + "use strict"; + function o(n, r) { + var l, c, d, h; + if ( + (i(this, o), + ((l = s(this, ((c = o), a(c)).call(this))).element = n), + (l.clickableElements = []), + (l.listeners = []), + (l.files = []), + "string" == typeof l.element && + (l.element = document.querySelector(l.element)), + !l.element || null == l.element.nodeType) + ) + throw new Error("Invalid dropzone element."); + if (l.element.dropzone) throw new Error("Dropzone already attached."); + o.instances.push(t(l)), (l.element.dropzone = t(l)); + var f = null != (h = o.optionsForElement(l.element)) ? h : {}; + if ( + ((l.options = e(u)(!0, {}, p, f, null != r ? r : {})), + (l.options.previewTemplate = l.options.previewTemplate.replace( + /\n*/g, + "" + )), + l.options.forceFallback || !o.isBrowserSupported()) + ) + return s(l, l.options.fallback.call(t(l))); + if ( + (null == l.options.url && + (l.options.url = l.element.getAttribute("action")), + !l.options.url) + ) + throw new Error("No URL provided."); + if (l.options.acceptedFiles && l.options.acceptedMimeTypes) + throw new Error( + "You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated." + ); + if (l.options.uploadMultiple && l.options.chunking) + throw new Error("You cannot set both: uploadMultiple and chunking."); + if (l.options.binaryBody && l.options.uploadMultiple) + throw new Error( + "You cannot set both: binaryBody and uploadMultiple." + ); + return ( + l.options.acceptedMimeTypes && + ((l.options.acceptedFiles = l.options.acceptedMimeTypes), + delete l.options.acceptedMimeTypes), + null != l.options.renameFilename && + (l.options.renameFile = function (e) { + return l.options.renameFilename.call(t(l), e.name, e); + }), + "string" == typeof l.options.method && + (l.options.method = l.options.method.toUpperCase()), + (d = l.getExistingFallback()) && + d.parentNode && + d.parentNode.removeChild(d), + !1 !== l.options.previewsContainer && + (l.options.previewsContainer + ? (l.previewsContainer = o.getElement( + l.options.previewsContainer, + "previewsContainer" + )) + : (l.previewsContainer = l.element)), + l.options.clickable && + (!0 === l.options.clickable + ? (l.clickableElements = [l.element]) + : (l.clickableElements = o.getElements( + l.options.clickable, + "clickable" + ))), + l.init(), + l + ); + } + return ( + l(o, n), + r( + o, + [ + { + key: "getAcceptedFiles", + value: function () { + return this.files + .filter(function (e) { + return e.accepted; + }) + .map(function (e) { + return e; + }); + }, + }, + { + key: "getRejectedFiles", + value: function () { + return this.files + .filter(function (e) { + return !e.accepted; + }) + .map(function (e) { + return e; + }); + }, + }, + { + key: "getFilesWithStatus", + value: function (e) { + return this.files + .filter(function (t) { + return t.status === e; + }) + .map(function (e) { + return e; + }); + }, + }, + { + key: "getQueuedFiles", + value: function () { + return this.getFilesWithStatus(o.QUEUED); + }, + }, + { + key: "getUploadingFiles", + value: function () { + return this.getFilesWithStatus(o.UPLOADING); + }, + }, + { + key: "getAddedFiles", + value: function () { + return this.getFilesWithStatus(o.ADDED); + }, + }, + { + key: "getActiveFiles", + value: function () { + return this.files + .filter(function (e) { + return e.status === o.UPLOADING || e.status === o.QUEUED; + }) + .map(function (e) { + return e; + }); + }, + }, + { + key: "init", + value: function () { + var e = this, + t = this, + i = this, + n = this, + r = this, + a = this, + l = this, + s = this, + u = this, + c = this, + d = this; + if ( + ("form" === this.element.tagName && + this.element.setAttribute("enctype", "multipart/form-data"), + this.element.classList.contains("dropzone") && + !this.element.querySelector(".dz-message") && + this.element.appendChild( + o.createElement( + '
" + ) + ) + ), + this.clickableElements.length) + ) { + var h = this, + p = function () { + var e = h; + h.hiddenFileInput && + h.hiddenFileInput.parentNode.removeChild( + h.hiddenFileInput + ), + (h.hiddenFileInput = document.createElement("input")), + h.hiddenFileInput.setAttribute("type", "file"), + (null === h.options.maxFiles || + h.options.maxFiles > 1) && + h.hiddenFileInput.setAttribute( + "multiple", + "multiple" + ), + (h.hiddenFileInput.className = "dz-hidden-input"), + null !== h.options.acceptedFiles && + h.hiddenFileInput.setAttribute( + "accept", + h.options.acceptedFiles + ), + null !== h.options.capture && + h.hiddenFileInput.setAttribute( + "capture", + h.options.capture + ), + h.hiddenFileInput.setAttribute("tabindex", "-1"), + (h.hiddenFileInput.style.visibility = "hidden"), + (h.hiddenFileInput.style.position = "absolute"), + (h.hiddenFileInput.style.top = "0"), + (h.hiddenFileInput.style.left = "0"), + (h.hiddenFileInput.style.height = "0"), + (h.hiddenFileInput.style.width = "0"), + o + .getElement( + h.options.hiddenInputContainer, + "hiddenInputContainer" + ) + .appendChild(h.hiddenFileInput), + h.hiddenFileInput.addEventListener( + "change", + function () { + var t = e.hiddenFileInput.files, + i = !0, + n = !1, + r = void 0; + if (t.length) + try { + for ( + var a, o = t[Symbol.iterator](); + !(i = (a = o.next()).done); + i = !0 + ) { + var l = a.value; + e.addFile(l); + } + } catch (e) { + (n = !0), (r = e); + } finally { + try { + i || null == o.return || o.return(); + } finally { + if (n) throw r; + } + } + e.emit("addedfiles", t), p(); + } + ); + }; + p(); + } + this.URL = null !== window.URL ? window.URL : window.webkitURL; + var f = !0, + m = !1, + v = void 0; + try { + for ( + var y, g = this.events[Symbol.iterator](); + !(f = (y = g.next()).done); + f = !0 + ) { + var b = y.value; + this.on(b, this.options[b]); + } + } catch (e) { + (m = !0), (v = e); + } finally { + try { + f || null == g.return || g.return(); + } finally { + if (m) throw v; + } + } + this.on("uploadprogress", function () { + return e.updateTotalUploadProgress(); + }), + this.on("removedfile", function () { + return t.updateTotalUploadProgress(); + }), + this.on("canceled", function (e) { + return i.emit("complete", e); + }), + this.on("complete", function (e) { + var t = n; + if ( + 0 === n.getAddedFiles().length && + 0 === n.getUploadingFiles().length && + 0 === n.getQueuedFiles().length + ) + return setTimeout(function () { + return t.emit("queuecomplete"); + }, 0); + }); + var k = function (e) { + if ( + (function (e) { + if (e.dataTransfer.types) + for (var t = 0; t < e.dataTransfer.types.length; t++) + if ("Files" === e.dataTransfer.types[t]) return !0; + return !1; + })(e) + ) + return ( + e.stopPropagation(), + e.preventDefault + ? e.preventDefault() + : (e.returnValue = !1) + ); + }; + return ( + (this.listeners = [ + { + element: this.element, + events: { + dragstart: function (e) { + return r.emit("dragstart", e); + }, + dragenter: function (e) { + return k(e), a.emit("dragenter", e); + }, + dragover: function (e) { + var t; + try { + t = e.dataTransfer.effectAllowed; + } catch (e) {} + return ( + (e.dataTransfer.dropEffect = + "move" === t || "linkMove" === t + ? "move" + : "copy"), + k(e), + l.emit("dragover", e) + ); + }, + dragleave: function (e) { + return s.emit("dragleave", e); + }, + drop: function (e) { + return k(e), u.drop(e); + }, + dragend: function (e) { + return c.emit("dragend", e); + }, + }, + }, + ]), + this.clickableElements.forEach(function (e) { + var t = d; + return d.listeners.push({ + element: e, + events: { + click: function (i) { + return ( + (e !== t.element || + i.target === t.element || + o.elementInside( + i.target, + t.element.querySelector(".dz-message") + )) && + t.hiddenFileInput.click(), + !0 + ); + }, + }, + }); + }), + this.enable(), + this.options.init.call(this) + ); + }, + }, + { + key: "destroy", + value: function () { + return ( + this.disable(), + this.removeAllFiles(!0), + (null != this.hiddenFileInput + ? this.hiddenFileInput.parentNode + : void 0) && + (this.hiddenFileInput.parentNode.removeChild( + this.hiddenFileInput + ), + (this.hiddenFileInput = null)), + delete this.element.dropzone, + o.instances.splice(o.instances.indexOf(this), 1) + ); + }, + }, + { + key: "updateTotalUploadProgress", + value: function () { + var e, + t = 0, + i = 0; + if (this.getActiveFiles().length) { + var n = !0, + r = !1, + a = void 0; + try { + for ( + var o, l = this.getActiveFiles()[Symbol.iterator](); + !(n = (o = l.next()).done); + n = !0 + ) { + var s = o.value; + (t += s.upload.bytesSent), (i += s.upload.total); + } + } catch (e) { + (r = !0), (a = e); + } finally { + try { + n || null == l.return || l.return(); + } finally { + if (r) throw a; + } + } + e = (100 * t) / i; + } else e = 100; + return this.emit("totaluploadprogress", e, i, t); + }, + }, + { + key: "_getParamName", + value: function (e) { + return "function" == typeof this.options.paramName + ? this.options.paramName(e) + : "" + .concat(this.options.paramName) + .concat( + this.options.uploadMultiple ? "[".concat(e, "]") : "" + ); + }, + }, + { + key: "_renameFile", + value: function (e) { + return "function" != typeof this.options.renameFile + ? e.name + : this.options.renameFile(e); + }, + }, + { + key: "getFallbackForm", + value: function () { + var e, t; + if ((e = this.getExistingFallback())) return e; + var i = '
'; + this.options.dictFallbackText && + (i += "

".concat(this.options.dictFallbackText, "

")), + (i += '
' + )); + var n = o.createElement(i); + return ( + "FORM" !== this.element.tagName + ? (t = o.createElement( + '
') + )).appendChild(n) + : (this.element.setAttribute( + "enctype", + "multipart/form-data" + ), + this.element.setAttribute("method", this.options.method)), + null != t ? t : n + ); + }, + }, + { + key: "getExistingFallback", + value: function () { + var e = function (e) { + var t = !0, + i = !1, + n = void 0; + try { + for ( + var r, a = e[Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + var o = r.value; + if (/(^| )fallback($| )/.test(o.className)) return o; + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + }, + t = !0, + i = !1, + n = void 0; + try { + for ( + var r, a = ["div", "form"][Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + var o, + l = r.value; + if ((o = e(this.element.getElementsByTagName(l)))) return o; + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + }, + }, + { + key: "setupEventListeners", + value: function () { + return this.listeners.map(function (e) { + return (function () { + var t = []; + for (var i in e.events) { + var n = e.events[i]; + t.push(e.element.addEventListener(i, n, !1)); + } + return t; + })(); + }); + }, + }, + { + key: "removeEventListeners", + value: function () { + return this.listeners.map(function (e) { + return (function () { + var t = []; + for (var i in e.events) { + var n = e.events[i]; + t.push(e.element.removeEventListener(i, n, !1)); + } + return t; + })(); + }); + }, + }, + { + key: "disable", + value: function () { + var e = this; + return ( + this.clickableElements.forEach(function (e) { + return e.classList.remove("dz-clickable"); + }), + this.removeEventListeners(), + (this.disabled = !0), + this.files.map(function (t) { + return e.cancelUpload(t); + }) + ); + }, + }, + { + key: "enable", + value: function () { + return ( + delete this.disabled, + this.clickableElements.forEach(function (e) { + return e.classList.add("dz-clickable"); + }), + this.setupEventListeners() + ); + }, + }, + { + key: "filesize", + value: function (e) { + var t = 0, + i = "b"; + if (e > 0) { + for ( + var n = ["tb", "gb", "mb", "kb", "b"], r = 0; + r < n.length; + r++ + ) { + var a = n[r]; + if (e >= Math.pow(this.options.filesizeBase, 4 - r) / 10) { + (t = e / Math.pow(this.options.filesizeBase, 4 - r)), + (i = a); + break; + } + } + t = Math.round(10 * t) / 10; + } + return "" + .concat(t, " ") + .concat(this.options.dictFileSizeUnits[i]); + }, + }, + { + key: "_updateMaxFilesReachedClass", + value: function () { + return null != this.options.maxFiles && + this.getAcceptedFiles().length >= this.options.maxFiles + ? (this.getAcceptedFiles().length === this.options.maxFiles && + this.emit("maxfilesreached", this.files), + this.element.classList.add("dz-max-files-reached")) + : this.element.classList.remove("dz-max-files-reached"); + }, + }, + { + key: "drop", + value: function (e) { + if (e.dataTransfer) { + this.emit("drop", e); + for (var t = [], i = 0; i < e.dataTransfer.files.length; i++) + t[i] = e.dataTransfer.files[i]; + if (t.length) { + var n = e.dataTransfer.items; + n && n.length && null != n[0].webkitGetAsEntry + ? this._addFilesFromItems(n) + : this.handleFiles(t); + } + this.emit("addedfiles", t); + } + }, + }, + { + key: "paste", + value: function (e) { + if ( + null != + ((t = null != e ? e.clipboardData : void 0), + (i = function (e) { + return e.items; + }), + null != t ? i(t) : void 0) + ) { + var t, i; + this.emit("paste", e); + var n = e.clipboardData.items; + return n.length ? this._addFilesFromItems(n) : void 0; + } + }, + }, + { + key: "handleFiles", + value: function (e) { + var t = !0, + i = !1, + n = void 0; + try { + for ( + var r, a = e[Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + var o = r.value; + this.addFile(o); + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + }, + }, + { + key: "_addFilesFromItems", + value: function (e) { + var t = this; + return (function () { + var i = [], + n = !0, + r = !1, + a = void 0; + try { + for ( + var o, l = e[Symbol.iterator](); + !(n = (o = l.next()).done); + n = !0 + ) { + var s, + u = o.value; + null != u.webkitGetAsEntry && (s = u.webkitGetAsEntry()) + ? s.isFile + ? i.push(t.addFile(u.getAsFile())) + : s.isDirectory + ? i.push(t._addFilesFromDirectory(s, s.name)) + : i.push(void 0) + : null != u.getAsFile && + (null == u.kind || "file" === u.kind) + ? i.push(t.addFile(u.getAsFile())) + : i.push(void 0); + } + } catch (e) { + (r = !0), (a = e); + } finally { + try { + n || null == l.return || l.return(); + } finally { + if (r) throw a; + } + } + return i; + })(); + }, + }, + { + key: "_addFilesFromDirectory", + value: function (e, t) { + var i = this, + n = e.createReader(), + r = function (e) { + return ( + (t = console), + (i = "log"), + (n = function (t) { + return t.log(e); + }), + null != t && "function" == typeof t[i] ? n(t, i) : void 0 + ); + var t, i, n; + }, + a = function () { + var e = i; + return n.readEntries(function (i) { + if (i.length > 0) { + var n = !0, + r = !1, + o = void 0; + try { + for ( + var l, s = i[Symbol.iterator](); + !(n = (l = s.next()).done); + n = !0 + ) { + var u = l.value, + c = e; + u.isFile + ? u.file(function (e) { + if ( + !c.options.ignoreHiddenFiles || + "." !== e.name.substring(0, 1) + ) + return ( + (e.fullPath = "" + .concat(t, "/") + .concat(e.name)), + c.addFile(e) + ); + }) + : u.isDirectory && + e._addFilesFromDirectory( + u, + "".concat(t, "/").concat(u.name) + ); + } + } catch (e) { + (r = !0), (o = e); + } finally { + try { + n || null == s.return || s.return(); + } finally { + if (r) throw o; + } + } + a(); + } + return null; + }, r); + }; + return a(); + }, + }, + { + key: "accept", + value: function (e, t) { + this.options.maxFilesize && + e.size > 1048576 * this.options.maxFilesize + ? t( + this.options.dictFileTooBig + .replace( + "{{filesize}}", + Math.round(e.size / 1024 / 10.24) / 100 + ) + .replace("{{maxFilesize}}", this.options.maxFilesize) + ) + : o.isValidFile(e, this.options.acceptedFiles) + ? null != this.options.maxFiles && + this.getAcceptedFiles().length >= this.options.maxFiles + ? (t( + this.options.dictMaxFilesExceeded.replace( + "{{maxFiles}}", + this.options.maxFiles + ) + ), + this.emit("maxfilesexceeded", e)) + : this.options.accept.call(this, e, t) + : t(this.options.dictInvalidFileType); + }, + }, + { + key: "addFile", + value: function (e) { + var t = this; + (e.upload = { + uuid: o.uuidv4(), + progress: 0, + total: e.size, + bytesSent: 0, + filename: this._renameFile(e), + }), + this.files.push(e), + (e.status = o.ADDED), + this.emit("addedfile", e), + this._enqueueThumbnail(e), + this.accept(e, function (i) { + i + ? ((e.accepted = !1), t._errorProcessing([e], i)) + : ((e.accepted = !0), + t.options.autoQueue && t.enqueueFile(e)), + t._updateMaxFilesReachedClass(); + }); + }, + }, + { + key: "enqueueFiles", + value: function (e) { + var t = !0, + i = !1, + n = void 0; + try { + for ( + var r, a = e[Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + var o = r.value; + this.enqueueFile(o); + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + return null; + }, + }, + { + key: "enqueueFile", + value: function (e) { + if (e.status !== o.ADDED || !0 !== e.accepted) + throw new Error( + "This file can't be queued because it has already been processed or was rejected." + ); + var t = this; + if (((e.status = o.QUEUED), this.options.autoProcessQueue)) + return setTimeout(function () { + return t.processQueue(); + }, 0); + }, + }, + { + key: "_enqueueThumbnail", + value: function (e) { + if ( + this.options.createImageThumbnails && + e.type.match(/image.*/) && + e.size <= 1048576 * this.options.maxThumbnailFilesize + ) { + var t = this; + return ( + this._thumbnailQueue.push(e), + setTimeout(function () { + return t._processThumbnailQueue(); + }, 0) + ); + } + }, + }, + { + key: "_processThumbnailQueue", + value: function () { + var e = this; + if ( + !this._processingThumbnail && + 0 !== this._thumbnailQueue.length + ) { + this._processingThumbnail = !0; + var t = this._thumbnailQueue.shift(); + return this.createThumbnail( + t, + this.options.thumbnailWidth, + this.options.thumbnailHeight, + this.options.thumbnailMethod, + !0, + function (i) { + return ( + e.emit("thumbnail", t, i), + (e._processingThumbnail = !1), + e._processThumbnailQueue() + ); + } + ); + } + }, + }, + { + key: "removeFile", + value: function (e) { + if ( + (e.status === o.UPLOADING && this.cancelUpload(e), + (this.files = m(this.files, e)), + this.emit("removedfile", e), + 0 === this.files.length) + ) + return this.emit("reset"); + }, + }, + { + key: "removeAllFiles", + value: function (e) { + null == e && (e = !1); + var t = !0, + i = !1, + n = void 0; + try { + for ( + var r, a = this.files.slice()[Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + var l = r.value; + (l.status !== o.UPLOADING || e) && this.removeFile(l); + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + return null; + }, + }, + { + key: "resizeImage", + value: function (e, t, i, n, r) { + var a = this; + return this.createThumbnail(e, t, i, n, !0, function (t, i) { + if (null == i) return r(e); + var n = a.options.resizeMimeType; + null == n && (n = e.type); + var l = i.toDataURL(n, a.options.resizeQuality); + return ( + ("image/jpeg" !== n && "image/jpg" !== n) || + (l = g.restore(e.dataURL, l)), + r(o.dataURItoBlob(l)) + ); + }); + }, + }, + { + key: "createThumbnail", + value: function (e, t, i, n, r, a) { + var o = this, + l = new FileReader(); + (l.onload = function () { + (e.dataURL = l.result), + "image/svg+xml" !== e.type + ? o.createThumbnailFromUrl(e, t, i, n, r, a) + : null != a && a(l.result); + }), + l.readAsDataURL(e); + }, + }, + { + key: "displayExistingFile", + value: function (e, t, i, n, r) { + var a = void 0 === r || r; + if ((this.emit("addedfile", e), this.emit("complete", e), a)) { + var o = this; + (e.dataURL = t), + this.createThumbnailFromUrl( + e, + this.options.thumbnailWidth, + this.options.thumbnailHeight, + this.options.thumbnailMethod, + this.options.fixOrientation, + function (t) { + o.emit("thumbnail", e, t), i && i(); + }, + n + ); + } else this.emit("thumbnail", e, t), i && i(); + }, + }, + { + key: "createThumbnailFromUrl", + value: function (e, t, i, n, r, a, o) { + var l = this, + s = document.createElement("img"); + return ( + o && (s.crossOrigin = o), + (r = + "from-image" != + getComputedStyle(document.body).imageOrientation && r), + (s.onload = function () { + var o = l, + u = function (e) { + return e(1); + }; + return ( + "undefined" != typeof EXIF && + null !== EXIF && + r && + (u = function (e) { + return EXIF.getData(s, function () { + return e(EXIF.getTag(this, "Orientation")); + }); + }), + u(function (r) { + (e.width = s.width), (e.height = s.height); + var l = o.options.resize.call(o, e, t, i, n), + u = document.createElement("canvas"), + c = u.getContext("2d"); + switch ( + ((u.width = l.trgWidth), + (u.height = l.trgHeight), + r > 4 && + ((u.width = l.trgHeight), (u.height = l.trgWidth)), + r) + ) { + case 2: + c.translate(u.width, 0), c.scale(-1, 1); + break; + case 3: + c.translate(u.width, u.height), c.rotate(Math.PI); + break; + case 4: + c.translate(0, u.height), c.scale(1, -1); + break; + case 5: + c.rotate(0.5 * Math.PI), c.scale(1, -1); + break; + case 6: + c.rotate(0.5 * Math.PI), c.translate(0, -u.width); + break; + case 7: + c.rotate(0.5 * Math.PI), + c.translate(u.height, -u.width), + c.scale(-1, 1); + break; + case 8: + c.rotate(-0.5 * Math.PI), c.translate(-u.height, 0); + } + y( + c, + s, + null != l.srcX ? l.srcX : 0, + null != l.srcY ? l.srcY : 0, + l.srcWidth, + l.srcHeight, + null != l.trgX ? l.trgX : 0, + null != l.trgY ? l.trgY : 0, + l.trgWidth, + l.trgHeight + ); + var d = u.toDataURL("image/png"); + if (null != a) return a(d, u); + }) + ); + }), + null != a && (s.onerror = a), + (s.src = e.dataURL) + ); + }, + }, + { + key: "processQueue", + value: function () { + var e = this.options.parallelUploads, + t = this.getUploadingFiles().length, + i = t; + if (!(t >= e)) { + var n = this.getQueuedFiles(); + if (n.length > 0) { + if (this.options.uploadMultiple) + return this.processFiles(n.slice(0, e - t)); + for (; i < e; ) { + if (!n.length) return; + this.processFile(n.shift()), i++; + } + } + } + }, + }, + { + key: "processFile", + value: function (e) { + return this.processFiles([e]); + }, + }, + { + key: "processFiles", + value: function (e) { + var t = !0, + i = !1, + n = void 0; + try { + for ( + var r, a = e[Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + var l = r.value; + (l.processing = !0), + (l.status = o.UPLOADING), + this.emit("processing", l); + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + return ( + this.options.uploadMultiple && + this.emit("processingmultiple", e), + this.uploadFiles(e) + ); + }, + }, + { + key: "_getFilesWithXhr", + value: function (e) { + return this.files + .filter(function (t) { + return t.xhr === e; + }) + .map(function (e) { + return e; + }); + }, + }, + { + key: "cancelUpload", + value: function (e) { + if (e.status === o.UPLOADING) { + var t = this._getFilesWithXhr(e.xhr), + i = !0, + n = !1, + r = void 0; + try { + for ( + var a, l = t[Symbol.iterator](); + !(i = (a = l.next()).done); + i = !0 + ) { + (p = a.value).status = o.CANCELED; + } + } catch (e) { + (n = !0), (r = e); + } finally { + try { + i || null == l.return || l.return(); + } finally { + if (n) throw r; + } + } + void 0 !== e.xhr && e.xhr.abort(); + var s = !0, + u = !1, + c = void 0; + try { + for ( + var d, h = t[Symbol.iterator](); + !(s = (d = h.next()).done); + s = !0 + ) { + var p = d.value; + this.emit("canceled", p); + } + } catch (e) { + (u = !0), (c = e); + } finally { + try { + s || null == h.return || h.return(); + } finally { + if (u) throw c; + } + } + this.options.uploadMultiple && + this.emit("canceledmultiple", t); + } else + (e.status !== o.ADDED && e.status !== o.QUEUED) || + ((e.status = o.CANCELED), + this.emit("canceled", e), + this.options.uploadMultiple && + this.emit("canceledmultiple", [e])); + if (this.options.autoProcessQueue) return this.processQueue(); + }, + }, + { + key: "resolveOption", + value: function (e) { + for ( + var t = arguments.length, + i = new Array(t > 1 ? t - 1 : 0), + n = 1; + n < t; + n++ + ) + i[n - 1] = arguments[n]; + return "function" == typeof e ? e.apply(this, i) : e; + }, + }, + { + key: "uploadFile", + value: function (e) { + return this.uploadFiles([e]); + }, + }, + { + key: "uploadFiles", + value: function (e) { + var t = this; + this._transformFiles(e, function (i) { + if (t.options.chunking) { + var n = i[0]; + (e[0].upload.chunked = + t.options.chunking && + (t.options.forceChunking || + n.size > t.options.chunkSize)), + (e[0].upload.totalChunkCount = Math.ceil( + n.size / t.options.chunkSize + )); + } + if (e[0].upload.chunked) { + var r = t, + a = t, + l = e[0]; + n = i[0]; + l.upload.chunks = []; + var s = function () { + for (var t = 0; void 0 !== l.upload.chunks[t]; ) t++; + if (!(t >= l.upload.totalChunkCount)) { + 0; + var i = t * r.options.chunkSize, + a = Math.min(i + r.options.chunkSize, n.size), + s = { + name: r._getParamName(0), + data: n.webkitSlice + ? n.webkitSlice(i, a) + : n.slice(i, a), + filename: l.upload.filename, + chunkIndex: t, + }; + (l.upload.chunks[t] = { + file: l, + index: t, + dataBlock: s, + status: o.UPLOADING, + progress: 0, + retries: 0, + }), + r._uploadData(e, [s]); + } + }; + if ( + ((l.upload.finishedChunkUpload = function (t, i) { + var n = a, + r = !0; + (t.status = o.SUCCESS), + (t.dataBlock = null), + (t.response = t.xhr.responseText), + (t.responseHeaders = t.xhr.getAllResponseHeaders()), + (t.xhr = null); + for (var u = 0; u < l.upload.totalChunkCount; u++) { + if (void 0 === l.upload.chunks[u]) return s(); + l.upload.chunks[u].status !== o.SUCCESS && (r = !1); + } + r && + a.options.chunksUploaded(l, function () { + n._finished(e, i, null); + }); + }), + t.options.parallelChunkUploads) + ) + for (var u = 0; u < l.upload.totalChunkCount; u++) s(); + else s(); + } else { + var c = []; + for (u = 0; u < e.length; u++) + c[u] = { + name: t._getParamName(u), + data: i[u], + filename: e[u].upload.filename, + }; + t._uploadData(e, c); + } + }); + }, + }, + { + key: "_getChunk", + value: function (e, t) { + for (var i = 0; i < e.upload.totalChunkCount; i++) + if ( + void 0 !== e.upload.chunks[i] && + e.upload.chunks[i].xhr === t + ) + return e.upload.chunks[i]; + }, + }, + { + key: "_uploadData", + value: function (t, i) { + var n = this, + r = this, + a = this, + o = this, + l = new XMLHttpRequest(), + s = !0, + c = !1, + d = void 0; + try { + for ( + var h = t[Symbol.iterator](); + !(s = (x = h.next()).done); + s = !0 + ) { + (g = x.value).xhr = l; + } + } catch (e) { + (c = !0), (d = e); + } finally { + try { + s || null == h.return || h.return(); + } finally { + if (c) throw d; + } + } + t[0].upload.chunked && + (t[0].upload.chunks[i[0].chunkIndex].xhr = l); + var p = this.resolveOption(this.options.method, t, i), + f = this.resolveOption(this.options.url, t, i); + l.open(p, f, !0), + this.resolveOption(this.options.timeout, t) && + (l.timeout = this.resolveOption(this.options.timeout, t)), + (l.withCredentials = !!this.options.withCredentials), + (l.onload = function (e) { + n._finishedUploading(t, l, e); + }), + (l.ontimeout = function () { + r._handleUploadError( + t, + l, + "Request timedout after ".concat( + r.options.timeout / 1e3, + " seconds" + ) + ); + }), + (l.onerror = function () { + a._handleUploadError(t, l); + }), + ((null != l.upload ? l.upload : l).onprogress = function (e) { + return o._updateFilesUploadProgress(t, l, e); + }); + var m = this.options.defaultHeaders + ? { + Accept: "application/json", + "Cache-Control": "no-cache", + "X-Requested-With": "XMLHttpRequest", + } + : {}; + for (var v in (this.options.binaryBody && + (m["Content-Type"] = t[0].type), + this.options.headers && e(u)(m, this.options.headers), + m)) { + var y = m[v]; + y && l.setRequestHeader(v, y); + } + if (this.options.binaryBody) { + (s = !0), (c = !1), (d = void 0); + try { + for ( + h = t[Symbol.iterator](); + !(s = (x = h.next()).done); + s = !0 + ) { + var g = x.value; + this.emit("sending", g, l); + } + } catch (e) { + (c = !0), (d = e); + } finally { + try { + s || null == h.return || h.return(); + } finally { + if (c) throw d; + } + } + this.options.uploadMultiple && + this.emit("sendingmultiple", t, l), + this.submitRequest(l, null, t); + } else { + var b = new FormData(); + if (this.options.params) { + var k = this.options.params; + for (var w in ("function" == typeof k && + (k = k.call( + this, + t, + l, + t[0].upload.chunked ? this._getChunk(t[0], l) : null + )), + k)) { + var F = k[w]; + if (Array.isArray(F)) + for (var E = 0; E < F.length; E++) b.append(w, F[E]); + else b.append(w, F); + } + } + (s = !0), (c = !1), (d = void 0); + try { + var x; + for ( + h = t[Symbol.iterator](); + !(s = (x = h.next()).done); + s = !0 + ) { + g = x.value; + this.emit("sending", g, l, b); + } + } catch (e) { + (c = !0), (d = e); + } finally { + try { + s || null == h.return || h.return(); + } finally { + if (c) throw d; + } + } + this.options.uploadMultiple && + this.emit("sendingmultiple", t, l, b), + this._addFormElementData(b); + for (E = 0; E < i.length; E++) { + var z = i[E]; + b.append(z.name, z.data, z.filename); + } + this.submitRequest(l, b, t); + } + }, + }, + { + key: "_transformFiles", + value: function (e, t) { + for ( + var i = this, + n = function (n) { + i.options.transformFile.call(i, e[n], function (i) { + (r[n] = i), ++a === e.length && t(r); + }); + }, + r = [], + a = 0, + o = 0; + o < e.length; + o++ + ) + n(o); + }, + }, + { + key: "_addFormElementData", + value: function (e) { + var t = !0, + i = !1, + n = void 0; + if ("FORM" === this.element.tagName) + try { + for ( + var r = this.element + .querySelectorAll("input, textarea, select, button") + [Symbol.iterator](); + !(t = (s = r.next()).done); + t = !0 + ) { + var a = s.value, + o = a.getAttribute("name"), + l = a.getAttribute("type"); + if ((l && (l = l.toLowerCase()), null != o)) + if ( + "SELECT" === a.tagName && + a.hasAttribute("multiple") + ) { + (t = !0), (i = !1), (n = void 0); + try { + var s; + for ( + r = a.options[Symbol.iterator](); + !(t = (s = r.next()).done); + t = !0 + ) { + var u = s.value; + u.selected && e.append(o, u.value); + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == r.return || r.return(); + } finally { + if (i) throw n; + } + } + } else + (!l || + ("checkbox" !== l && "radio" !== l) || + a.checked) && + e.append(o, a.value); + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == r.return || r.return(); + } finally { + if (i) throw n; + } + } + }, + }, + { + key: "_updateFilesUploadProgress", + value: function (e, t, i) { + var n = !0, + r = !1, + a = void 0; + if (e[0].upload.chunked) { + c = e[0]; + var o = this._getChunk(c, t); + i + ? ((o.progress = (100 * i.loaded) / i.total), + (o.total = i.total), + (o.bytesSent = i.loaded)) + : ((o.progress = 100), (o.bytesSent = o.total)), + (c.upload.progress = 0), + (c.upload.total = 0), + (c.upload.bytesSent = 0); + for (var l = 0; l < c.upload.totalChunkCount; l++) + c.upload.chunks[l] && + void 0 !== c.upload.chunks[l].progress && + ((c.upload.progress += c.upload.chunks[l].progress), + (c.upload.total += c.upload.chunks[l].total), + (c.upload.bytesSent += c.upload.chunks[l].bytesSent)); + (c.upload.progress = + c.upload.progress / c.upload.totalChunkCount), + this.emit( + "uploadprogress", + c, + c.upload.progress, + c.upload.bytesSent + ); + } else + try { + for ( + var s, u = e[Symbol.iterator](); + !(n = (s = u.next()).done); + n = !0 + ) { + var c; + ((c = s.value).upload.total && + c.upload.bytesSent && + c.upload.bytesSent == c.upload.total) || + (i + ? ((c.upload.progress = (100 * i.loaded) / i.total), + (c.upload.total = i.total), + (c.upload.bytesSent = i.loaded)) + : ((c.upload.progress = 100), + (c.upload.bytesSent = c.upload.total)), + this.emit( + "uploadprogress", + c, + c.upload.progress, + c.upload.bytesSent + )); + } + } catch (e) { + (r = !0), (a = e); + } finally { + try { + n || null == u.return || u.return(); + } finally { + if (r) throw a; + } + } + }, + }, + { + key: "_finishedUploading", + value: function (e, t, i) { + var n; + if (e[0].status !== o.CANCELED && 4 === t.readyState) { + if ( + "arraybuffer" !== t.responseType && + "blob" !== t.responseType && + ((n = t.responseText), + t.getResponseHeader("content-type") && + ~t + .getResponseHeader("content-type") + .indexOf("application/json")) + ) + try { + n = JSON.parse(n); + } catch (e) { + (i = e), (n = "Invalid JSON response from server."); + } + this._updateFilesUploadProgress(e, t), + 200 <= t.status && t.status < 300 + ? e[0].upload.chunked + ? e[0].upload.finishedChunkUpload( + this._getChunk(e[0], t), + n + ) + : this._finished(e, n, i) + : this._handleUploadError(e, t, n); + } + }, + }, + { + key: "_handleUploadError", + value: function (e, t, i) { + if (e[0].status !== o.CANCELED) { + if (e[0].upload.chunked && this.options.retryChunks) { + var n = this._getChunk(e[0], t); + if (n.retries++ < this.options.retryChunksLimit) + return void this._uploadData(e, [n.dataBlock]); + console.warn("Retried this chunk too often. Giving up."); + } + this._errorProcessing( + e, + i || + this.options.dictResponseError.replace( + "{{statusCode}}", + t.status + ), + t + ); + } + }, + }, + { + key: "submitRequest", + value: function (e, t, i) { + if (1 == e.readyState) + if (this.options.binaryBody) + if (i[0].upload.chunked) { + var n = this._getChunk(i[0], e); + e.send(n.dataBlock.data); + } else e.send(i[0]); + else e.send(t); + else + console.warn( + "Cannot send this request because the XMLHttpRequest.readyState is not OPENED." + ); + }, + }, + { + key: "_finished", + value: function (e, t, i) { + var n = !0, + r = !1, + a = void 0; + try { + for ( + var l, s = e[Symbol.iterator](); + !(n = (l = s.next()).done); + n = !0 + ) { + var u = l.value; + (u.status = o.SUCCESS), + this.emit("success", u, t, i), + this.emit("complete", u); + } + } catch (e) { + (r = !0), (a = e); + } finally { + try { + n || null == s.return || s.return(); + } finally { + if (r) throw a; + } + } + if ( + (this.options.uploadMultiple && + (this.emit("successmultiple", e, t, i), + this.emit("completemultiple", e)), + this.options.autoProcessQueue) + ) + return this.processQueue(); + }, + }, + { + key: "_errorProcessing", + value: function (e, t, i) { + var n = !0, + r = !1, + a = void 0; + try { + for ( + var l, s = e[Symbol.iterator](); + !(n = (l = s.next()).done); + n = !0 + ) { + var u = l.value; + (u.status = o.ERROR), + this.emit("error", u, t, i), + this.emit("complete", u); + } + } catch (e) { + (r = !0), (a = e); + } finally { + try { + n || null == s.return || s.return(); + } finally { + if (r) throw a; + } + } + if ( + (this.options.uploadMultiple && + (this.emit("errormultiple", e, t, i), + this.emit("completemultiple", e)), + this.options.autoProcessQueue) + ) + return this.processQueue(); + }, + }, + ], + [ + { + key: "initClass", + value: function () { + (this.prototype.Emitter = h), + (this.prototype.events = [ + "drop", + "dragstart", + "dragend", + "dragenter", + "dragover", + "dragleave", + "addedfile", + "addedfiles", + "removedfile", + "thumbnail", + "error", + "errormultiple", + "processing", + "processingmultiple", + "uploadprogress", + "totaluploadprogress", + "sending", + "sendingmultiple", + "success", + "successmultiple", + "canceled", + "canceledmultiple", + "complete", + "completemultiple", + "reset", + "maxfilesexceeded", + "maxfilesreached", + "queuecomplete", + ]), + (this.prototype._thumbnailQueue = []), + (this.prototype._processingThumbnail = !1); + }, + }, + { + key: "uuidv4", + value: function () { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( + /[xy]/g, + function (e) { + var t = (16 * Math.random()) | 0; + return ("x" === e ? t : (3 & t) | 8).toString(16); + } + ); + }, + }, + ] + ), + o + ); + })(h); + f.initClass(), + (f.options = {}), + (f.optionsForElement = function (e) { + return e.getAttribute("id") ? f.options[v(e.getAttribute("id"))] : void 0; + }), + (f.instances = []), + (f.forElement = function (e) { + if ( + ("string" == typeof e && (e = document.querySelector(e)), + null == (null != e ? e.dropzone : void 0)) + ) + throw new Error( + "No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone." + ); + return e.dropzone; + }), + (f.discover = function () { + var e; + if (document.querySelectorAll) e = document.querySelectorAll(".dropzone"); + else { + e = []; + var t = function (t) { + return (function () { + var i = [], + n = !0, + r = !1, + a = void 0; + try { + for ( + var o, l = t[Symbol.iterator](); + !(n = (o = l.next()).done); + n = !0 + ) { + var s = o.value; + /(^| )dropzone($| )/.test(s.className) + ? i.push(e.push(s)) + : i.push(void 0); + } + } catch (e) { + (r = !0), (a = e); + } finally { + try { + n || null == l.return || l.return(); + } finally { + if (r) throw a; + } + } + return i; + })(); + }; + t(document.getElementsByTagName("div")), + t(document.getElementsByTagName("form")); + } + return (function () { + var t = [], + i = !0, + n = !1, + r = void 0; + try { + for ( + var a, o = e[Symbol.iterator](); + !(i = (a = o.next()).done); + i = !0 + ) { + var l = a.value; + !1 !== f.optionsForElement(l) ? t.push(new f(l)) : t.push(void 0); + } + } catch (e) { + (n = !0), (r = e); + } finally { + try { + i || null == o.return || o.return(); + } finally { + if (n) throw r; + } + } + return t; + })(); + }), + (f.blockedBrowsers = [/opera.*(Macintosh|Windows Phone).*version\/12/i]), + (f.isBrowserSupported = function () { + var e = !0; + if ( + window.File && + window.FileReader && + window.FileList && + window.Blob && + window.FormData && + document.querySelector + ) + if ("classList" in document.createElement("a")) { + void 0 !== f.blacklistedBrowsers && + (f.blockedBrowsers = f.blacklistedBrowsers); + var t = !0, + i = !1, + n = void 0; + try { + for ( + var r, a = f.blockedBrowsers[Symbol.iterator](); + !(t = (r = a.next()).done); + t = !0 + ) { + r.value.test(navigator.userAgent) && (e = !1); + } + } catch (e) { + (i = !0), (n = e); + } finally { + try { + t || null == a.return || a.return(); + } finally { + if (i) throw n; + } + } + } else e = !1; + else e = !1; + return e; + }), + (f.dataURItoBlob = function (e) { + for ( + var t = atob(e.split(",")[1]), + i = e.split(",")[0].split(":")[1].split(";")[0], + n = new ArrayBuffer(t.length), + r = new Uint8Array(n), + a = 0, + o = t.length, + l = 0 <= o; + l ? a <= o : a >= o; + l ? a++ : a-- + ) + r[a] = t.charCodeAt(a); + return new Blob([n], { type: i }); + }); + var m = function (e, t) { + return e + .filter(function (e) { + return e !== t; + }) + .map(function (e) { + return e; + }); + }, + v = function (e) { + return e.replace(/[\-_](\w)/g, function (e) { + return e.charAt(1).toUpperCase(); + }); + }; + (f.createElement = function (e) { + var t = document.createElement("div"); + return (t.innerHTML = e), t.childNodes[0]; + }), + (f.elementInside = function (e, t) { + if (e === t) return !0; + for (; (e = e.parentNode); ) if (e === t) return !0; + return !1; + }), + (f.getElement = function (e, t) { + var i; + if ( + ("string" == typeof e + ? (i = document.querySelector(e)) + : null != e.nodeType && (i = e), + null == i) + ) + throw new Error( + "Invalid `".concat( + t, + "` option provided. Please provide a CSS selector or a plain HTML element." + ) + ); + return i; + }), + (f.getElements = function (e, t) { + var i, n; + if (e instanceof Array) { + n = []; + try { + var r = !0, + a = !1, + o = void 0; + try { + for ( + var l = e[Symbol.iterator](); + !(r = (s = l.next()).done); + r = !0 + ) + (i = s.value), n.push(this.getElement(i, t)); + } catch (e) { + (a = !0), (o = e); + } finally { + try { + r || null == l.return || l.return(); + } finally { + if (a) throw o; + } + } + } catch (e) { + n = null; + } + } else if ("string" == typeof e) { + n = []; + (r = !0), (a = !1), (o = void 0); + try { + var s; + for ( + l = document.querySelectorAll(e)[Symbol.iterator](); + !(r = (s = l.next()).done); + r = !0 + ) + (i = s.value), n.push(i); + } catch (e) { + (a = !0), (o = e); + } finally { + try { + r || null == l.return || l.return(); + } finally { + if (a) throw o; + } + } + } else null != e.nodeType && (n = [e]); + if (null == n || !n.length) + throw new Error( + "Invalid `".concat( + t, + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those." + ) + ); + return n; + }), + (f.confirm = function (e, t, i) { + return window.confirm(e) ? t() : null != i ? i() : void 0; + }), + (f.isValidFile = function (e, t) { + if (!t) return !0; + t = t.split(","); + var i = e.type, + n = i.replace(/\/.*$/, ""), + r = !0, + a = !1, + o = void 0; + try { + for ( + var l, s = t[Symbol.iterator](); + !(r = (l = s.next()).done); + r = !0 + ) { + var u = l.value; + if ("." === (u = u.trim()).charAt(0)) { + if ( + -1 !== + e.name + .toLowerCase() + .indexOf(u.toLowerCase(), e.name.length - u.length) + ) + return !0; + } else if (/\/\*$/.test(u)) { + if (n === u.replace(/\/.*$/, "")) return !0; + } else if (i === u) return !0; + } + } catch (e) { + (a = !0), (o = e); + } finally { + try { + r || null == s.return || s.return(); + } finally { + if (a) throw o; + } + } + return !1; + }), + "undefined" != typeof jQuery && + null !== jQuery && + (jQuery.fn.dropzone = function (e) { + return this.each(function () { + return new f(this, e); + }); + }), + (f.ADDED = "added"), + (f.QUEUED = "queued"), + (f.ACCEPTED = f.QUEUED), + (f.UPLOADING = "uploading"), + (f.PROCESSING = f.UPLOADING), + (f.CANCELED = "canceled"), + (f.ERROR = "error"), + (f.SUCCESS = "success"); + var y = function (e, t, i, n, r, a, o, l, s, u) { + var c = (function (e) { + e.naturalWidth; + var t = e.naturalHeight, + i = document.createElement("canvas"); + (i.width = 1), (i.height = t); + var n = i.getContext("2d"); + n.drawImage(e, 0, 0); + for ( + var r = n.getImageData(1, 0, 1, t).data, a = 0, o = t, l = t; + l > a; + + ) + 0 === r[4 * (l - 1) + 3] ? (o = l) : (a = l), (l = (o + a) >> 1); + var s = l / t; + return 0 === s ? 1 : s; + })(t); + return e.drawImage(t, i, n, r, a, o, l, s, u / c); + }, + g = (function () { + "use strict"; + function e() { + i(this, e); + } + return ( + r(e, null, [ + { + key: "initClass", + value: function () { + this.KEY_STR = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + }, + }, + { + key: "encode64", + value: function (e) { + for ( + var t = "", + i = void 0, + n = void 0, + r = "", + a = void 0, + o = void 0, + l = void 0, + s = "", + u = 0; + (a = (i = e[u++]) >> 2), + (o = ((3 & i) << 4) | ((n = e[u++]) >> 4)), + (l = ((15 & n) << 2) | ((r = e[u++]) >> 6)), + (s = 63 & r), + isNaN(n) ? (l = s = 64) : isNaN(r) && (s = 64), + (t = + t + + this.KEY_STR.charAt(a) + + this.KEY_STR.charAt(o) + + this.KEY_STR.charAt(l) + + this.KEY_STR.charAt(s)), + (i = n = r = ""), + (a = o = l = s = ""), + u < e.length; + + ); + return t; + }, + }, + { + key: "restore", + value: function (e, t) { + if (!e.match("data:image/jpeg;base64,")) return t; + var i = this.decode64(e.replace("data:image/jpeg;base64,", "")), + n = this.slice2Segments(i), + r = this.exifManipulation(t, n); + return "data:image/jpeg;base64,".concat(this.encode64(r)); + }, + }, + { + key: "exifManipulation", + value: function (e, t) { + var i = this.getExifArray(t), + n = this.insertExif(e, i); + return new Uint8Array(n); + }, + }, + { + key: "getExifArray", + value: function (e) { + for (var t = void 0, i = 0; i < e.length; ) { + if ((255 === (t = e[i])[0]) & (225 === t[1])) return t; + i++; + } + return []; + }, + }, + { + key: "insertExif", + value: function (e, t) { + var i = e.replace("data:image/jpeg;base64,", ""), + n = this.decode64(i), + r = n.indexOf(255, 3), + a = n.slice(0, r), + o = n.slice(r), + l = a; + return (l = (l = l.concat(t)).concat(o)); + }, + }, + { + key: "slice2Segments", + value: function (e) { + for (var t = 0, i = []; ; ) { + if ((255 === e[t]) & (218 === e[t + 1])) break; + if ((255 === e[t]) & (216 === e[t + 1])) t += 2; + else { + var n = t + (256 * e[t + 2] + e[t + 3]) + 2, + r = e.slice(t, n); + i.push(r), (t = n); + } + if (t > e.length) break; + } + return i; + }, + }, + { + key: "decode64", + value: function (e) { + var t = void 0, + i = void 0, + n = "", + r = void 0, + a = void 0, + o = "", + l = 0, + s = []; + for ( + /[^A-Za-z0-9\+\/\=]/g.exec(e) && + console.warn( + "There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding." + ), + e = e.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + (t = + (this.KEY_STR.indexOf(e.charAt(l++)) << 2) | + ((r = this.KEY_STR.indexOf(e.charAt(l++))) >> 4)), + (i = + ((15 & r) << 4) | + ((a = this.KEY_STR.indexOf(e.charAt(l++))) >> 2)), + (n = + ((3 & a) << 6) | (o = this.KEY_STR.indexOf(e.charAt(l++)))), + s.push(t), + 64 !== a && s.push(i), + 64 !== o && s.push(n), + (t = i = n = ""), + (r = a = o = ""), + l < e.length; + + ); + return s; + }, + }, + ]), + e + ); + })(); + g.initClass(); + window.Dropzone = f; +})(); //# sourceMappingURL=dropzone-min.js.map diff --git a/src/ui/static/js/logs.js b/src/ui/static/js/logs.js index b84219d8f..b401b09e6 100644 --- a/src/ui/static/js/logs.js +++ b/src/ui/static/js/logs.js @@ -1,12 +1,11 @@ import { Checkbox } from "./utils.js"; -//import AirDatepicker from "./air-datepicker/index.js"; +import Datepicker from "./datepicker/datepicker.js"; class LogsDropdown { constructor(prefix = "logs") { this.prefix = prefix; this.container = document.querySelector("main"); this.initDropdown(); - this.logListContainer = document.querySelector(`[${this.prefix}-list]`); } initDropdown() { @@ -163,10 +162,9 @@ class FetchLogs { this.toDateInp = document.querySelector("input#to-date"); this.fromDate = ""; this.toDate = ""; - this.isLiveUpdate = false; this.updateDelay = 2000; - this.lastUpdate = Math.round(Date.now() / 1000 - 86400); + this.lastUpdate = Date.now() - 86400000; this.container = document.querySelector(`[${this.prefix}-settings]`); this.logListContainer = document.querySelector(`[${this.prefix}-list]`); this.submitSettings = document.querySelector("button#submit-settings"); @@ -175,8 +173,10 @@ class FetchLogs { init() { this.submitSettings.addEventListener("click", (e) => { + //remove prev logs + this.logListContainer.textContent = ""; //wait if live update previously - if (this.isLiveUpdate) { + if (this.isLiveUpdate && !this.toDate) { setTimeout(() => { const isSettings = this.getSettings(); return isSettings ? this.getLogsFromToDate() : ""; @@ -186,18 +186,46 @@ class FetchLogs { return isSettings ? this.getLogsFromToDate() : ""; } }); + //disabled/enabled filed logic + this.toDateInp.addEventListener("input", (e) => { + this.toDateInp.value + ? this.updateDelayInp.setAttribute("disabled", "") + : this.updateDelayInp.removeAttribute("disabled"); + this.toDateInp.value + ? this.liveUpdateInp.setAttribute("disabled", "") + : this.liveUpdateInp.removeAttribute("disabled"); + }); + + this.updateDelayInp.addEventListener("input", (e) => { + this.updateDelayInp.value + ? this.toDateInp.setAttribute("disabled", "") + : this.toDateInp.removeAttribute("disabled"); + }); + + this.liveUpdateInp.addEventListener("input", (e) => { + this.liveUpdateInp.checked + ? this.toDateInp.setAttribute("disabled", "") + : this.toDateInp.removeAttribute("disabled"); + }); } getSettings() { //get settings + //check valid instance name this.instanceName = this.instance.textContent; if (!this.instanceName || this.instanceName.trim() === "none") return false; - this.formDate = this.fromDateInp.valueAsNumber - ? this.fromDateInp.valueAsNumber - : Math.round(Date.now() / 1000 - 86400); - this.toDate = this.toDateInp.valueAsNumber - ? this.toDateInp.valueAsNumber - : ""; + //if a date value exist, check if is a timestamp + if (this.fromDateInp.value && isNaN(Date.parse(this.fromDateInp.value))) + return false; + if (this.toDateInp.value && isNaN(Date.parse(this.toDateInp.value))) + return false; + //check valid date + this.fromDate = Date.parse(this.fromDateInp.value) + ? Date.parse(this.fromDateInp.value) + : Date.now() - 86400000; + this.toDate = Date.parse(this.toDateInp.value) + ? Date.parse(this.toDateInp.value) + : false; this.updateDelay = this.updateDelayInp.value * 1000 ? this.updateDelayInp.value : 2000; this.isLiveUpdate = this.liveUpdateInp.checked; @@ -214,9 +242,19 @@ class FetchLogs { } async getLogsFromToDate() { - const response = await fetch( - `${location.href}/${this.lastUpdate}?from_date=${this.fromDate}?to_date=${this.toDate}` - ); + console.log(this.fromDate, this.toDate); + let response; + if (this.toDate) { + response = await fetch( + `${location.href}/${this.instanceName}?from_date=${this.fromDate}&to_date=${this.toDate}` + ); + } + + if (!this.toDate) { + response = await fetch( + `${location.href}/${this.instanceName}?from_date=${this.fromDate}` + ); + } if (response.status === 200) { const res = await response.json(); @@ -230,7 +268,7 @@ class FetchLogs { async getLogsSinceLastUpdate() { const response = await fetch( - `${location.href}/${this.lastUpdate}` + + `${location.href}/${this.instanceName}` + (this.lastUpdate ? `?last_update=${this.lastUpdate}` : "") ); @@ -272,8 +310,8 @@ class FetchLogs { setTimeout(() => { this.goBottomList(); }, 100); - //loop if true - if (this.isLiveUpdate) { + //loop if no to date and live update true + if (this.isLiveUpdate && !this.toDate) { setTimeout(() => { this.getLogsSinceLastUpdate(); }, this.updateDelay); @@ -286,7 +324,7 @@ class FilterLogs { this.prefix = prefix; this.container = document.querySelector(`[${this.prefix}-filter]`); this.keyInp = document.querySelector("input#keyword"); - this.lastType = ""; + this.lastType = "all"; this.initHandler(); } @@ -329,7 +367,6 @@ class FilterLogs { //filter type this.setFilterType(logs); this.setFilterKeyword(logs); - this.setFilterDate(logs); } setFilterType(logs) { @@ -350,17 +387,30 @@ class FilterLogs { } setFilterKeyword(logs) { - const keyword = this.keyInp.value; + const keyword = this.keyInp.value.trim().toLowerCase(); if (!keyword) return; for (let i = 0; i < logs.length; i++) { const el = logs[i]; - const content = el.querySelector("[logs-content]").textContent; + const content = el + .querySelector("[logs-content]") + .textContent.trim() + .toLowerCase(); if (!content.includes(keyword)) el.classList.add("hidden"); } } } +class LogsDate { + constructor(el, options = {}) { + this.datepicker = new Datepicker(el, options); + this.init(); + this.container = document.querySelector("[logs-settings]"); + } +} + const setCheckbox = new Checkbox("[logs-settings]"); const dropdown = new LogsDropdown(); const setLogs = new FetchLogs(); const setFilter = new FilterLogs(); +const fromDatepicker = new LogsDate(document.querySelector("input#from-date")); +const toDatepicker = new LogsDate(document.querySelector("input#to-date")); diff --git a/src/ui/static/js/plugins.js b/src/ui/static/js/plugins.js index a25a4a64a..476b6da53 100644 --- a/src/ui/static/js/plugins.js +++ b/src/ui/static/js/plugins.js @@ -1,30 +1,247 @@ -import AirDatepicker from "./air-datepicker/index.es.js"; - class Upload { - constructor(prefix) { - this.prefix = prefix; - this.uploadDOM = document.querySelector(`[${this.prefix}-upload-button]`); - this.uploadTxt = document.querySelector(`[${this.prefix}-upload-text]`); - this.uploadInp = document.querySelector(`[${this.prefix}-upload-input]`); - this.dragNdrop = document.querySelector(`[${this.prefix}-drag-and-drop]`); + constructor() { + this.dropEl = document.querySelector("#dropzone"); + this.drop = new Dropzone(this.dropEl, { + paramName: "file", + method: "post", + maxFiles: 100, + autoProcessQueue: false, + uploadMultiple: true, + parallelUploads: 100, + url: "#", + }); + this.submitBtn = this.dropEl.querySelector('button[type="submit"]'); this.init(); } init() { - this.uploadDOM.addEventListener("click", (e) => { - this.uploadInp.click(); - }); - - this.uploadInp.addEventListener("change", (e) => { - this.uploadTxt.textContent = "FILES : "; - const files = this.uploadInp.files; - for (let i = 0; i < files.length; i++) { - const file = files[i]; - const spanEl = document.createElement("span"); - spanEl.textContent = - i == files.length - 1 ? `${file.name};` : `${file.name}, `; - this.uploadTxt.append(spanEl); - } + this.submitBtn.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + drop.processQueue(); }); } } + +class PluginsDropdown { + constructor(prefix = "plugins") { + this.prefix = prefix; + this.container = document.querySelector("main"); + this.initDropdown(); + } + + initDropdown() { + this.container.addEventListener("click", (e) => { + //SELECT BTN LOGIC + try { + if ( + e.target + .closest("button") + .hasAttribute(`${this.prefix}-setting-select`) && + !e.target.closest("button").hasAttribute(`disabled`) + ) { + this.toggleSelectBtn(e); + } + } catch (err) {} + //SELECT DROPDOWN BTN LOGIC + try { + if ( + e.target + .closest("button") + .hasAttribute(`${this.prefix}-setting-select-dropdown-btn`) + ) { + const btn = e.target.closest("button"); + const btnValue = btn.getAttribute("value"); + const btnSetting = btn.getAttribute( + `${this.prefix}-setting-select-dropdown-btn` + ); + //stop if same value to avoid new fetching + const isSameVal = this.isSameValue(btnSetting, btnValue); + if (isSameVal) return this.hideDropdown(btnSetting); + //else, add new value to custom + this.setSelectNewValue(btnSetting, btnValue); + //close dropdown and change style + this.hideDropdown(btnSetting); + this.changeDropBtnStyle(btnSetting, btn); + //show / hide filter + if (btnSetting === "instances") { + this.hideFilterOnLocal(btn.getAttribute("_type")); + } + } + } catch (err) {} + }); + } + + isSameValue(btnSetting, value) { + const selectCustom = document.querySelector( + `[${this.prefix}-setting-select-text="${btnSetting}"]` + ); + const currVal = selectCustom.textContent; + return currVal === value ? true : false; + } + + setSelectNewValue(btnSetting, value) { + const selectCustom = document.querySelector( + `[${this.prefix}-setting-select="${btnSetting}"]` + ); + selectCustom.querySelector( + `[${this.prefix}-setting-select-text]` + ).textContent = value; + } + + hideDropdown(btnSetting) { + //hide dropdown + const dropdownEl = document.querySelector( + `[${this.prefix}-setting-select-dropdown="${btnSetting}"]` + ); + dropdownEl.classList.add("hidden"); + dropdownEl.classList.remove("flex"); + //svg effect + const dropdownChevron = document.querySelector( + `svg[${this.prefix}-setting-select="${btnSetting}"]` + ); + dropdownChevron.classList.remove("rotate-180"); + } + + changeDropBtnStyle(btnSetting, selectedBtn) { + const dropdownEl = document.querySelector( + `[${this.prefix}-setting-select-dropdown="${btnSetting}"]` + ); + //reset dropdown btns + const btnEls = dropdownEl.querySelectorAll("button"); + + btnEls.forEach((btn) => { + btn.classList.remove( + "dark:bg-primary", + "bg-primary", + "bg-primary", + "text-gray-300", + "text-gray-300" + ); + btn.classList.add("bg-white", "dark:bg-slate-700", "text-gray-700"); + }); + //highlight clicked btn + selectedBtn.classList.remove( + "bg-white", + "dark:bg-slate-700", + "text-gray-700" + ); + selectedBtn.classList.add("dark:bg-primary", "bg-primary", "text-gray-300"); + } + + toggleSelectBtn(e) { + const attribut = e.target + .closest("button") + .getAttribute(`${this.prefix}-setting-select`); + //toggle dropdown + const dropdownEl = document.querySelector( + `[${this.prefix}-setting-select-dropdown="${attribut}"]` + ); + const dropdownChevron = document.querySelector( + `svg[${this.prefix}-setting-select="${attribut}"]` + ); + dropdownEl.classList.toggle("hidden"); + dropdownEl.classList.toggle("flex"); + dropdownChevron.classList.toggle("rotate-180"); + } + + //hide date filter on local + hideFilterOnLocal(type) { + console.log(type); + if (type === "local") { + this.hideInp(`input#from-date`); + this.hideInp(`input#to-date`); + } + + if (type !== "local") { + this.showInp(`input#from-date`); + this.showInp(`input#to-date`); + } + } + + showInp(selector) { + document.querySelector(selector).closest("div").classList.add("flex"); + document.querySelector(selector).closest("div").classList.remove("hidden"); + } + + hideInp(selector) { + document.querySelector(selector).closest("div").classList.add("hidden"); + document.querySelector(selector).closest("div").classList.remove("flex"); + } +} + +class FilterPlugins { + constructor(prefix = "plugins") { + this.prefix = prefix; + this.container = document.querySelector(`[${this.prefix}-filter]`); + this.keyInp = document.querySelector("input#keyword"); + this.lastType = "all"; + this.initHandler(); + } + + initHandler() { + //TYPE HANDLER + this.container.addEventListener("click", (e) => { + try { + if ( + e.target + .closest("button") + .getAttribute(`${this.prefix}-setting-select-dropdown-btn`) === + "types" + ) { + const btn = e.target.closest("button"); + const btnValue = btn.getAttribute("value"); + + this.lastType = btnValue; + console.log(this.lastType); + //run filter + this.filter(); + } + } catch (err) {} + }); + //KEYWORD HANDLER + this.keyInp.addEventListener("input", (e) => { + this.filter(); + }); + } + + filter() { + const logs = document.querySelector(`[${this.prefix}-list]`).children; + if (logs.length === 0) return; + //reset + for (let i = 0; i < logs.length; i++) { + const el = logs[i]; + el.classList.remove("hidden"); + } + //filter type + this.setFilterType(logs); + this.setFilterKeyword(logs); + } + + setFilterType(logs) { + if (this.lastType === "all") return; + for (let i = 0; i < logs.length; i++) { + const el = logs[i]; + const type = el.getAttribute(`${this.prefix}-external`).trim(); + if (type !== this.lastType) el.classList.add("hidden"); + } + } + + setFilterKeyword(logs) { + const keyword = this.keyInp.value.trim().toLowerCase(); + if (!keyword) return; + for (let i = 0; i < logs.length; i++) { + const el = logs[i]; + const content = el + .querySelector(`[${this.prefix}-content]`) + .textContent.trim() + .toLowerCase(); + + if (!content.includes(keyword)) el.classList.add("hidden"); + } + } +} + +const setUpload = new Upload(); +const setDropdown = new PluginsDropdown(); +const setFilter = new FilterPlugins(); diff --git a/src/ui/templates/global_config.html b/src/ui/templates/global_config.html index a2d11980e..1c746f9c6 100644 --- a/src/ui/templates/global_config.html +++ b/src/ui/templates/global_config.html @@ -8,7 +8,7 @@ config["CONFIG"].get_config() %} global-config-form id="form-edit-global-configs" method="POST" - class="flex flex-col justify-between min-h-50-screen dark:brightness-110 col-span-12 break-words bg-white shadow-xl p-4 dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border" + class="flex flex-col justify-between overflow-hidden overflow-y-auto max-h-135 md:max-h-160 dark:brightness-110 col-span-12 break-words bg-white shadow-xl p-4 dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border" > diff --git a/src/ui/templates/head.html b/src/ui/templates/head.html index 44ac21187..d6cf815f1 100644 --- a/src/ui/templates/head.html +++ b/src/ui/templates/head.html @@ -34,14 +34,24 @@ {% elif current_endpoint == "services" %} {% elif current_endpoint == "plugins" %} - - + + {% elif current_endpoint == "cache" %} {% elif current_endpoint == "logs" %} - + + + {% endif %} diff --git a/src/ui/templates/home.html b/src/ui/templates/home.html index c93a6757f..a0f030b58 100644 --- a/src/ui/templates/home.html +++ b/src/ui/templates/home.html @@ -66,7 +66,7 @@
{{ instances_number }}

1 / {{ instances_number }}{{instance_health_count}} / {{ instances_number }} is working

@@ -104,10 +104,18 @@

{{ services_number }}

- last created is service-1{{services_ui_count}} + ui, + {{services_scheduler_count}} + scheduler, + {{services_autoconf_count}} + autoconf

@@ -145,7 +153,7 @@
1

0{{plugins_errors}} error

diff --git a/src/ui/templates/jobs.html b/src/ui/templates/jobs.html index d49fa6bd2..21095dfd2 100644 --- a/src/ui/templates/jobs.html +++ b/src/ui/templates/jobs.html @@ -1,60 +1,58 @@ {% extends "base.html" %} {% block content %} {% set current_endpoint = url_for(request.endpoint)[1:].split("/")[-1].strip() %} + +
+
INFO
+
+

+ JOBS TOTAL +

+

+ {{jobs_total}} +

+
+
+

+ JOBS ERROS +

+

+ {{jobs_errors}} +

+
+
+

+ AUTO UPDATE +

+

+ 2 mins +

+
+
+ +
FILTER
- -
-
- Update auto -
-
- - - - -
-
- - -
-
- Update delay (in seconds) -
- -
- -
+
@@ -64,34 +62,34 @@ url_for(request.endpoint)[1:].split("/")[-1].strip() %} type="text" id="keyword" name="keyword" - class="col-span-12 sm:col-span-6 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500" + class="dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500" placeholder="key words" pattern="(.*?)" required />
- -
+ +
- Select types + Sort by
+ + +
+ +
+ + +
+
+ Select success +
+ + + +
- + + +
+
+ Select reload +
+ + + + + +
+
-
LOGS
+
{{current_endpoint}}
-
+

-

    - {% for job in jobs %} +
      + {% for job in jobs %} {{job['every']}}
    • - {{job["last_run"]}} + {{job['last_run']}}

      BunkerWeb UI - - - + + + -

      - {% if error %} - - {% endif %} {% with messages = get_flashed_messages(with_categories=true) - %} {% if messages %} {% for category, message in messages %} - - {% endfor %} {% endif %} {% endwith %} + {% if error %} + + {% with messages = get_flashed_messages(with_categories=true) %} {% if + messages %} {% for category, message in messages %} + -
      -
      -
      - -
      - + {% endfor %} {% endif %} {% endwith %} {%endif %} + + +
      + +
      +
      +
      logo
      +

      + Log in +

      +
      + + + +
      +
      + Username +
      + +
      + + +
      +
      + Password +
      + +
      + +
      + +
      +
      +
      +
      + + +
      + +
      + + - - - diff --git a/src/ui/templates/logs.html b/src/ui/templates/logs.html index f83e44480..7109446fb 100644 --- a/src/ui/templates/logs.html +++ b/src/ui/templates/logs.html @@ -71,11 +71,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %} From date @@ -91,11 +91,11 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %} To date @@ -144,14 +144,14 @@ url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %} type="number" id="update-delay" name="update-delay" - class="col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500" + class="disabled:bg-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 dark:disabled:text-gray-300 disabled:text-gray-700 col-span-12 sm:col-span-6 lg:col-span-4 3xl:col-span-3 dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-3 py-1 font-normal text-gray-700 transition-all placeholder:text-gray-500" placeholder="2" pattern="(.*?)" required />
      -
      +
      @@ -322,6 +352,12 @@
      +
      - -
      -
      UPLOAD PLUGIN
      -
      INFO +
      +

      + TOTAL PLUGINS +

      +

      + {{plugins_total}} +

      +
      +
      +

      + INTERNAL PLUGINS +

      +

      + {{plugins_internal}} +

      +
      +
      +

      + EXTERNAL PLUGINS +

      +

      + {{plugins_external}} +

      +
      +
      +

      + PLUGINS ERRORS +

      +

      + {{plugins_errors}} +

      +
      +
      + + + +
      +
      UPLOAD PLUGIN
      + +
      + + - - -
      - -
      -
      - - -
      -
      LIST PLUGIN
      - {% if pages %} - - - {% endfor %} {% endif %} + Reload + + +
      +
      +
      + + + +
      +
      FILTER
      +
      + +
      +
      + Search +
      + +
      + + +
      +
      + Select types +
      + + + + + +
      + +
      +
      + + +
      +
      LIST
      + +
      + {% for plugin in plugins %} {% if plugin['page'] %} + +

      + {{plugin['name']}} +

      + + + +
      + {% else %} +
      +

      + {{plugin['name']}} +

      +
      + {% endif %} {% endfor %}
      {% endblock %} diff --git a/src/ui/templates/settings_general.html b/src/ui/templates/settings_general.html index e6b22978f..71d0c4a06 100644 --- a/src/ui/templates/settings_general.html +++ b/src/ui/templates/settings_general.html @@ -48,7 +48,7 @@ {% if value["type"] != "select" and value["type"] != "check" %} - {% endif %} @@ -57,7 +57,7 @@ {% if value["type"] == "select" %} - {% endif %} @@ -62,7 +62,7 @@ {% if value["type"] == "select" %}
      - {% if current_endpoint != "services" %}general {% else %} {% endif %} + general - + {% if current_endpoint == "global-config" %}general {% endif %} str: - if root is None: - root = BeautifulSoup() - - tooltip = Tag( - name="div", - attrs={ - "class": "px-2 d-sm-inline", - "data-bs-toggle": "tooltip", - "data-bs-placement": "bottom", - "title": _help, - }, - ) - tooltip.append(Tag(name="i", attrs={"class": "fas fa-question-circle"})) - root.append(tooltip) - pt = "" - invalid_div = None - - if _type in ("text", "number"): - edit = Tag( - name="input", - attrs={ - "type": _type, - "class": "form-control", - "id": _id, - "name": name, - "value": value if value else default, - "pattern": regex, - }, - ) - - invalid_div = Tag(name="div", attrs={"class": "invalid-feedback"}) - invalid_div.append( - BeautifulSoup( - f"{label} is invalid and must match this pattern: {regex}", - "html.parser", - ) - ) - elif _type == "check": - edit = Tag( - name="div", - attrs={"class": "form-check form-switch"}, - ) - edit.append( - BeautifulSoup( - f"", - "html.parser", - ) - ) - edit.append( - Tag( - name="input", - attrs={ - "type": "hidden", - "id": f"{_id}-hidden", - "name": name, - "value": "off", - }, - ) - ) - pt = "pt-0" - elif _type == "select": - edit = Tag( - name="select", - attrs={ - "type": "form-select", - "class": "form-control form-select", - "id": _id, - "name": name, - }, - ) - - for select in selects: - edit.append( - BeautifulSoup( - f"", - "html.parser", - ) - ) - - label_tag = Tag( - name="label", attrs={"for": _id, "class": f"flex-grow-1 d-sm-inline {pt}"} - ) - label_tag.append(label) - root.append(label_tag) - - div = Tag(name="div", attrs={"class": "d-sm-inline"}) - div.append(edit) - - if invalid_div: - div.append(invalid_div) - - root.append(div) - - if from_html: - return root.prettify() - else: - return root - - -def form_service_gen_multiple(_id, label, params, root) -> Tag: - label_tag = Tag( - name="label", - attrs={"for": f"{_id}-btn", "class": "flex-grow-1 d-sm-inline"}, - ) - label_tag.append(label) - root.append(label_tag) - - buttons = Tag(name="div", attrs={"class": "d-sm-inline", "id": _id}) - - add_button = Tag( - name="button", - attrs={ - "class": "btn btn-outline-success", - "type": "button", - "onClick": f"addMultiple('{_id}', '{json.dumps(params)}');", - }, - ) - add_button.append(Tag(name="i", attrs={"class": "fas fa-plus"})) - add_button.append(" Add") - buttons.append(add_button) - - del_button = Tag( - name="button", - attrs={ - "class": "btn btn-outline-danger", - "type": "button", - "onClick": f"delMultiple('{_id}', '{json.dumps(params)}');", - }, - ) - del_button.append(Tag(name="i", attrs={"class": "fas fa-trash"})) - del_button.append(" Delete") - buttons.append(del_button) - - root.append(buttons) - return root - - -def form_service_gen_multiple_values(_id, params, service) -> Union[Tag, str]: - script = Tag(name="script", attrs={"defer": True}) - values = [] - for env in sorted( - service, - reverse=True, - key=lambda x: int(re.search(r"\d+$", x).group()) if x[-1].isdigit() else 0, - ): - for param, param_value in params.items(): - suffix = env.replace(param, "") - if env.startswith(param): - values.append( - { - "default": service.get( - f"{param}{suffix}", param_value["default"] - ), - "env": param, - "help": param_value["help"], - "id": param_value["id"], - "label": param_value["label"], - "selects": param_value.get("selects", []), - "type": param_value["type"], - } - ) - - if len(values) >= len(params): - script.append(f"addMultiple('{_id}', '{json.dumps(values)}');") - values = [] - - return script if script.children else "" - - -def form_plugin_gen( - service: dict, - plugin: dict, - action: str, - id_server_name: str = None, - *, - context: str = "multisite", -) -> str: - soup = BeautifulSoup() - soup.append( - Tag( - name="div", - attrs={ - "class": "tab-pane fade", - "id": f"{action}-{plugin['id']}" - + (f"-{id_server_name}" if id_server_name else ""), - "role": "tabpanel", - "aria-labelledby": f"{action}-{plugin['id']}" - + (f"-{id_server_name}" if id_server_name else "") - + "-tab", - }, - ) - ) - multiple_plugins = {} - multiple = None - - for setting, value in plugin["settings"].items(): - if value["context"] == context: - if "multiple" in value: - if multiple != value["multiple"]: - multiple = value["multiple"] - multiple_plugins[multiple] = {} - multiple_plugins[multiple][setting] = value - multiple_plugins[multiple][setting]["env"] = setting - else: - div = Tag( - name="div", - attrs={ - "class": "d-flex flex-row justify-content-between align-items-center mb-3", - "id": f"form-{action}" - + (f"-{id_server_name}" if id_server_name else "") - + f"-{value['id']}", - }, - ) - - div = form_service_gen( - f"form-{action}" - + (f"-{id_server_name}" if id_server_name else "") - + f"-{value['id']}", - value["help"], - value["label"], - value["type"], - service.get(setting, value["default"]), - setting, - value["default"], - value.get("select", None), - value["regex"], - False, - div, - ) - - soup.div.append(div) - - for multiple_plugin in multiple_plugins: - div = Tag( - name="div", - attrs={ - "class": "d-flex flex-row justify-content-between align-items-center mb-3", - "id": f"form-{action}" - + (f"-{id_server_name}" if id_server_name else "") - + f"-{multiple_plugin}", - }, - ) - - div = form_service_gen_multiple( - f"form-{action}" - + (f"-{id_server_name}" if id_server_name else "") - + f"-{multiple_plugin}", - plugin["name"], - multiple_plugins[multiple_plugin], - div, - ) - if service: - div.append( - form_service_gen_multiple_values( - f"form-{action}" - + (f"-{id_server_name}" if id_server_name else "") - + f"-{multiple_plugin}", - multiple_plugins[multiple_plugin], - service, - ) - ) - - soup.div.append(div) - - return soup.prettify() - - def path_to_dict( path, *, @@ -468,256 +171,5 @@ def path_to_dict( return d -options = { - "can_edit": { - "button_style": "btn-outline-primary", - "data-bs-target": "#modal-edit-new-folder", - "icon": "fa-solid fa-pen-to-square", - }, - "can_delete": { - "button_style": "btn-outline-danger", - "data-bs-target": "#modal-delete", - "icon": "fa-solid fa-trash-can", - }, - "can_create_folders": { - "button_style": "btn-outline-success", - "data-bs-target": "#modal-edit-new-folder", - "icon": "fa-solid fa-folder", - }, - "can_create_files": { - "button_style": "btn-outline-success", - "data-bs-target": "#modal-edit-new-file", - "icon": "fa-solid fa-file", - }, -} - - -def gen_folders_tree_html(data: list) -> str: - html = "
        " - - for _dict in sorted(data, key=lambda x: x["type"] == "file", reverse=True): - path_id = _dict["path"].replace("/", "-")[1:] - root_li = Tag( - name="li", - attrs={ - "class": f"{_dict['type']}-item d-flex align-items-center", - }, - ) - - if _dict["type"] == "folder": - root_div = Tag( - name="div", - attrs={ - "class": "collapse-div", - "data-bs-toggle": "collapse", - "href": f"#{path_id}", - "role": "button", - "aria-expanded": "true", - "aria-controls": path_id, - }, - ) - - h6 = Tag(name="span", attrs={"class": "mb-0 pl-2"}) - h6.append(_dict["name"]) - - if _dict.get("children", False): - root_div.append( - Tag( - name="span", - attrs={"class": f"fa-solid fa-play fa-xs rotate-icon down"}, - ) - ) - - root_div.append(h6) - - root_li.append(root_div) - - if any( - [ - _dict["can_create_files"], - _dict["can_create_folders"], - _dict["can_edit"], - _dict["can_delete"], - ] - ): - div = Tag( - name="div", attrs={"class": "ms-2 d-sm-flex align-items-between"} - ) - dropdown = None - - if any( - [ - _dict["can_create_files"], - _dict["can_create_folders"], - ] - ): - dropdown = Tag(name="div", attrs={"class": "badge dropdown"}) - button = Tag( - name="button", - attrs={ - "type": "button", - "class": "btn btn-outline-success", - "id": "dropdownSettingsButton", - "data-bs-toggle": "dropdown", - "aria-expanded": "false", - }, - ) - button.append(Tag(name="i", attrs={"class": "fa-solid fa-plus"})) - dropdown.append(button) - ul = Tag( - name="ul", - attrs={ - "class": "dropdown-menu", - "aria-labelledby": "dropdownSettingsButton", - }, - ) - - for option in options: - if _dict[option]: - if option in ("can_create_files", "can_create_folders"): - li = Tag(name="li") - - button = Tag( - name="button", - attrs={ - "class": "dropdown-item", - "data-bs-toggle": "modal", - "data-bs-target": options[option]["data-bs-target"], - "data-path": _dict["path"], - "data-action": "new", - }, - ) - button.append( - Tag( - name="i", - attrs={ - "class": options[option]["icon"], - }, - ) - ) - - span = Tag( - name="span", - attrs={"class": "pl-2"}, - ) - span.append(option.split("_")[-1][0:-1].title()) - button.append(span) - - li.append(button) - ul.append(li) - else: - badge = Tag(name="div", attrs={"class": "badge px-1"}) - action = option.split("_")[1] - button = Tag( - name="button", - attrs={ - "class": f"btn {options[option]['button_style']}", - "data-bs-toggle": "modal", - "data-bs-target": options[option]["data-bs-target"], - "data-path": _dict["path"], - } - | ( - {"data-action": action} - if action != "delete" - else {} - ), - ) - button.append( - Tag(name="i", attrs={"class": options[option]["icon"]}) - ) - - badge.append(button) - div.append(badge) - - if dropdown: - dropdown.append(ul) - div.append(dropdown) - - root_li.append(div) - - html += root_li.prettify() - html += ( - f"
      • " - if _dict.get("children", False) - else "
      • " - ) - - if _dict.get("children", False): - html += gen_folders_tree_html(_dict["children"]) - html += "
    • " - else: - h6 = Tag(name="h6", attrs={"class": "mb-0"}) - h6.append(_dict["name"]) - root_li.append(h6) - - div = Tag(name="div", attrs={"class": "ms-2 d-sm-flex align-items-between"}) - - if _dict["can_edit"]: - badge = Tag(name="div", attrs={"class": "badge px-1"}) - button = Tag( - name="button", - attrs={ - "class": f"btn btn-outline-primary", - "data-bs-toggle": "modal", - "data-bs-target": "#modal-edit-new-file", - "data-path": _dict["path"], - "data-content": _dict["content"], - "data-action": "edit", - }, - ) - button.append( - Tag(name="i", attrs={"class": "fa-solid fa-pen-to-square"}) - ) - badge.append(button) - div.append(badge) - - badge = Tag(name="div", attrs={"class": "badge px-1"}) - button = Tag( - name="button", - attrs={ - "class": f"btn btn-outline-danger", - "data-bs-toggle": "modal", - "data-bs-target": "#modal-delete", - "data-path": _dict["path"], - }, - ) - button.append(Tag(name="i", attrs={"class": "fa-solid fa-trash-can"})) - badge.append(button) - div.append(badge) - elif "content" in _dict: - badge = Tag(name="div", attrs={"class": "badge px-1"}) - button = Tag( - name="button", - attrs={ - "class": f"btn btn-outline-secondary", - "data-bs-toggle": "modal", - "data-bs-target": "#modal-see-file", - "data-path": _dict["path"], - "data-content": _dict["content"], - }, - ) - button.append(Tag(name="i", attrs={"class": "fa-solid fa-eye"})) - badge.append(button) - div.append(badge) - - if _dict["can_download"]: - badge = Tag(name="div", attrs={"class": "badge px-1"}) - button = Tag( - name="button", - attrs={ - "class": f"btn btn-outline-primary download-button", - "data-path": _dict["path"], - }, - ) - button.append(Tag(name="i", attrs={"class": "fa-solid fa-download"})) - badge.append(button) - div.append(badge) - - root_li.append(div) - html += root_li.prettify() - - return html - - def check_settings(settings: dict, check: str) -> bool: return any(setting["context"] == check for setting in settings.values())