From 3615193e2031b0ba8b556ad17b3172c875668c22 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Wed, 31 Jul 2024 14:23:36 +0200 Subject: [PATCH 001/106] REL: Begin next release cycle --- CHANGELOG.md | 16 ++++++++++++++++ setup.py | 4 ++-- src/doc/conf.py | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92180a7d..831ea7fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] ## + +### Added ### + +### Changed ### + +### Deprecated ### + +### Removed ### + +### Fixed ### + +### Security ### + +### Documentation ### + ## [0.12.0] - 2024-07-31 ## ### Added ### diff --git a/setup.py b/setup.py index 03c515e6..bee11751 100755 --- a/setup.py +++ b/setup.py @@ -47,9 +47,9 @@ from setuptools import find_packages, setup MAJOR = 0 MINOR = 12 -MICRO = 0 +MICRO = 1 PRE = "" # e.g. rc0, alpha.1, 0.beta-23 -ISRELEASED = True +ISRELEASED = False if PRE: VERSION = "{}.{}.{}-{}".format(MAJOR, MINOR, MICRO, PRE) diff --git a/src/doc/conf.py b/src/doc/conf.py index 0fc4ff08..2aa08622 100644 --- a/src/doc/conf.py +++ b/src/doc/conf.py @@ -27,9 +27,9 @@ copyright = '2023, IndiScale GmbH' author = 'Daniel Hornung' # The short X.Y version -version = '0.12.0' +version = '0.12.1' # The full version, including alpha/beta/rc tags -release = '0.12.0' +release = '0.12.1-dev' # -- General configuration --------------------------------------------------- -- GitLab From 6362238ea7f1b231f4b509422acffaa591a2e243 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Tue, 6 Aug 2024 16:52:16 +0200 Subject: [PATCH 002/106] WIP: Add docstrings to more of loadfile's methods --- src/caosadvancedtools/loadFiles.py | 86 ++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index 77872d1d..24b7ddc3 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -40,6 +40,10 @@ timeout_fallback = 20 def convert_size(size): + """Convert `size` from B to a human-readable file size in KB, + MB, ... + + """ if (size == 0): return '0B' size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") @@ -51,8 +55,24 @@ def convert_size(size): def combine_ignore_files(caosdbignore, localignore, dirname=None): - """appends the contents of localignore to caosdbignore and saves the result - and returns the name + """Append the contents of localignore to caosdbignore, save the result, + and return the name. + + Parameters + ---------- + caosdbignore : str + Path to parent level caosdbignore file + localignore : str + Path to current working directory's local caosdbignore. + dirname : str, optional + The path of the directory to which the temporary combined file + is written. If None is given, `NamedTemporaryFile`'s default + is used. Default is None. + + Returns + ------- + name : str + Name of the temporary combined caosdbignore file. """ @@ -67,8 +87,21 @@ def combine_ignore_files(caosdbignore, localignore, dirname=None): def compile_file_list(caosdbignore, localpath): - """creates a list of files that contain all files under localpath except - those excluded by caosdbignore + """Create a list of files that contain all files under localpath except + those excluded by caosdbignore. + + Parameters + ---------- + caosdbignore : str + Path of caosdbignore file + localpath : str + Path of the directory from which the file list will be compiled. + + Returns + ------- + file_list : list[str] + List of files in `localpath` after appling the ignore rules + from `caosdbignore`. """ @@ -111,9 +144,27 @@ def compile_file_list(caosdbignore, localpath): def create_re_for_file_list(files, localroot, remoteroot): - """creates a regular expression that matches file paths contained in the - files argument and all parent directories. The prefix localroot is replaced - by the prefix remoteroot. + """Create a regular expression that matches file paths contained + in the files argument and all parent directories. The prefix + localroot is replaced by the prefix remoteroot. + + Parameters + ---------- + files : list[str] + List of file paths to be converted to a regular expression. + localroot : str + Prefix (of the local directory root) to be removed from the + paths in `files`. + remoteroot : str + Prefix (of the LinkAhead filesystem's directory root) to be + prepended to the file paths after the removal of the + `localroot` prefix. + + Returns + ------- + regexp : str + Regular expression that matches all file paths from `files` + adapted for the remote directory root. """ regexp = "" @@ -130,6 +181,19 @@ def create_re_for_file_list(files, localroot, remoteroot): def loadpath(path, include, exclude, prefix, dryrun, forceAllowSymlinks, caosdbignore=None, localpath=None): + """Make all files in `path` available to the LinkAhead server as FILE entities. + + Parameters + ---------- + path : str + Path to the directory the files of which are to be made + available as seen by the linkahead server (i.e., the path from + within the Docker container in a typical LinkAhead Control + setup.) + include : str + + + """ if caosdbignore: # create list of files and create regular expression for small chunks @@ -182,7 +246,11 @@ def loadpath(path, include, exclude, prefix, dryrun, forceAllowSymlinks, caosdbi def main(argv=None): - '''Command line options.''' + """Run `loadpath` with the arguments specified on the command + line, extended by the optional `argv` parameter. See ``--help`` + for more information. + + """ if argv is None: argv = sys.argv @@ -191,7 +259,7 @@ def main(argv=None): # Setup argument parser parser = ArgumentParser(description=""" -Make files that the LinkAhead server can see available als FILE entities. +Make files that the LinkAhead server can see available as FILE entities. In a typical scenario where LinkAhead runs in a Docker container and a host directory `mydir` is mounted as an extroot with name `myext`, loadfiles could be called like this: -- GitLab From 0b01d3f078113135261df79bd1bd32cbfe75be16 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Wed, 7 Aug 2024 10:01:05 +0200 Subject: [PATCH 003/106] DOC: Improve docstrings in loadFiles --- src/caosadvancedtools/loadFiles.py | 35 ++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index 24b7ddc3..1c7d7bf9 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -181,7 +181,12 @@ def create_re_for_file_list(files, localroot, remoteroot): def loadpath(path, include, exclude, prefix, dryrun, forceAllowSymlinks, caosdbignore=None, localpath=None): - """Make all files in `path` available to the LinkAhead server as FILE entities. + """Make all files in `path` available to the LinkAhead server as + FILE entities. + + Notes + ----- + Run ``linkahead-loadfiles --help`` for more information and examples. Parameters ---------- @@ -190,9 +195,31 @@ def loadpath(path, include, exclude, prefix, dryrun, forceAllowSymlinks, caosdbi available as seen by the linkahead server (i.e., the path from within the Docker container in a typical LinkAhead Control setup.) - include : str - - + include : str or None + Regular expression matching the files that will be + included. If None, all files are matched. This is ignored if a + `caosdbignore` is provided. + exclude : str or None + Regular expression matching files that are to be included. + prefix : str + The prefix under which the files are to be inserted into + LinkAhead's file system. + dryrun : bool + Whether a dryrun should be performed. + forceAllowSymlinks : bool + Whether symlinks in the `path` to be inserted should be + processed. + caosdbignore : str, optional + Path to a caosdbignore file that defines which files shall be + included and which do not. The syntax is the same as in a + gitignore file. You must also provide the `localpath` option + since the check is done locally. If this is given, any + `include` is ignored. + localpath : str, optional + Path of `path` on the local machine. Only needed in the + combination with a `caosdbignore` file since it is processed + locally. + """ if caosdbignore: -- GitLab From 6a4dddbd04e320baaf7c83ee6f56e4948707d290 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Wed, 7 Aug 2024 10:01:19 +0200 Subject: [PATCH 004/106] DOC: Add short section on loadFiles to utilities documentation --- src/doc/utilities.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/doc/utilities.rst b/src/doc/utilities.rst index 4d520ae2..45874352 100644 --- a/src/doc/utilities.rst +++ b/src/doc/utilities.rst @@ -35,3 +35,24 @@ behavior can be changed by initializing the ``TableImporter`` with :py:class:`~caosadvancedtools.datainconsistency.DataInconsistencyError` is raised when an empty field is encountered in a column with an non-nullable integer datatype. + +The loadfiles module and executable +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +For making files available to the LinkAhead server as File entities +(see also the server's `file server +<https://docs.indiscale.com/caosdb-server/specification/Fileserver.html>`_ +documentation), the LinkAhead Advanced User tools provide the +:py:mod:`~caosadvancedtools.loadFiles` module and a +`linkahead-loadfiles` executable. Both operate on a path as seen by +the LinkAhead server (i.e., a path within the Docker container in the +typical LinkAhead Control setup) and can be further specified to +exclude or exclude specific files. + +Execute + +.. code-block:: sh + + linkahead-loadfiles --help + +for more information and examples. -- GitLab From 4f793ddaa068eaa3de1c8968754e7286e7126d32 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Wed, 7 Aug 2024 10:07:15 +0200 Subject: [PATCH 005/106] DOC: Add example to loadfiles section --- src/doc/utilities.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/doc/utilities.rst b/src/doc/utilities.rst index 45874352..36ed6a04 100644 --- a/src/doc/utilities.rst +++ b/src/doc/utilities.rst @@ -47,9 +47,15 @@ documentation), the LinkAhead Advanced User tools provide the `linkahead-loadfiles` executable. Both operate on a path as seen by the LinkAhead server (i.e., a path within the Docker container in the typical LinkAhead Control setup) and can be further specified to -exclude or exclude specific files. +exclude or exclude specific files. In the typical setup, where a +directory is mounted as an extroot into the Docker container by +LinkAhead control, running -Execute +.. code-block:: sh + + linkahead-loadfiles /opt/caosdb/mnt/extroot + +makes all files available. Execute .. code-block:: sh -- GitLab From 0a90222806e48e450f7e413b73c7cb3026f3969e Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Wed, 7 Aug 2024 10:10:17 +0200 Subject: [PATCH 006/106] DOC: Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 831ea7fd..787b9df8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Documentation ### +* Added documentation of `caosadvancedtools.loadFiles` module. + ## [0.12.0] - 2024-07-31 ## ### Added ### -- GitLab From df895484153d110db0157629947c713028663185 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Wed, 7 Aug 2024 11:12:47 +0200 Subject: [PATCH 007/106] MAINT, DOC: More documentation, type hints and linting. --- src/caosadvancedtools/loadFiles.py | 50 +++++++++++++++++------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index 1c7d7bf9..eb40f5c6 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -23,6 +23,16 @@ # ** end header # +"""Utilities to make the LinkAhead server aware of files. + +Installation of `caosadvancedtools` also creates an executable script ``linkahead-loadfiles`` which +calls the `loadpath` function. Get the full help with ``linkahead-loadfiles --help``. In short, +that script tells the LinkAhead server to create `FILE` entities for existing files in one branch of +the directory tree. It is necessary that this directory is already visible for the server (for +example because it is defined as ``extroot`` in the LinkAhead profile). + +""" + import argparse import logging import os @@ -31,30 +41,30 @@ import sys import re from argparse import ArgumentParser from tempfile import NamedTemporaryFile +from typing import Union -import shutil import caosdb as db logger = logging.getLogger(__name__) timeout_fallback = 20 -def convert_size(size): - """Convert `size` from B to a human-readable file size in KB, +def convert_size(size: int): + """Convert `size` from bytes to a human-readable file size in KB, MB, ... """ if (size == 0): return '0B' size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") - i = int(math.floor(math.log(size, 1000))) - p = math.pow(1000, i) + index = int(math.floor(math.log(size, 1000))) + p = math.pow(1000, index) s = round(size / p, 2) - return '%s %s' % (s, size_name[i]) + return f"{s} {size_name[index]}" -def combine_ignore_files(caosdbignore, localignore, dirname=None): +def combine_ignore_files(caosdbignore: str, localignore: str, dirname=None) -> str: """Append the contents of localignore to caosdbignore, save the result, and return the name. @@ -86,7 +96,7 @@ def combine_ignore_files(caosdbignore, localignore, dirname=None): return tmp.name -def compile_file_list(caosdbignore, localpath): +def compile_file_list(caosdbignore: str, localpath: str) -> list[str]: """Create a list of files that contain all files under localpath except those excluded by caosdbignore. @@ -109,11 +119,11 @@ def compile_file_list(caosdbignore, localpath): matches = parse_gitignore(caosdbignore) current_ignore = caosdbignore non_ignored_files = [] - ignore_files = [] + ignore_files: list[tuple[str, str]] = [] for root, dirs, files in os.walk(localpath): # remove local ignore files that do no longer apply to the current subtree (branch switch) while len(ignore_files) > 0 and not root.startswith(ignore_files[-1][0]): - shutil.os.remove(ignore_files[-1][1]) + os.remove(ignore_files[-1][1]) ignore_files.pop() # use the global one if there are no more local ones @@ -143,10 +153,10 @@ def compile_file_list(caosdbignore, localpath): return non_ignored_files -def create_re_for_file_list(files, localroot, remoteroot): +def create_re_for_file_list(files: list[str], localroot: str, remoteroot: str) -> str: """Create a regular expression that matches file paths contained - in the files argument and all parent directories. The prefix - localroot is replaced by the prefix remoteroot. + in the `files` argument and all parent directories. The prefix + `localroot is replaced by the prefix `remoteroot`. Parameters ---------- @@ -179,10 +189,10 @@ def create_re_for_file_list(files, localroot, remoteroot): return "^("+regexp[1:]+")$" -def loadpath(path, include, exclude, prefix, dryrun, forceAllowSymlinks, caosdbignore=None, - localpath=None): - """Make all files in `path` available to the LinkAhead server as - FILE entities. +def loadpath(path: str, include: Union[str, None], exclude: Union[str, None], prefix: str, + dryrun: bool, forceAllowSymlinks: bool, caosdbignore: Union[str, None] = None, + localpath: Union[str, None] = None): + """Make all files in `path` available to the LinkAhead server as FILE entities. Notes ----- @@ -216,10 +226,8 @@ def loadpath(path, include, exclude, prefix, dryrun, forceAllowSymlinks, caosdbi since the check is done locally. If this is given, any `include` is ignored. localpath : str, optional - Path of `path` on the local machine. Only needed in the - combination with a `caosdbignore` file since it is processed - locally. - + Path of `path` on the local machine. Only needed in combination with a + ``caosdbignore`` file since that is processed locally. """ if caosdbignore: -- GitLab From 985570895040d6638b5d540a105fa2aa51cb7b7f Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Wed, 7 Aug 2024 11:13:19 +0200 Subject: [PATCH 008/106] DOC: Fixed unrelated documentation mistake. --- src/doc/table-json-conversion/specs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/table-json-conversion/specs.rst b/src/doc/table-json-conversion/specs.rst index c98eddc1..62c75a70 100644 --- a/src/doc/table-json-conversion/specs.rst +++ b/src/doc/table-json-conversion/specs.rst @@ -181,7 +181,7 @@ a. Properties with primitive data types "date": "2023-06-15", "url": "www.indiscale.com/next", "duration": 2.5, - "participants": None, + "participants": null, "remote": true } ] -- GitLab From c8e5998a0c6136f6ade08ac9beca60ce7b5c0583 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Wed, 7 Aug 2024 11:15:52 +0200 Subject: [PATCH 009/106] DOC: Minor formatting. --- src/doc/utilities.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/utilities.rst b/src/doc/utilities.rst index 36ed6a04..f80460f3 100644 --- a/src/doc/utilities.rst +++ b/src/doc/utilities.rst @@ -44,11 +44,11 @@ For making files available to the LinkAhead server as File entities <https://docs.indiscale.com/caosdb-server/specification/Fileserver.html>`_ documentation), the LinkAhead Advanced User tools provide the :py:mod:`~caosadvancedtools.loadFiles` module and a -`linkahead-loadfiles` executable. Both operate on a path as seen by +``linkahead-loadfiles`` executable. Both operate on a path as seen by the LinkAhead server (i.e., a path within the Docker container in the typical LinkAhead Control setup) and can be further specified to exclude or exclude specific files. In the typical setup, where a -directory is mounted as an extroot into the Docker container by +directory is mounted as an *extroot* into the Docker container by LinkAhead control, running .. code-block:: sh -- GitLab From 4724682618393afbe682f2c39eeaff0f109872c1 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Wed, 7 Aug 2024 11:18:19 +0200 Subject: [PATCH 010/106] MAINT: from __future__ import annotations --- src/caosadvancedtools/loadFiles.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index eb40f5c6..cedef367 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -33,6 +33,8 @@ example because it is defined as ``extroot`` in the LinkAhead profile). """ +from __future__ import annotations + import argparse import logging import os -- GitLab From 63bdb534a7e4aebc3ef8e044d168a23ebe8e8667 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 13 Aug 2024 14:37:23 +0200 Subject: [PATCH 011/106] MAINT: Removed Bloxberg code snippets. The relevant code is in git@gitlab.indiscale.com:caosdb/src/archived/bloxberg.git --- CHANGELOG.md | 2 + src/caosadvancedtools/bloxberg/__init__.py | 4 - src/caosadvancedtools/bloxberg/bloxberg.py | 197 ------ .../bloxberg/swagger_client/__init__.py | 35 - .../bloxberg/swagger_client/api/__init__.py | 7 - .../swagger_client/api/certificate_api.py | 132 ---- .../bloxberg/swagger_client/api/pdf_api.py | 132 ---- .../bloxberg/swagger_client/api_client.py | 628 ------------------ .../bloxberg/swagger_client/configuration.py | 244 ------- .../swagger_client/models/__init__.py | 21 - .../bloxberg/swagger_client/models/batch.py | 228 ------- ...ert_tools_generate_pdf_json_certificate.py | 380 ----------- ...e_unsigned_certificate_json_certificate.py | 380 ----------- .../models/http_validation_error.py | 111 ---- .../swagger_client/models/validation_error.py | 166 ----- .../bloxberg/swagger_client/rest.py | 322 --------- src/doc/conf.py | 1 - 17 files changed, 2 insertions(+), 2988 deletions(-) delete mode 100644 src/caosadvancedtools/bloxberg/__init__.py delete mode 100644 src/caosadvancedtools/bloxberg/bloxberg.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/__init__.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/api/__init__.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/api/certificate_api.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/api/pdf_api.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/api_client.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/configuration.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/models/__init__.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/models/batch.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_pdf_json_certificate.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_unsigned_certificate_json_certificate.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/models/http_validation_error.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/models/validation_error.py delete mode 100644 src/caosadvancedtools/bloxberg/swagger_client/rest.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 787b9df8..62794e6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed ### +- Bloxberg code snippets. These were just a proof of concept, untested and never used in production. + ### Fixed ### ### Security ### diff --git a/src/caosadvancedtools/bloxberg/__init__.py b/src/caosadvancedtools/bloxberg/__init__.py deleted file mode 100644 index 5ca50276..00000000 --- a/src/caosadvancedtools/bloxberg/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""Integration with the Bloxberg proof-of-existence blockchain. -""" - -print("Warning: The Bloxberg module is still experimental and under active development.") diff --git a/src/caosadvancedtools/bloxberg/bloxberg.py b/src/caosadvancedtools/bloxberg/bloxberg.py deleted file mode 100644 index 6aa2eaab..00000000 --- a/src/caosadvancedtools/bloxberg/bloxberg.py +++ /dev/null @@ -1,197 +0,0 @@ -# This file is a part of the CaosDB Project. -# -# Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> -# Copyright (C) 2021 Daniel Hornung <d.hornung@indiscale.com> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. -"""Interaction with the Bloxberg blockchain. -""" - - -import hashlib -import json -import secrets - -import caosdb as db - -from ..models.parser import parse_model_from_string -from . import swagger_client - - -__model_yaml = """ -BloxbergCertificate: - obligatory_properties: - pepper: - datatype: TEXT - hash: - datatype: TEXT - proofValue: - datatype: TEXT - certificateJSON: - datatype: TEXT - recommended_properties: - certified: - datatype: REFERENCE -""" -__model = parse_model_from_string(__model_yaml) - - -class Bloxberg: - """A Bloxberg instance can be used to obtain or verify certificates.""" - - def __init__(self, connection=None): - """A Bloxberg instance can be used to obtain or verify certificates. - -Parameters ----------- -connection : dict -A dict with the following keys: - - url : The bloxberg URL. Default is "https://qa.certify.bloxberg.org" - """ - self._create_conf(connection) - self._api_client = swagger_client.ApiClient(configuration=self._conf) - self._api = swagger_client.CertificateApi(self._api_client) - - def _create_conf(self, connection=None): - """Generate a Swagger configuration object.""" - self._conf = swagger_client.Configuration() - if connection: - if "URL" in connection: - self._conf.host = connection["URL"] - - def certify(self, entity): - """Attempt to certify the given `entity` and return a certificate Record. - -Parameters ----------- -entity : caosdb.Entity -The entity to be certified - -Returns -------- -out : caosdb.Record -A BloxbergCertificate Record with all the necessary Properties. -""" - # Calculate hash - pepper = str(secrets.randbits(1024)) - entity.retrieve() - hasher = hashlib.sha256() - hasher.update(pepper.encode(encoding="utf8")) - hasher.update(str(entity).encode(encoding="utf8")) - entity_hash = "0x" + hasher.hexdigest() - print(entity_hash) - pubkey = "0x9858eC18a269EE69ebfD7C38eb297996827DDa98" # TODO The key of the API server? - # Create body - body = swagger_client.Batch(public_key=pubkey, crid=[entity_hash], crid_type="sha2-256", - enable_ipfs=False) - # Submit hash & obtain response - result = self._api.create_bloxberg_certificate_create_bloxberg_certificate_post(body=body) - attribute_map = result[0].attribute_map - cert = result[0].to_dict() - for old, new in attribute_map.items(): - if old == new: - continue - cert[new] = cert.pop(old) - json_s = json.dumps(cert) - # Generate result Record - cert_rec = db.Record().add_parent("BloxbergCertificate") - # Extract information and put into result - cert_rec.add_property(property="certified", value=entity) - cert_rec.add_property(property="pepper", value=pepper) - cert_rec.add_property(property="hash", value=entity_hash) - cert_rec.add_property(property="proofvalue", value=cert["proof"]["proofValue"]) - cert_rec.add_property(property="certificateJSON", value=json_s) - # Return result - return cert_rec - - def verify(self, certificate): - """Attempt to verify the certificate. - -A certificate passes verification if the Bloxberg instance says it is good. Typical use cases may -also include the `validate` step to make sure that the certificate's original data exists and -contains what it claimed to contain when the certificate was created. - -This method does nothing if the verification passes, else it raises an exception. - -Parameters ----------- -certificate : caosdb.Record -The BloxbergCertificate Record which shall be verified. - - """ - raise NotImplementedError("Bloxberg first needs to implement a verification API method.") - - @staticmethod - def json_from_certificate(certificate, filename=None): - """Generate a qa.certify.bloxberg.org JSON string, optionally writing it to a file. - -Parameters ----------- -certificate : caosdb.Record -The BloxbergCertificate Record for which the JSON is generated. - -filename : str -Write the JSON to this file. -""" - content = {} - print(certificate, filename) - - return content - - -def ensure_data_model(force=False): - """Make sure that the data model fits our needs. - - Most importantly, this means that a suitable RecordType "BoxbergCertificate" must exist. - """ - __model.sync_data_model(noquestion=force) - - -def certify_entity(entity, json_filename=None): - """Certify the given entity and store the result in the CaosDB. - -Parameters ----------- -entity : caosdb.Entity - The Entity to be certified. - -json_filename : str - If given, store the JSON here. -""" - if isinstance(entity, int): - entity = db.Entity(id=entity) - - blx = Bloxberg() - print("Obtaining certificate...") - certificate = blx.certify(entity) - print("Certificate was successfully obtained.") - certificate.insert() - print("Certificate was stored in CaosDB.") - - if json_filename: - with open(json_filename, "w") as json_file: - json_file.write(certificate.get_property("certificateJSON").value) - - -def demo_run(): - """Run the core functions for demonstration purposes.""" - print("Making sure that the remote data model is up to date.") - ensure_data_model() - print("Data model is up to date.") - CertRT = db.RecordType(name="BloxbergCertificate").retrieve() - print("Certifying the `BloxbergCertificate` RecordType...") - json_filename = "/tmp/cert.json" - certify_entity(CertRT, json_filename=json_filename) - print("Certificate json file can be found here: {}".format(json_filename)) - print("You can verify the certificate here: https://certify.bloxberg.org/verify") diff --git a/src/caosadvancedtools/bloxberg/swagger_client/__init__.py b/src/caosadvancedtools/bloxberg/swagger_client/__init__.py deleted file mode 100644 index 255d6d31..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# coding: utf-8 - -# flake8: noqa - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -from __future__ import absolute_import -from swagger_client.models.validation_error import ValidationError -from swagger_client.models.http_validation_error import HTTPValidationError -from swagger_client.models.controller_cert_tools_generate_unsigned_certificate_json_certificate import ControllerCertToolsGenerateUnsignedCertificateJsonCertificate -from swagger_client.models.controller_cert_tools_generate_pdf_json_certificate import ControllerCertToolsGeneratePdfJsonCertificate -from swagger_client.models.batch import Batch -from swagger_client.configuration import Configuration -from swagger_client.api_client import ApiClient -from swagger_client.api.pdf_api import PdfApi -from swagger_client.api.certificate_api import CertificateApi - -# Fake the installation -import sys -import pathlib -__this_dir = str(pathlib.Path(__file__).parent.parent) -if __this_dir not in sys.path: - sys.path.append(__this_dir) - -# import apis into sdk package -# import ApiClient -# import models into sdk package diff --git a/src/caosadvancedtools/bloxberg/swagger_client/api/__init__.py b/src/caosadvancedtools/bloxberg/swagger_client/api/__init__.py deleted file mode 100644 index d33c26ea..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/api/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import absolute_import - -# flake8: noqa - -# import apis into api package -from swagger_client.api.certificate_api import CertificateApi -from swagger_client.api.pdf_api import PdfApi diff --git a/src/caosadvancedtools/bloxberg/swagger_client/api/certificate_api.py b/src/caosadvancedtools/bloxberg/swagger_client/api/certificate_api.py deleted file mode 100644 index 0f0f1c6a..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/api/certificate_api.py +++ /dev/null @@ -1,132 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -from __future__ import absolute_import - -import re # noqa: F401 - -# python 2 and python 3 compatibility library -import six - -from swagger_client.api_client import ApiClient - - -class CertificateApi(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - Ref: https://github.com/swagger-api/swagger-codegen - """ - - def __init__(self, api_client=None): - if api_client is None: - api_client = ApiClient() - self.api_client = api_client - - def create_bloxberg_certificate_create_bloxberg_certificate_post(self, body, **kwargs): # noqa: E501 - """Createbloxbergcertificate # noqa: E501 - - Creates, transacts, and signs a research object certificate on the bloxberg blockchain. Hashes must be generated client side for each desired file and provided in an array. Each hash corresponds to one research object certificate returned in a JSON object array. # noqa: E501 - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - >>> thread = api.create_bloxberg_certificate_create_bloxberg_certificate_post(body, async_req=True) - >>> result = thread.get() - - :param async_req bool - :param Batch body: (required) - :return: list[ControllerCertToolsGenerateUnsignedCertificateJsonCertificate] - If the method is called asynchronously, - returns the request thread. - """ - kwargs['_return_http_data_only'] = True - if kwargs.get('async_req'): - return self.create_bloxberg_certificate_create_bloxberg_certificate_post_with_http_info(body, **kwargs) # noqa: E501 - else: - (data) = self.create_bloxberg_certificate_create_bloxberg_certificate_post_with_http_info(body, **kwargs) # noqa: E501 - return data - - def create_bloxberg_certificate_create_bloxberg_certificate_post_with_http_info(self, body, **kwargs): # noqa: E501 - """Createbloxbergcertificate # noqa: E501 - - Creates, transacts, and signs a research object certificate on the bloxberg blockchain. Hashes must be generated client side for each desired file and provided in an array. Each hash corresponds to one research object certificate returned in a JSON object array. # noqa: E501 - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - >>> thread = api.create_bloxberg_certificate_create_bloxberg_certificate_post_with_http_info(body, async_req=True) - >>> result = thread.get() - - :param async_req bool - :param Batch body: (required) - :return: list[ControllerCertToolsGenerateUnsignedCertificateJsonCertificate] - If the method is called asynchronously, - returns the request thread. - """ - - all_params = ['body'] # noqa: E501 - all_params.append('async_req') - all_params.append('_return_http_data_only') - all_params.append('_preload_content') - all_params.append('_request_timeout') - - params = locals() - for key, val in six.iteritems(params['kwargs']): - if key not in all_params: - raise TypeError( - "Got an unexpected keyword argument '%s'" - " to method create_bloxberg_certificate_create_bloxberg_certificate_post" % key - ) - params[key] = val - del params['kwargs'] - # verify the required parameter 'body' is set - if ('body' not in params or - params['body'] is None): - raise ValueError("Missing the required parameter `body` when calling `create_bloxberg_certificate_create_bloxberg_certificate_post`") # noqa: E501 - - collection_formats = {} - - path_params = {} - - query_params = [] - - header_params = {} - - form_params = [] - local_var_files = {} - - body_params = None - if 'body' in params: - body_params = params['body'] - # HTTP header `Accept` - header_params['Accept'] = self.api_client.select_header_accept( - ['application/json']) # noqa: E501 - - # HTTP header `Content-Type` - header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 - ['application/json']) # noqa: E501 - - # Authentication setting - auth_settings = [] # noqa: E501 - - return self.api_client.call_api( - '/createBloxbergCertificate', 'POST', - path_params, - query_params, - header_params, - body=body_params, - post_params=form_params, - files=local_var_files, - response_type='list[ControllerCertToolsGenerateUnsignedCertificateJsonCertificate]', # noqa: E501 - auth_settings=auth_settings, - async_req=params.get('async_req'), - _return_http_data_only=params.get('_return_http_data_only'), - _preload_content=params.get('_preload_content', True), - _request_timeout=params.get('_request_timeout'), - collection_formats=collection_formats) diff --git a/src/caosadvancedtools/bloxberg/swagger_client/api/pdf_api.py b/src/caosadvancedtools/bloxberg/swagger_client/api/pdf_api.py deleted file mode 100644 index a5a279de..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/api/pdf_api.py +++ /dev/null @@ -1,132 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -from __future__ import absolute_import - -import re # noqa: F401 - -# python 2 and python 3 compatibility library -import six - -from swagger_client.api_client import ApiClient - - -class PdfApi(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - Ref: https://github.com/swagger-api/swagger-codegen - """ - - def __init__(self, api_client=None): - if api_client is None: - api_client = ApiClient() - self.api_client = api_client - - def generate_pdf_generate_pdf_post(self, body, **kwargs): # noqa: E501 - """Generatepdf # noqa: E501 - - Accepts as input the response from the createBloxbergCertificate endpoint, for example a research object JSON array. Returns as response a zip archive with PDF files that correspond to the number of cryptographic identifiers provided. PDF files are embedded with the Research Object Certification which is used for verification. # noqa: E501 - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - >>> thread = api.generate_pdf_generate_pdf_post(body, async_req=True) - >>> result = thread.get() - - :param async_req bool - :param list[ControllerCertToolsGeneratePdfJsonCertificate] body: (required) - :return: Object - If the method is called asynchronously, - returns the request thread. - """ - kwargs['_return_http_data_only'] = True - if kwargs.get('async_req'): - return self.generate_pdf_generate_pdf_post_with_http_info(body, **kwargs) # noqa: E501 - else: - (data) = self.generate_pdf_generate_pdf_post_with_http_info(body, **kwargs) # noqa: E501 - return data - - def generate_pdf_generate_pdf_post_with_http_info(self, body, **kwargs): # noqa: E501 - """Generatepdf # noqa: E501 - - Accepts as input the response from the createBloxbergCertificate endpoint, for example a research object JSON array. Returns as response a zip archive with PDF files that correspond to the number of cryptographic identifiers provided. PDF files are embedded with the Research Object Certification which is used for verification. # noqa: E501 - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - >>> thread = api.generate_pdf_generate_pdf_post_with_http_info(body, async_req=True) - >>> result = thread.get() - - :param async_req bool - :param list[ControllerCertToolsGeneratePdfJsonCertificate] body: (required) - :return: Object - If the method is called asynchronously, - returns the request thread. - """ - - all_params = ['body'] # noqa: E501 - all_params.append('async_req') - all_params.append('_return_http_data_only') - all_params.append('_preload_content') - all_params.append('_request_timeout') - - params = locals() - for key, val in six.iteritems(params['kwargs']): - if key not in all_params: - raise TypeError( - "Got an unexpected keyword argument '%s'" - " to method generate_pdf_generate_pdf_post" % key - ) - params[key] = val - del params['kwargs'] - # verify the required parameter 'body' is set - if ('body' not in params or - params['body'] is None): - raise ValueError("Missing the required parameter `body` when calling `generate_pdf_generate_pdf_post`") # noqa: E501 - - collection_formats = {} - - path_params = {} - - query_params = [] - - header_params = {} - - form_params = [] - local_var_files = {} - - body_params = None - if 'body' in params: - body_params = params['body'] - # HTTP header `Accept` - header_params['Accept'] = self.api_client.select_header_accept( - ['application/json']) # noqa: E501 - - # HTTP header `Content-Type` - header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 - ['application/json']) # noqa: E501 - - # Authentication setting - auth_settings = [] # noqa: E501 - - return self.api_client.call_api( - '/generatePDF', 'POST', - path_params, - query_params, - header_params, - body=body_params, - post_params=form_params, - files=local_var_files, - response_type='Object', # noqa: E501 - auth_settings=auth_settings, - async_req=params.get('async_req'), - _return_http_data_only=params.get('_return_http_data_only'), - _preload_content=params.get('_preload_content', True), - _request_timeout=params.get('_request_timeout'), - collection_formats=collection_formats) diff --git a/src/caosadvancedtools/bloxberg/swagger_client/api_client.py b/src/caosadvancedtools/bloxberg/swagger_client/api_client.py deleted file mode 100644 index 7337ca33..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/api_client.py +++ /dev/null @@ -1,628 +0,0 @@ -# coding: utf-8 -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" -from __future__ import absolute_import - -import datetime -import json -import mimetypes -from multiprocessing.pool import ThreadPool -import os -import re -import tempfile - -# python 2 and python 3 compatibility library -import six -from six.moves.urllib.parse import quote - -from swagger_client.configuration import Configuration -import swagger_client.models -from swagger_client import rest - - -class ApiClient(object): - """Generic API client for Swagger client library builds. - - Swagger generic API client. This client handles the client- - server communication, and is invariant across implementations. Specifics of - the methods and models for each application are generated from the Swagger - templates. - - NOTE: This class is auto generated by the swagger code generator program. - Ref: https://github.com/swagger-api/swagger-codegen - Do not edit the class manually. - - :param configuration: .Configuration object for this client - :param header_name: a header to pass when making calls to the API. - :param header_value: a header value to pass when making calls to - the API. - :param cookie: a cookie to include in the header when making calls - to the API - """ - - PRIMITIVE_TYPES = (float, bool, bytes, six.text_type) + six.integer_types - NATIVE_TYPES_MAPPING = { - 'int': int, - 'long': int if six.PY3 else long, # noqa: F821 - 'float': float, - 'str': str, - 'bool': bool, - 'date': datetime.date, - 'datetime': datetime.datetime, - 'object': object, - } - - def __init__(self, configuration=None, header_name=None, header_value=None, - cookie=None): - if configuration is None: - configuration = Configuration() - self.configuration = configuration - - self.pool = ThreadPool() - self.rest_client = rest.RESTClientObject(configuration) - self.default_headers = {} - if header_name is not None: - self.default_headers[header_name] = header_value - self.cookie = cookie - # Set default User-Agent. - self.user_agent = 'Swagger-Codegen/1.0.0/python' - - def __del__(self): - self.pool.close() - self.pool.join() - - @property - def user_agent(self): - """User agent for this API client""" - return self.default_headers['User-Agent'] - - @user_agent.setter - def user_agent(self, value): - self.default_headers['User-Agent'] = value - - def set_default_header(self, header_name, header_value): - self.default_headers[header_name] = header_value - - def __call_api( - self, resource_path, method, path_params=None, - query_params=None, header_params=None, body=None, post_params=None, - files=None, response_type=None, auth_settings=None, - _return_http_data_only=None, collection_formats=None, - _preload_content=True, _request_timeout=None): - - config = self.configuration - - # header parameters - header_params = header_params or {} - header_params.update(self.default_headers) - if self.cookie: - header_params['Cookie'] = self.cookie - if header_params: - header_params = self.sanitize_for_serialization(header_params) - header_params = dict(self.parameters_to_tuples(header_params, - collection_formats)) - - # path parameters - if path_params: - path_params = self.sanitize_for_serialization(path_params) - path_params = self.parameters_to_tuples(path_params, - collection_formats) - for k, v in path_params: - # specified safe chars, encode everything - resource_path = resource_path.replace( - '{%s}' % k, - quote(str(v), safe=config.safe_chars_for_path_param) - ) - - # query parameters - if query_params: - query_params = self.sanitize_for_serialization(query_params) - query_params = self.parameters_to_tuples(query_params, - collection_formats) - - # post parameters - if post_params or files: - post_params = self.prepare_post_parameters(post_params, files) - post_params = self.sanitize_for_serialization(post_params) - post_params = self.parameters_to_tuples(post_params, - collection_formats) - - # auth setting - self.update_params_for_auth(header_params, query_params, auth_settings) - - # body - if body: - body = self.sanitize_for_serialization(body) - - # request url - url = self.configuration.host + resource_path - - # perform request and return response - response_data = self.request( - method, url, query_params=query_params, headers=header_params, - post_params=post_params, body=body, - _preload_content=_preload_content, - _request_timeout=_request_timeout) - - self.last_response = response_data - - return_data = response_data - if _preload_content: - # deserialize response data - if response_type: - return_data = self.deserialize(response_data, response_type) - else: - return_data = None - - if _return_http_data_only: - return (return_data) - else: - return (return_data, response_data.status, - response_data.getheaders()) - - def sanitize_for_serialization(self, obj): - """Builds a JSON POST object. - - If obj is None, return None. - If obj is str, int, long, float, bool, return directly. - If obj is datetime.datetime, datetime.date - convert to string in iso8601 format. - If obj is list, sanitize each element in the list. - If obj is dict, return the dict. - If obj is swagger model, return the properties dict. - - :param obj: The data to serialize. - :return: The serialized form of data. - """ - if obj is None: - return None - elif isinstance(obj, self.PRIMITIVE_TYPES): - return obj - elif isinstance(obj, list): - return [self.sanitize_for_serialization(sub_obj) - for sub_obj in obj] - elif isinstance(obj, tuple): - return tuple(self.sanitize_for_serialization(sub_obj) - for sub_obj in obj) - elif isinstance(obj, (datetime.datetime, datetime.date)): - return obj.isoformat() - - if isinstance(obj, dict): - obj_dict = obj - else: - # Convert model obj to dict except - # attributes `swagger_types`, `attribute_map` - # and attributes which value is not None. - # Convert attribute name to json key in - # model definition for request. - obj_dict = {obj.attribute_map[attr]: getattr(obj, attr) - for attr, _ in six.iteritems(obj.swagger_types) - if getattr(obj, attr) is not None} - - return {key: self.sanitize_for_serialization(val) - for key, val in six.iteritems(obj_dict)} - - def deserialize(self, response, response_type): - """Deserializes response into an object. - - :param response: RESTResponse object to be deserialized. - :param response_type: class literal for - deserialized object, or string of class name. - - :return: deserialized object. - """ - # handle file downloading - # save response body into a tmp file and return the instance - if response_type == "file": - return self.__deserialize_file(response) - - # fetch data from response object - try: - data = json.loads(response.data) - except ValueError: - data = response.data - - return self.__deserialize(data, response_type) - - def __deserialize(self, data, klass): - """Deserializes dict, list, str into an object. - - :param data: dict, list or str. - :param klass: class literal, or string of class name. - - :return: object. - """ - if data is None: - return None - - if type(klass) == str: - if klass.startswith('list['): - sub_kls = re.match(r'list\[(.*)\]', klass).group(1) - return [self.__deserialize(sub_data, sub_kls) - for sub_data in data] - - if klass.startswith('dict('): - sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2) - return {k: self.__deserialize(v, sub_kls) - for k, v in six.iteritems(data)} - - # convert str to class - if klass in self.NATIVE_TYPES_MAPPING: - klass = self.NATIVE_TYPES_MAPPING[klass] - else: - klass = getattr(swagger_client.models, klass) - - if klass in self.PRIMITIVE_TYPES: - return self.__deserialize_primitive(data, klass) - elif klass == object: - return self.__deserialize_object(data) - elif klass == datetime.date: - return self.__deserialize_date(data) - elif klass == datetime.datetime: - return self.__deserialize_datatime(data) - else: - return self.__deserialize_model(data, klass) - - def call_api(self, resource_path, method, - path_params=None, query_params=None, header_params=None, - body=None, post_params=None, files=None, - response_type=None, auth_settings=None, async_req=None, - _return_http_data_only=None, collection_formats=None, - _preload_content=True, _request_timeout=None): - """Makes the HTTP request (synchronous) and returns deserialized data. - - To make an async request, set the async_req parameter. - - :param resource_path: Path to method endpoint. - :param method: Method to call. - :param path_params: Path parameters in the url. - :param query_params: Query parameters in the url. - :param header_params: Header parameters to be - placed in the request header. - :param body: Request body. - :param post_params dict: Request post form parameters, - for `application/x-www-form-urlencoded`, `multipart/form-data`. - :param auth_settings list: Auth Settings names for the request. - :param response: Response data type. - :param files dict: key -> filename, value -> filepath, - for `multipart/form-data`. - :param async_req bool: execute request asynchronously - :param _return_http_data_only: response data without head status code - and headers - :param collection_formats: dict of collection formats for path, query, - header, and post parameters. - :param _preload_content: if False, the urllib3.HTTPResponse object will - be returned without reading/decoding response - data. Default is True. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: - If async_req parameter is True, - the request will be called asynchronously. - The method will return the request thread. - If parameter async_req is False or missing, - then the method will return the response directly. - """ - if not async_req: - return self.__call_api(resource_path, method, - path_params, query_params, header_params, - body, post_params, files, - response_type, auth_settings, - _return_http_data_only, collection_formats, - _preload_content, _request_timeout) - else: - thread = self.pool.apply_async(self.__call_api, (resource_path, - method, path_params, query_params, - header_params, body, - post_params, files, - response_type, auth_settings, - _return_http_data_only, - collection_formats, - _preload_content, _request_timeout)) - return thread - - def request(self, method, url, query_params=None, headers=None, - post_params=None, body=None, _preload_content=True, - _request_timeout=None): - """Makes the HTTP request using RESTClient.""" - if method == "GET": - return self.rest_client.GET(url, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - headers=headers) - elif method == "HEAD": - return self.rest_client.HEAD(url, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - headers=headers) - elif method == "OPTIONS": - return self.rest_client.OPTIONS(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "POST": - return self.rest_client.POST(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "PUT": - return self.rest_client.PUT(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "PATCH": - return self.rest_client.PATCH(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "DELETE": - return self.rest_client.DELETE(url, - query_params=query_params, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - else: - raise ValueError( - "http method must be `GET`, `HEAD`, `OPTIONS`," - " `POST`, `PATCH`, `PUT` or `DELETE`." - ) - - def parameters_to_tuples(self, params, collection_formats): - """Get parameters as list of tuples, formatting collections. - - :param params: Parameters as dict or list of two-tuples - :param dict collection_formats: Parameter collection formats - :return: Parameters as list of tuples, collections formatted - """ - new_params = [] - if collection_formats is None: - collection_formats = {} - for k, v in six.iteritems(params) if isinstance(params, dict) else params: # noqa: E501 - if k in collection_formats: - collection_format = collection_formats[k] - if collection_format == 'multi': - new_params.extend((k, value) for value in v) - else: - if collection_format == 'ssv': - delimiter = ' ' - elif collection_format == 'tsv': - delimiter = '\t' - elif collection_format == 'pipes': - delimiter = '|' - else: # csv is the default - delimiter = ',' - new_params.append( - (k, delimiter.join(str(value) for value in v))) - else: - new_params.append((k, v)) - return new_params - - def prepare_post_parameters(self, post_params=None, files=None): - """Builds form parameters. - - :param post_params: Normal form parameters. - :param files: File parameters. - :return: Form parameters with files. - """ - params = [] - - if post_params: - params = post_params - - if files: - for k, v in six.iteritems(files): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = (mimetypes.guess_type(filename)[0] or - 'application/octet-stream') - params.append( - tuple([k, tuple([filename, filedata, mimetype])])) - - return params - - def select_header_accept(self, accepts): - """Returns `Accept` based on an array of accepts provided. - - :param accepts: List of headers. - :return: Accept (e.g. application/json). - """ - if not accepts: - return - - accepts = [x.lower() for x in accepts] - - if 'application/json' in accepts: - return 'application/json' - else: - return ', '.join(accepts) - - def select_header_content_type(self, content_types): - """Returns `Content-Type` based on an array of content_types provided. - - :param content_types: List of content-types. - :return: Content-Type (e.g. application/json). - """ - if not content_types: - return 'application/json' - - content_types = [x.lower() for x in content_types] - - if 'application/json' in content_types or '*/*' in content_types: - return 'application/json' - else: - return content_types[0] - - def update_params_for_auth(self, headers, querys, auth_settings): - """Updates header and query params based on authentication setting. - - :param headers: Header parameters dict to be updated. - :param querys: Query parameters tuple list to be updated. - :param auth_settings: Authentication setting identifiers list. - """ - if not auth_settings: - return - - for auth in auth_settings: - auth_setting = self.configuration.auth_settings().get(auth) - if auth_setting: - if not auth_setting['value']: - continue - elif auth_setting['in'] == 'header': - headers[auth_setting['key']] = auth_setting['value'] - elif auth_setting['in'] == 'query': - querys.append((auth_setting['key'], auth_setting['value'])) - else: - raise ValueError( - 'Authentication token must be in `query` or `header`' - ) - - def __deserialize_file(self, response): - """Deserializes body to file - - Saves response body into a file in a temporary folder, - using the filename from the `Content-Disposition` header if provided. - - :param response: RESTResponse. - :return: file path. - """ - fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path) - os.close(fd) - os.remove(path) - - content_disposition = response.getheader("Content-Disposition") - if content_disposition: - filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', - content_disposition).group(1) - path = os.path.join(os.path.dirname(path), filename) - - with open(path, "wb") as f: - f.write(response.data) - - return path - - def __deserialize_primitive(self, data, klass): - """Deserializes string to primitive type. - - :param data: str. - :param klass: class literal. - - :return: int, long, float, str, bool. - """ - try: - return klass(data) - except UnicodeEncodeError: - return six.text_type(data) - except TypeError: - return data - - def __deserialize_object(self, value): - """Return a original value. - - :return: object. - """ - return value - - def __deserialize_date(self, string): - """Deserializes string to date. - - :param string: str. - :return: date. - """ - try: - from dateutil.parser import parse - return parse(string).date() - except ImportError: - return string - except ValueError: - raise rest.ApiException( - status=0, - reason="Failed to parse `{0}` as date object".format(string) - ) - - def __deserialize_datatime(self, string): - """Deserializes string to datetime. - - The string should be in iso8601 datetime format. - - :param string: str. - :return: datetime. - """ - try: - from dateutil.parser import parse - return parse(string) - except ImportError: - return string - except ValueError: - raise rest.ApiException( - status=0, - reason=( - "Failed to parse `{0}` as datetime object" - .format(string) - ) - ) - - def __hasattr(self, object, name): - return name in object.__class__.__dict__ - - def __deserialize_model(self, data, klass): - """Deserializes list or dict to model. - - :param data: dict, list. - :param klass: class literal. - :return: model object. - """ - - if not klass.swagger_types and not self.__hasattr(klass, 'get_real_child_model'): - return data - - kwargs = {} - if klass.swagger_types is not None: - for attr, attr_type in six.iteritems(klass.swagger_types): - if (data is not None and - klass.attribute_map[attr] in data and - isinstance(data, (list, dict))): - value = data[klass.attribute_map[attr]] - kwargs[attr] = self.__deserialize(value, attr_type) - - instance = klass(**kwargs) - - if (isinstance(instance, dict) and - klass.swagger_types is not None and - isinstance(data, dict)): - for key, value in data.items(): - if key not in klass.swagger_types: - instance[key] = value - if self.__hasattr(instance, 'get_real_child_model'): - klass_name = instance.get_real_child_model(data) - if klass_name: - instance = self.__deserialize(data, klass_name) - return instance diff --git a/src/caosadvancedtools/bloxberg/swagger_client/configuration.py b/src/caosadvancedtools/bloxberg/swagger_client/configuration.py deleted file mode 100644 index 2be9f6a7..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/configuration.py +++ /dev/null @@ -1,244 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -from __future__ import absolute_import - -import copy -import logging -import multiprocessing -import sys -import urllib3 - -import six -from six.moves import http_client as httplib - - -class TypeWithDefault(type): - def __init__(cls, name, bases, dct): - super(TypeWithDefault, cls).__init__(name, bases, dct) - cls._default = None - - def __call__(cls): - if cls._default is None: - cls._default = type.__call__(cls) - return copy.copy(cls._default) - - def set_default(cls, default): - cls._default = copy.copy(default) - - -class Configuration(six.with_metaclass(TypeWithDefault, object)): - """NOTE: This class is auto generated by the swagger code generator program. - - Ref: https://github.com/swagger-api/swagger-codegen - Do not edit the class manually. - """ - - def __init__(self): - """Constructor""" - # Default Base url - self.host = "https://qa.certify.bloxberg.org" - # Temp file folder for downloading files - self.temp_folder_path = None - - # Authentication Settings - # dict to store API key(s) - self.api_key = {} - # dict to store API prefix (e.g. Bearer) - self.api_key_prefix = {} - # function to refresh API key if expired - self.refresh_api_key_hook = None - # Username for HTTP basic authentication - self.username = "" - # Password for HTTP basic authentication - self.password = "" - # Logging Settings - self.logger = {} - self.logger["package_logger"] = logging.getLogger("swagger_client") - self.logger["urllib3_logger"] = logging.getLogger("urllib3") - # Log format - self.logger_format = '%(asctime)s %(levelname)s %(message)s' - # Log stream handler - self.logger_stream_handler = None - # Log file handler - self.logger_file_handler = None - # Debug file location - self.logger_file = None - # Debug switch - self.debug = False - - # SSL/TLS verification - # Set this to false to skip verifying SSL certificate when calling API - # from https server. - self.verify_ssl = True - # Set this to customize the certificate file to verify the peer. - self.ssl_ca_cert = None - # client certificate file - self.cert_file = None - # client key file - self.key_file = None - # Set this to True/False to enable/disable SSL hostname verification. - self.assert_hostname = None - - # urllib3 connection pool's maximum number of connections saved - # per pool. urllib3 uses 1 connection as default value, but this is - # not the best value when you are making a lot of possibly parallel - # requests to the same host, which is often the case here. - # cpu_count * 5 is used as default value to increase performance. - self.connection_pool_maxsize = multiprocessing.cpu_count() * 5 - - # Proxy URL - self.proxy = None - # Safe chars for path_param - self.safe_chars_for_path_param = '' - - @property - def logger_file(self): - """The logger file. - - If the logger_file is None, then add stream handler and remove file - handler. Otherwise, add file handler and remove stream handler. - - :param value: The logger_file path. - :type: str - """ - return self.__logger_file - - @logger_file.setter - def logger_file(self, value): - """The logger file. - - If the logger_file is None, then add stream handler and remove file - handler. Otherwise, add file handler and remove stream handler. - - :param value: The logger_file path. - :type: str - """ - self.__logger_file = value - if self.__logger_file: - # If set logging file, - # then add file handler and remove stream handler. - self.logger_file_handler = logging.FileHandler(self.__logger_file) - self.logger_file_handler.setFormatter(self.logger_formatter) - for _, logger in six.iteritems(self.logger): - logger.addHandler(self.logger_file_handler) - if self.logger_stream_handler: - logger.removeHandler(self.logger_stream_handler) - else: - # If not set logging file, - # then add stream handler and remove file handler. - self.logger_stream_handler = logging.StreamHandler() - self.logger_stream_handler.setFormatter(self.logger_formatter) - for _, logger in six.iteritems(self.logger): - logger.addHandler(self.logger_stream_handler) - if self.logger_file_handler: - logger.removeHandler(self.logger_file_handler) - - @property - def debug(self): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - return self.__debug - - @debug.setter - def debug(self, value): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - self.__debug = value - if self.__debug: - # if debug status is True, turn on debug logging - for _, logger in six.iteritems(self.logger): - logger.setLevel(logging.DEBUG) - # turn on httplib debug - httplib.HTTPConnection.debuglevel = 1 - else: - # if debug status is False, turn off debug logging, - # setting log level to default `logging.WARNING` - for _, logger in six.iteritems(self.logger): - logger.setLevel(logging.WARNING) - # turn off httplib debug - httplib.HTTPConnection.debuglevel = 0 - - @property - def logger_format(self): - """The logger format. - - The logger_formatter will be updated when sets logger_format. - - :param value: The format string. - :type: str - """ - return self.__logger_format - - @logger_format.setter - def logger_format(self, value): - """The logger format. - - The logger_formatter will be updated when sets logger_format. - - :param value: The format string. - :type: str - """ - self.__logger_format = value - self.logger_formatter = logging.Formatter(self.__logger_format) - - def get_api_key_with_prefix(self, identifier): - """Gets API key (with prefix if set). - - :param identifier: The identifier of apiKey. - :return: The token for api key authentication. - """ - if self.refresh_api_key_hook: - self.refresh_api_key_hook(self) - - key = self.api_key.get(identifier) - if key: - prefix = self.api_key_prefix.get(identifier) - if prefix: - return "%s %s" % (prefix, key) - else: - return key - - def get_basic_auth_token(self): - """Gets HTTP basic authentication header (string). - - :return: The token for basic HTTP authentication. - """ - return urllib3.util.make_headers( - basic_auth=self.username + ':' + self.password - ).get('authorization') - - def auth_settings(self): - """Gets Auth Settings dict for api client. - - :return: The Auth Settings information dict. - """ - return { - } - - def to_debug_report(self): - """Gets the essential information for debugging. - - :return: The report for debugging. - """ - return "Python SDK Debug Report:\n"\ - "OS: {env}\n"\ - "Python Version: {pyversion}\n"\ - "Version of the API: 0.2.0\n"\ - "SDK Package Version: 1.0.0".\ - format(env=sys.platform, pyversion=sys.version) diff --git a/src/caosadvancedtools/bloxberg/swagger_client/models/__init__.py b/src/caosadvancedtools/bloxberg/swagger_client/models/__init__.py deleted file mode 100644 index 55b01c66..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/models/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# coding: utf-8 - -# flake8: noqa -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -from __future__ import absolute_import - -# import models into model package -from swagger_client.models.batch import Batch -from swagger_client.models.controller_cert_tools_generate_pdf_json_certificate import ControllerCertToolsGeneratePdfJsonCertificate -from swagger_client.models.controller_cert_tools_generate_unsigned_certificate_json_certificate import ControllerCertToolsGenerateUnsignedCertificateJsonCertificate -from swagger_client.models.http_validation_error import HTTPValidationError -from swagger_client.models.validation_error import ValidationError diff --git a/src/caosadvancedtools/bloxberg/swagger_client/models/batch.py b/src/caosadvancedtools/bloxberg/swagger_client/models/batch.py deleted file mode 100644 index 474ca01a..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/models/batch.py +++ /dev/null @@ -1,228 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -import pprint -import re # noqa: F401 - -import six - - -class Batch(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - """ - """ - Attributes: - swagger_types (dict): The key is attribute name - and the value is attribute type. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - """ - swagger_types = { - 'public_key': 'str', - 'crid': 'list[str]', - 'crid_type': 'str', - 'enable_ipfs': 'bool', - 'metadata_json': 'str' - } - - attribute_map = { - 'public_key': 'publicKey', - 'crid': 'crid', - 'crid_type': 'cridType', - 'enable_ipfs': 'enableIPFS', - 'metadata_json': 'metadataJson' - } - - def __init__(self, public_key=None, crid=None, crid_type=None, enable_ipfs=None, metadata_json=None): # noqa: E501 - """Batch - a model defined in Swagger""" # noqa: E501 - self._public_key = None - self._crid = None - self._crid_type = None - self._enable_ipfs = None - self._metadata_json = None - self.discriminator = None - self.public_key = public_key - self.crid = crid - if crid_type is not None: - self.crid_type = crid_type - self.enable_ipfs = enable_ipfs - if metadata_json is not None: - self.metadata_json = metadata_json - - @property - def public_key(self): - """Gets the public_key of this Batch. # noqa: E501 - - Public bloxberg address where the Research Object Certificate token will be minted # noqa: E501 - - :return: The public_key of this Batch. # noqa: E501 - :rtype: str - """ - return self._public_key - - @public_key.setter - def public_key(self, public_key): - """Sets the public_key of this Batch. - - Public bloxberg address where the Research Object Certificate token will be minted # noqa: E501 - - :param public_key: The public_key of this Batch. # noqa: E501 - :type: str - """ - if public_key is None: - raise ValueError("Invalid value for `public_key`, must not be `None`") # noqa: E501 - - self._public_key = public_key - - @property - def crid(self): - """Gets the crid of this Batch. # noqa: E501 - - Cryptographic Identifier of each file you wish to certify. One certificate will be generated per hash up to a maximum of 1001 in a single request # noqa: E501 - - :return: The crid of this Batch. # noqa: E501 - :rtype: list[str] - """ - return self._crid - - @crid.setter - def crid(self, crid): - """Sets the crid of this Batch. - - Cryptographic Identifier of each file you wish to certify. One certificate will be generated per hash up to a maximum of 1001 in a single request # noqa: E501 - - :param crid: The crid of this Batch. # noqa: E501 - :type: list[str] - """ - if crid is None: - raise ValueError("Invalid value for `crid`, must not be `None`") # noqa: E501 - - self._crid = crid - - @property - def crid_type(self): - """Gets the crid_type of this Batch. # noqa: E501 - - If crid is not self-describing, provide the type of cryptographic function you used to generate the cryptographic identifier. Please use the name field from the multihash list to ensure compatibility: https://github.com/multiformats/multicodec/blob/master/table.csv # noqa: E501 - - :return: The crid_type of this Batch. # noqa: E501 - :rtype: str - """ - return self._crid_type - - @crid_type.setter - def crid_type(self, crid_type): - """Sets the crid_type of this Batch. - - If crid is not self-describing, provide the type of cryptographic function you used to generate the cryptographic identifier. Please use the name field from the multihash list to ensure compatibility: https://github.com/multiformats/multicodec/blob/master/table.csv # noqa: E501 - - :param crid_type: The crid_type of this Batch. # noqa: E501 - :type: str - """ - - self._crid_type = crid_type - - @property - def enable_ipfs(self): - """Gets the enable_ipfs of this Batch. # noqa: E501 - - EXPERIMENTAL: Set to true to enable posting certificate to IPFS. If set to false, will simply return certificates in the response. By default, this is disabled on the server due to performance and storage problems with IPFS # noqa: E501 - - :return: The enable_ipfs of this Batch. # noqa: E501 - :rtype: bool - """ - return self._enable_ipfs - - @enable_ipfs.setter - def enable_ipfs(self, enable_ipfs): - """Sets the enable_ipfs of this Batch. - - EXPERIMENTAL: Set to true to enable posting certificate to IPFS. If set to false, will simply return certificates in the response. By default, this is disabled on the server due to performance and storage problems with IPFS # noqa: E501 - - :param enable_ipfs: The enable_ipfs of this Batch. # noqa: E501 - :type: bool - """ - if enable_ipfs is None: - raise ValueError("Invalid value for `enable_ipfs`, must not be `None`") # noqa: E501 - - self._enable_ipfs = enable_ipfs - - @property - def metadata_json(self): - """Gets the metadata_json of this Batch. # noqa: E501 - - Provide optional metadata to describe the research object batch in more detail that will be included in the certificate. # noqa: E501 - - :return: The metadata_json of this Batch. # noqa: E501 - :rtype: str - """ - return self._metadata_json - - @metadata_json.setter - def metadata_json(self, metadata_json): - """Sets the metadata_json of this Batch. - - Provide optional metadata to describe the research object batch in more detail that will be included in the certificate. # noqa: E501 - - :param metadata_json: The metadata_json of this Batch. # noqa: E501 - :type: str - """ - - self._metadata_json = metadata_json - - def to_dict(self): - """Returns the model properties as a dict""" - result = {} - - for attr, _ in six.iteritems(self.swagger_types): - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - if issubclass(Batch, dict): - for key, value in self.items(): - result[key] = value - - return result - - def to_str(self): - """Returns the string representation of the model""" - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - if not isinstance(other, Batch): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_pdf_json_certificate.py b/src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_pdf_json_certificate.py deleted file mode 100644 index 8c1b50d8..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_pdf_json_certificate.py +++ /dev/null @@ -1,380 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -import pprint -import re # noqa: F401 - -import six - - -class ControllerCertToolsGeneratePdfJsonCertificate(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - """ - """ - Attributes: - swagger_types (dict): The key is attribute name - and the value is attribute type. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - """ - swagger_types = { - 'context': 'list[str]', - 'id': 'str', - 'type': 'list[str]', - 'issuer': 'str', - 'issuance_date': 'str', - 'credential_subject': 'object', - 'display_html': 'str', - 'crid': 'str', - 'crid_type': 'str', - 'metadata_json': 'str', - 'proof': 'object' - } - - attribute_map = { - 'context': '@context', - 'id': 'id', - 'type': 'type', - 'issuer': 'issuer', - 'issuance_date': 'issuanceDate', - 'credential_subject': 'credentialSubject', - 'display_html': 'displayHtml', - 'crid': 'crid', - 'crid_type': 'cridType', - 'metadata_json': 'metadataJson', - 'proof': 'proof' - } - - def __init__(self, context=None, id=None, type=None, issuer=None, issuance_date=None, credential_subject=None, display_html=None, crid=None, crid_type=None, metadata_json=None, proof=None): # noqa: E501 - """ControllerCertToolsGeneratePdfJsonCertificate - a model defined in Swagger""" # noqa: E501 - self._context = None - self._id = None - self._type = None - self._issuer = None - self._issuance_date = None - self._credential_subject = None - self._display_html = None - self._crid = None - self._crid_type = None - self._metadata_json = None - self._proof = None - self.discriminator = None - if context is not None: - self.context = context - self.id = id - self.type = type - self.issuer = issuer - self.issuance_date = issuance_date - self.credential_subject = credential_subject - if display_html is not None: - self.display_html = display_html - self.crid = crid - if crid_type is not None: - self.crid_type = crid_type - if metadata_json is not None: - self.metadata_json = metadata_json - self.proof = proof - - @property - def context(self): - """Gets the context of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - Relevant JSON-LD context links in order to validate Verifiable Credentials according to their spec. # noqa: E501 - - :return: The context of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: list[str] - """ - return self._context - - @context.setter - def context(self, context): - """Sets the context of this ControllerCertToolsGeneratePdfJsonCertificate. - - Relevant JSON-LD context links in order to validate Verifiable Credentials according to their spec. # noqa: E501 - - :param context: The context of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: list[str] - """ - - self._context = context - - @property - def id(self): - """Gets the id of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The id of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._id - - @id.setter - def id(self, id): - """Sets the id of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param id: The id of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: str - """ - if id is None: - raise ValueError("Invalid value for `id`, must not be `None`") # noqa: E501 - - self._id = id - - @property - def type(self): - """Gets the type of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The type of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: list[str] - """ - return self._type - - @type.setter - def type(self, type): - """Sets the type of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param type: The type of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: list[str] - """ - if type is None: - raise ValueError("Invalid value for `type`, must not be `None`") # noqa: E501 - - self._type = type - - @property - def issuer(self): - """Gets the issuer of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The issuer of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._issuer - - @issuer.setter - def issuer(self, issuer): - """Sets the issuer of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param issuer: The issuer of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: str - """ - if issuer is None: - raise ValueError("Invalid value for `issuer`, must not be `None`") # noqa: E501 - - self._issuer = issuer - - @property - def issuance_date(self): - """Gets the issuance_date of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The issuance_date of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._issuance_date - - @issuance_date.setter - def issuance_date(self, issuance_date): - """Sets the issuance_date of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param issuance_date: The issuance_date of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: str - """ - if issuance_date is None: - raise ValueError("Invalid value for `issuance_date`, must not be `None`") # noqa: E501 - - self._issuance_date = issuance_date - - @property - def credential_subject(self): - """Gets the credential_subject of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The credential_subject of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: object - """ - return self._credential_subject - - @credential_subject.setter - def credential_subject(self, credential_subject): - """Sets the credential_subject of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param credential_subject: The credential_subject of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: object - """ - if credential_subject is None: - raise ValueError("Invalid value for `credential_subject`, must not be `None`") # noqa: E501 - - self._credential_subject = credential_subject - - @property - def display_html(self): - """Gets the display_html of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The display_html of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._display_html - - @display_html.setter - def display_html(self, display_html): - """Sets the display_html of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param display_html: The display_html of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: str - """ - - self._display_html = display_html - - @property - def crid(self): - """Gets the crid of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The crid of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._crid - - @crid.setter - def crid(self, crid): - """Sets the crid of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param crid: The crid of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: str - """ - if crid is None: - raise ValueError("Invalid value for `crid`, must not be `None`") # noqa: E501 - - self._crid = crid - - @property - def crid_type(self): - """Gets the crid_type of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The crid_type of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._crid_type - - @crid_type.setter - def crid_type(self, crid_type): - """Sets the crid_type of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param crid_type: The crid_type of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: str - """ - - self._crid_type = crid_type - - @property - def metadata_json(self): - """Gets the metadata_json of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The metadata_json of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._metadata_json - - @metadata_json.setter - def metadata_json(self, metadata_json): - """Sets the metadata_json of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param metadata_json: The metadata_json of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: str - """ - - self._metadata_json = metadata_json - - @property - def proof(self): - """Gets the proof of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - - - :return: The proof of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :rtype: object - """ - return self._proof - - @proof.setter - def proof(self, proof): - """Sets the proof of this ControllerCertToolsGeneratePdfJsonCertificate. - - - :param proof: The proof of this ControllerCertToolsGeneratePdfJsonCertificate. # noqa: E501 - :type: object - """ - if proof is None: - raise ValueError("Invalid value for `proof`, must not be `None`") # noqa: E501 - - self._proof = proof - - def to_dict(self): - """Returns the model properties as a dict""" - result = {} - - for attr, _ in six.iteritems(self.swagger_types): - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - if issubclass(ControllerCertToolsGeneratePdfJsonCertificate, dict): - for key, value in self.items(): - result[key] = value - - return result - - def to_str(self): - """Returns the string representation of the model""" - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - if not isinstance(other, ControllerCertToolsGeneratePdfJsonCertificate): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_unsigned_certificate_json_certificate.py b/src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_unsigned_certificate_json_certificate.py deleted file mode 100644 index fa0da3cb..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/models/controller_cert_tools_generate_unsigned_certificate_json_certificate.py +++ /dev/null @@ -1,380 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -import pprint -import re # noqa: F401 - -import six - - -class ControllerCertToolsGenerateUnsignedCertificateJsonCertificate(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - """ - """ - Attributes: - swagger_types (dict): The key is attribute name - and the value is attribute type. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - """ - swagger_types = { - 'context': 'list[str]', - 'id': 'str', - 'type': 'list[str]', - 'issuer': 'str', - 'issuance_date': 'str', - 'credential_subject': 'object', - 'display_html': 'str', - 'crid': 'str', - 'crid_type': 'str', - 'metadata_json': 'str', - 'proof': 'object' - } - - attribute_map = { - 'context': '@context', - 'id': 'id', - 'type': 'type', - 'issuer': 'issuer', - 'issuance_date': 'issuanceDate', - 'credential_subject': 'credentialSubject', - 'display_html': 'displayHtml', - 'crid': 'crid', - 'crid_type': 'cridType', - 'metadata_json': 'metadataJson', - 'proof': 'proof' - } - - def __init__(self, context=None, id=None, type=None, issuer=None, issuance_date=None, credential_subject=None, display_html=None, crid=None, crid_type=None, metadata_json=None, proof=None): # noqa: E501 - """ControllerCertToolsGenerateUnsignedCertificateJsonCertificate - a model defined in Swagger""" # noqa: E501 - self._context = None - self._id = None - self._type = None - self._issuer = None - self._issuance_date = None - self._credential_subject = None - self._display_html = None - self._crid = None - self._crid_type = None - self._metadata_json = None - self._proof = None - self.discriminator = None - if context is not None: - self.context = context - self.id = id - self.type = type - self.issuer = issuer - self.issuance_date = issuance_date - self.credential_subject = credential_subject - if display_html is not None: - self.display_html = display_html - self.crid = crid - if crid_type is not None: - self.crid_type = crid_type - if metadata_json is not None: - self.metadata_json = metadata_json - self.proof = proof - - @property - def context(self): - """Gets the context of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - Relevant JSON-LD context links in order to validate Verifiable Credentials according to their spec. # noqa: E501 - - :return: The context of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: list[str] - """ - return self._context - - @context.setter - def context(self, context): - """Sets the context of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - Relevant JSON-LD context links in order to validate Verifiable Credentials according to their spec. # noqa: E501 - - :param context: The context of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: list[str] - """ - - self._context = context - - @property - def id(self): - """Gets the id of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The id of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._id - - @id.setter - def id(self, id): - """Sets the id of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param id: The id of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: str - """ - if id is None: - raise ValueError("Invalid value for `id`, must not be `None`") # noqa: E501 - - self._id = id - - @property - def type(self): - """Gets the type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: list[str] - """ - return self._type - - @type.setter - def type(self, type): - """Sets the type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param type: The type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: list[str] - """ - if type is None: - raise ValueError("Invalid value for `type`, must not be `None`") # noqa: E501 - - self._type = type - - @property - def issuer(self): - """Gets the issuer of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The issuer of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._issuer - - @issuer.setter - def issuer(self, issuer): - """Sets the issuer of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param issuer: The issuer of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: str - """ - if issuer is None: - raise ValueError("Invalid value for `issuer`, must not be `None`") # noqa: E501 - - self._issuer = issuer - - @property - def issuance_date(self): - """Gets the issuance_date of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The issuance_date of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._issuance_date - - @issuance_date.setter - def issuance_date(self, issuance_date): - """Sets the issuance_date of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param issuance_date: The issuance_date of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: str - """ - if issuance_date is None: - raise ValueError("Invalid value for `issuance_date`, must not be `None`") # noqa: E501 - - self._issuance_date = issuance_date - - @property - def credential_subject(self): - """Gets the credential_subject of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The credential_subject of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: object - """ - return self._credential_subject - - @credential_subject.setter - def credential_subject(self, credential_subject): - """Sets the credential_subject of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param credential_subject: The credential_subject of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: object - """ - if credential_subject is None: - raise ValueError("Invalid value for `credential_subject`, must not be `None`") # noqa: E501 - - self._credential_subject = credential_subject - - @property - def display_html(self): - """Gets the display_html of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The display_html of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._display_html - - @display_html.setter - def display_html(self, display_html): - """Sets the display_html of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param display_html: The display_html of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: str - """ - - self._display_html = display_html - - @property - def crid(self): - """Gets the crid of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The crid of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._crid - - @crid.setter - def crid(self, crid): - """Sets the crid of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param crid: The crid of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: str - """ - if crid is None: - raise ValueError("Invalid value for `crid`, must not be `None`") # noqa: E501 - - self._crid = crid - - @property - def crid_type(self): - """Gets the crid_type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The crid_type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._crid_type - - @crid_type.setter - def crid_type(self, crid_type): - """Sets the crid_type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param crid_type: The crid_type of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: str - """ - - self._crid_type = crid_type - - @property - def metadata_json(self): - """Gets the metadata_json of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The metadata_json of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: str - """ - return self._metadata_json - - @metadata_json.setter - def metadata_json(self, metadata_json): - """Sets the metadata_json of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param metadata_json: The metadata_json of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: str - """ - - self._metadata_json = metadata_json - - @property - def proof(self): - """Gets the proof of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - - - :return: The proof of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :rtype: object - """ - return self._proof - - @proof.setter - def proof(self, proof): - """Sets the proof of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. - - - :param proof: The proof of this ControllerCertToolsGenerateUnsignedCertificateJsonCertificate. # noqa: E501 - :type: object - """ - if proof is None: - raise ValueError("Invalid value for `proof`, must not be `None`") # noqa: E501 - - self._proof = proof - - def to_dict(self): - """Returns the model properties as a dict""" - result = {} - - for attr, _ in six.iteritems(self.swagger_types): - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - if issubclass(ControllerCertToolsGenerateUnsignedCertificateJsonCertificate, dict): - for key, value in self.items(): - result[key] = value - - return result - - def to_str(self): - """Returns the string representation of the model""" - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - if not isinstance(other, ControllerCertToolsGenerateUnsignedCertificateJsonCertificate): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/src/caosadvancedtools/bloxberg/swagger_client/models/http_validation_error.py b/src/caosadvancedtools/bloxberg/swagger_client/models/http_validation_error.py deleted file mode 100644 index 67c23fba..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/models/http_validation_error.py +++ /dev/null @@ -1,111 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -import pprint -import re # noqa: F401 - -import six - - -class HTTPValidationError(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - """ - """ - Attributes: - swagger_types (dict): The key is attribute name - and the value is attribute type. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - """ - swagger_types = { - 'detail': 'list[ValidationError]' - } - - attribute_map = { - 'detail': 'detail' - } - - def __init__(self, detail=None): # noqa: E501 - """HTTPValidationError - a model defined in Swagger""" # noqa: E501 - self._detail = None - self.discriminator = None - if detail is not None: - self.detail = detail - - @property - def detail(self): - """Gets the detail of this HTTPValidationError. # noqa: E501 - - - :return: The detail of this HTTPValidationError. # noqa: E501 - :rtype: list[ValidationError] - """ - return self._detail - - @detail.setter - def detail(self, detail): - """Sets the detail of this HTTPValidationError. - - - :param detail: The detail of this HTTPValidationError. # noqa: E501 - :type: list[ValidationError] - """ - - self._detail = detail - - def to_dict(self): - """Returns the model properties as a dict""" - result = {} - - for attr, _ in six.iteritems(self.swagger_types): - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - if issubclass(HTTPValidationError, dict): - for key, value in self.items(): - result[key] = value - - return result - - def to_str(self): - """Returns the string representation of the model""" - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - if not isinstance(other, HTTPValidationError): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/src/caosadvancedtools/bloxberg/swagger_client/models/validation_error.py b/src/caosadvancedtools/bloxberg/swagger_client/models/validation_error.py deleted file mode 100644 index 96d1e237..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/models/validation_error.py +++ /dev/null @@ -1,166 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -import pprint -import re # noqa: F401 - -import six - - -class ValidationError(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - """ - """ - Attributes: - swagger_types (dict): The key is attribute name - and the value is attribute type. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - """ - swagger_types = { - 'loc': 'list[str]', - 'msg': 'str', - 'type': 'str' - } - - attribute_map = { - 'loc': 'loc', - 'msg': 'msg', - 'type': 'type' - } - - def __init__(self, loc=None, msg=None, type=None): # noqa: E501 - """ValidationError - a model defined in Swagger""" # noqa: E501 - self._loc = None - self._msg = None - self._type = None - self.discriminator = None - self.loc = loc - self.msg = msg - self.type = type - - @property - def loc(self): - """Gets the loc of this ValidationError. # noqa: E501 - - - :return: The loc of this ValidationError. # noqa: E501 - :rtype: list[str] - """ - return self._loc - - @loc.setter - def loc(self, loc): - """Sets the loc of this ValidationError. - - - :param loc: The loc of this ValidationError. # noqa: E501 - :type: list[str] - """ - if loc is None: - raise ValueError("Invalid value for `loc`, must not be `None`") # noqa: E501 - - self._loc = loc - - @property - def msg(self): - """Gets the msg of this ValidationError. # noqa: E501 - - - :return: The msg of this ValidationError. # noqa: E501 - :rtype: str - """ - return self._msg - - @msg.setter - def msg(self, msg): - """Sets the msg of this ValidationError. - - - :param msg: The msg of this ValidationError. # noqa: E501 - :type: str - """ - if msg is None: - raise ValueError("Invalid value for `msg`, must not be `None`") # noqa: E501 - - self._msg = msg - - @property - def type(self): - """Gets the type of this ValidationError. # noqa: E501 - - - :return: The type of this ValidationError. # noqa: E501 - :rtype: str - """ - return self._type - - @type.setter - def type(self, type): - """Sets the type of this ValidationError. - - - :param type: The type of this ValidationError. # noqa: E501 - :type: str - """ - if type is None: - raise ValueError("Invalid value for `type`, must not be `None`") # noqa: E501 - - self._type = type - - def to_dict(self): - """Returns the model properties as a dict""" - result = {} - - for attr, _ in six.iteritems(self.swagger_types): - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - if issubclass(ValidationError, dict): - for key, value in self.items(): - result[key] = value - - return result - - def to_str(self): - """Returns the string representation of the model""" - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - if not isinstance(other, ValidationError): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/src/caosadvancedtools/bloxberg/swagger_client/rest.py b/src/caosadvancedtools/bloxberg/swagger_client/rest.py deleted file mode 100644 index c42e720c..00000000 --- a/src/caosadvancedtools/bloxberg/swagger_client/rest.py +++ /dev/null @@ -1,322 +0,0 @@ -# coding: utf-8 - -""" - Research Object Certification - - No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501 - - OpenAPI spec version: 0.2.0 - - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" - -from __future__ import absolute_import - -import io -import json -import logging -import re -import ssl - -import certifi -# python 2 and python 3 compatibility library -import six -from six.moves.urllib.parse import urlencode - -try: - import urllib3 -except ImportError: - raise ImportError('Swagger python client requires urllib3.') - - -logger = logging.getLogger(__name__) - - -class RESTResponse(io.IOBase): - - def __init__(self, resp): - self.urllib3_response = resp - self.status = resp.status - self.reason = resp.reason - self.data = resp.data - - def getheaders(self): - """Returns a dictionary of the response headers.""" - return self.urllib3_response.getheaders() - - def getheader(self, name, default=None): - """Returns a given response header.""" - return self.urllib3_response.getheader(name, default) - - -class RESTClientObject(object): - - def __init__(self, configuration, pools_size=4, maxsize=None): - # urllib3.PoolManager will pass all kw parameters to connectionpool - # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501 - # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501 - # maxsize is the number of requests to host that are allowed in parallel # noqa: E501 - # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501 - - # cert_reqs - if configuration.verify_ssl: - cert_reqs = ssl.CERT_REQUIRED - else: - cert_reqs = ssl.CERT_NONE - - # ca_certs - if configuration.ssl_ca_cert: - ca_certs = configuration.ssl_ca_cert - else: - # if not set certificate file, use Mozilla's root certificates. - ca_certs = certifi.where() - - addition_pool_args = {} - if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = configuration.assert_hostname # noqa: E501 - - if maxsize is None: - if configuration.connection_pool_maxsize is not None: - maxsize = configuration.connection_pool_maxsize - else: - maxsize = 4 - - # https pool manager - if configuration.proxy: - self.pool_manager = urllib3.ProxyManager( - num_pools=pools_size, - maxsize=maxsize, - cert_reqs=cert_reqs, - ca_certs=ca_certs, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - **addition_pool_args - ) - else: - self.pool_manager = urllib3.PoolManager( - num_pools=pools_size, - maxsize=maxsize, - cert_reqs=cert_reqs, - ca_certs=ca_certs, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) - - def request(self, method, url, query_params=None, headers=None, - body=None, post_params=None, _preload_content=True, - _request_timeout=None): - """Perform requests. - - :param method: http request method - :param url: http request url - :param query_params: query parameters in the url - :param headers: http request headers - :param body: request json body, for `application/json` - :param post_params: request post parameters, - `application/x-www-form-urlencoded` - and `multipart/form-data` - :param _preload_content: if False, the urllib3.HTTPResponse object will - be returned without reading/decoding response - data. Default is True. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - """ - method = method.upper() - assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', - 'PATCH', 'OPTIONS'] - - if post_params and body: - raise ValueError( - "body parameter cannot be used with post_params parameter." - ) - - post_params = post_params or {} - headers = headers or {} - - timeout = None - if _request_timeout: - if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)): # noqa: E501,F821 - timeout = urllib3.Timeout(total=_request_timeout) - elif (isinstance(_request_timeout, tuple) and - len(_request_timeout) == 2): - timeout = urllib3.Timeout( - connect=_request_timeout[0], read=_request_timeout[1]) - - if 'Content-Type' not in headers: - headers['Content-Type'] = 'application/json' - - try: - # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` - if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: - if query_params: - url += '?' + urlencode(query_params) - if re.search('json', headers['Content-Type'], re.IGNORECASE): - request_body = '{}' - if body is not None: - request_body = json.dumps(body) - r = self.pool_manager.request( - method, url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 - r = self.pool_manager.request( - method, url, - fields=post_params, - encode_multipart=False, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - elif headers['Content-Type'] == 'multipart/form-data': - # must del headers['Content-Type'], or the correct - # Content-Type which generated by urllib3 will be - # overwritten. - del headers['Content-Type'] - r = self.pool_manager.request( - method, url, - fields=post_params, - encode_multipart=True, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form - elif isinstance(body, str): - request_body = body - r = self.pool_manager.request( - method, url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - else: - # Cannot generate the request from given parameters - msg = """Cannot prepare a request message for provided - arguments. Please check that your arguments match - declared content type.""" - raise ApiException(status=0, reason=msg) - # For `GET`, `HEAD` - else: - r = self.pool_manager.request(method, url, - fields=query_params, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - except urllib3.exceptions.SSLError as e: - msg = "{0}\n{1}".format(type(e).__name__, str(e)) - raise ApiException(status=0, reason=msg) - - if _preload_content: - r = RESTResponse(r) - - # In the python 3, the response.data is bytes. - # we need to decode it to string. - if six.PY3: - r.data = r.data.decode('utf8') - - # log response body - logger.debug("response body: %s", r.data) - - if not 200 <= r.status <= 299: - raise ApiException(http_resp=r) - - return r - - def GET(self, url, headers=None, query_params=None, _preload_content=True, - _request_timeout=None): - return self.request("GET", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params) - - def HEAD(self, url, headers=None, query_params=None, _preload_content=True, - _request_timeout=None): - return self.request("HEAD", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params) - - def OPTIONS(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("OPTIONS", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def DELETE(self, url, headers=None, query_params=None, body=None, - _preload_content=True, _request_timeout=None): - return self.request("DELETE", url, - headers=headers, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def POST(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("POST", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def PUT(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("PUT", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def PATCH(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("PATCH", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - -class ApiException(Exception): - - def __init__(self, status=None, reason=None, http_resp=None): - if http_resp: - self.status = http_resp.status - self.reason = http_resp.reason - self.body = http_resp.data - self.headers = http_resp.getheaders() - else: - self.status = status - self.reason = reason - self.body = None - self.headers = None - - def __str__(self): - """Custom error messages for exception""" - error_message = "({0})\n"\ - "Reason: {1}\n".format(self.status, self.reason) - if self.headers: - error_message += "HTTP response headers: {0}\n".format( - self.headers) - - if self.body: - error_message += "HTTP response body: {0}\n".format(self.body) - - return error_message diff --git a/src/doc/conf.py b/src/doc/conf.py index 2aa08622..b769fd1e 100644 --- a/src/doc/conf.py +++ b/src/doc/conf.py @@ -201,6 +201,5 @@ autodoc_default_options = { 'undoc-members': None, } autodoc_mock_imports = [ - "caosadvancedtools.bloxberg", "labfolder", ] -- GitLab From ef34db532dee1a66c2981be51c24fc0e40fed675 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Fri, 11 Oct 2024 16:06:27 +0200 Subject: [PATCH 012/106] FIX: add datatype, unit and description to properties that are part of Records --- src/caosadvancedtools/models/data_model.py | 1 + src/caosadvancedtools/models/parser.py | 66 +++++++++++++++------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 26641489..7da52788 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -149,6 +149,7 @@ class DataModel(dict): ), name=ent.name)) if diff != "": + breakpoint() if verbose: print(diff) any_change = True diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 175f2f7f..964cf1f5 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -341,6 +341,38 @@ debug : bool, optional f"invalid keyword in line {entity['__line__']}:", 1) raise ValueError(err_str, *err.args[1:]) from err + # Update properties that are part of record types: + # e.g. add their datatypes, units etc.. + # Otherwise comparison of existing models and the parsed model become difficult. + for name, ent in self.model.items(): + if not isinstance(ent, db.RecordType): + continue + props = ent.get_properties() + for prop in props: + if prop.name in self.model: + model_prop = self.model[prop.name] + # The information must be missing, we don't want to overwrite it accidentally: + if prop.datatype is not None and prop.datatype != model_prop.datatype: + # breakpoint() + raise RuntimeError("datatype must not be set, here. This is probably a bug.") + if prop.unit is not None and prop.unit != model_prop.unit: + # continue + raise RuntimeError("unit must not be set, here. This is probably a bug.") + if prop.description is not None and prop.description != model_prop.description: + # continue + raise RuntimeError("description must not be set, here. This is probably a bug.") + + # If this property has a more detailed definition in the model, + # copy over the information: + + if isinstance(model_prop, db.RecordType): + # in this case the datatype equals the name of the record type: + prop.datatype = prop.name + else: + prop.datatype = model_prop.datatype + prop.unit = model_prop.unit + prop.description = model_prop.description + return DataModel(self.model.values()) @staticmethod @@ -470,6 +502,7 @@ debug : bool, optional """ for n, e in props.items(): + if n in KEYWORDS: if n in KEYWORDS_IGNORED: continue @@ -543,6 +576,13 @@ debug : bool, optional if name in self.treated: raise TwiceDefinedException(name) + # for reducing a little bit of code duplication: + importance_dict = { + "recommended_properties": db.RECOMMENDED, + "obligatory_properties": db.OBLIGATORY, + "suggested_properties": db.SUGGESTED + } + for prop_name, prop in definition.items(): if prop_name == "__line__": continue @@ -558,26 +598,14 @@ debug : bool, optional # Handled above continue - elif prop_name == "recommended_properties": - self._add_to_recordtype( - name, prop, importance=db.RECOMMENDED) - - for n, e in prop.items(): - self._treat_entity(n, e) - - elif prop_name == "obligatory_properties": - self._add_to_recordtype( - name, prop, importance=db.OBLIGATORY) - - for n, e in prop.items(): - self._treat_entity(n, e) - - elif prop_name == "suggested_properties": - self._add_to_recordtype( - name, prop, importance=db.SUGGESTED) + elif prop_name in importance_dict: + for imp_name, imp_val in importance_dict.items(): + if prop_name == imp_name: + self._add_to_recordtype( + name, prop, importance=imp_val) - for n, e in prop.items(): - self._treat_entity(n, e) + for n, e in prop.items(): + self._treat_entity(n, e) # datatype is already set elif prop_name == "datatype": -- GitLab From 112df32d7e7ed10f5b1bac9994ba8352ed9c3501 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Mon, 14 Oct 2024 18:12:51 +0200 Subject: [PATCH 013/106] MAINT: Unit tests for Python 3.13 --- .gitlab-ci.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61c68e67..65698d86 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -165,15 +165,8 @@ unittest_py312: unittest_py313: tags: [docker] stage: unittest - image: python:3.13-rc - script: - # TODO: Replace by '*python_test_script' as soon as 3.13 has been officially released. - - apt update && apt install -y cargo || true - - pip install meson[ninja] meson-python || true - - pip install pynose pandas pytest pytest-cov gitignore-parser openpyxl>=3.0.7 xlrd==1.2 h5py || true - - pip install git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev || true - - pip install . || true - - pytest --cov=caosadvancedtools unittests || true + image: python:3.13 + script: *python_test_script # Build the sphinx documentation and make it ready for deployment by Gitlab Pages # Special job for serving a static website. See https://docs.gitlab.com/ee/ci/yaml/README.html#pages -- GitLab From a2256bcfa2382060b3b155b154d2df3c848fd67d Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Tue, 15 Oct 2024 11:59:12 +0200 Subject: [PATCH 014/106] DOC: Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62794e6e..3be1b6de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### +* Official support for Python 3.13 + ### Changed ### ### Deprecated ### -- GitLab From a76cf9a53713fc1d7b0e67b4ac5d099d26f02c88 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Thu, 24 Oct 2024 13:22:04 +0200 Subject: [PATCH 015/106] TST: test for confirming issue number 71 --- unittests/test_yaml_model_parser.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index d6dbf718..371090cf 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -641,3 +641,21 @@ RT2: </RecordType> , 'bar': <RecordType name="bar"/> }""" + + +def test_setting_values(): + model = parse_model_from_string(""" +parameter: + datatype: INTEGER + +Simulation: + role: Record + obligatory_properties: + parameter: 26 +""") + + assert len(model) == 2 + assert str(model["parameter"])[:-1] == '<Property name="parameter" datatype="INTEGER"/>' + assert model["Simulation"].role == "Record" + assert model["Simulation"].name == "Simulation" + assert model["Simulation"].get_property("parameter").value == 26 -- GitLab From 5f8a472d0c363c0804288f5dee29763ea09cd48c Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Fri, 25 Oct 2024 11:31:09 +0200 Subject: [PATCH 016/106] fix(yaml-models): corrected output labels for the yaml model parser --- src/caosadvancedtools/models/data_model.py | 6 +- unittests/test_yaml_model_parser.py | 68 ++++++++++++++++++---- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 26641489..bda8cad6 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -145,8 +145,10 @@ class DataModel(dict): else: query = db.Query(f"FIND ENTITY with id={ent.id}") ref = query.execute(unique=True) - diff = (describe_diff(*compare_entities(ent, ref - ), name=ent.name)) + diff = (describe_diff(*compare_entities(ent, ref), + name=ent.name, + label_old="version from the yaml file", + label_new="version from LinkAhead")) if diff != "": if verbose: diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index 371090cf..bef2a1b5 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -21,7 +21,11 @@ from datetime import date from tempfile import NamedTemporaryFile from pytest import raises, mark +from unittest.mock import Mock + import linkahead as db + +import caosadvancedtools from caosadvancedtools.models.parser import (TwiceDefinedException, YamlDefinitionError, parse_model_from_string, @@ -644,18 +648,58 @@ RT2: def test_setting_values(): - model = parse_model_from_string(""" -parameter: - datatype: INTEGER - -Simulation: - role: Record + model = parse_model_from_string(""" + parameter: + datatype: INTEGER + + Simulation: + role: Record + obligatory_properties: + parameter: 26 + """) + + assert len(model) == 2 + assert str(model["parameter"])[:-1] == '<Property name="parameter" datatype="INTEGER"/>' + assert model["Simulation"].role == "Record" + assert model["Simulation"].name == "Simulation" + assert model["Simulation"].get_property("parameter").value == 26 + + +def test_sync_output(capfd): + model = parse_model_from_string(""" +RT: obligatory_properties: - parameter: 26 + identifier: + datatype: TEXT """) - assert len(model) == 2 - assert str(model["parameter"])[:-1] == '<Property name="parameter" datatype="INTEGER"/>' - assert model["Simulation"].role == "Record" - assert model["Simulation"].name == "Simulation" - assert model["Simulation"].get_property("parameter").value == 26 + existing_entities = [db.RecordType(name="RT", id=25).add_property(name="identifier", + datatype="INTEGER", + importance="OBLIGATORY", + id=24), + db.Property(name="identifier", datatype="INTEGER", id=24)] + + def get_existing_entities(ent_cont): + return existing_entities + + class MockQuery: + def __init__(self, q): + self.q = q + + def execute(self, unique=True): + id = int(self.q.split("=")[1]) + for existing_ent in existing_entities: + if existing_ent.id == id: + return existing_ent + return None + + model.get_existing_entities = get_existing_entities + caosadvancedtools.models.parser.db.Query = MockQuery + caosadvancedtools.models.parser.db.Container.update = Mock() + + model.sync_data_model(True, True) + assert caosadvancedtools.models.parser.db.Container.update.called + output, err = capfd.readouterr() + print(output) + assert "version from the yaml file: TEXT" in output + assert "version from LinkAhead: INTEGER" in output -- GitLab From f8b92cdd80b07b1af33a396dd4697b2c41970ec9 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Fri, 25 Oct 2024 11:31:09 +0200 Subject: [PATCH 017/106] fix(yaml-models): corrected output labels for the yaml model parser --- src/caosadvancedtools/models/data_model.py | 6 ++- unittests/test_yaml_model_parser.py | 44 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 26641489..bda8cad6 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -145,8 +145,10 @@ class DataModel(dict): else: query = db.Query(f"FIND ENTITY with id={ent.id}") ref = query.execute(unique=True) - diff = (describe_diff(*compare_entities(ent, ref - ), name=ent.name)) + diff = (describe_diff(*compare_entities(ent, ref), + name=ent.name, + label_old="version from the yaml file", + label_new="version from LinkAhead")) if diff != "": if verbose: diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index d6dbf718..5b3116fc 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -21,7 +21,11 @@ from datetime import date from tempfile import NamedTemporaryFile from pytest import raises, mark +from unittest.mock import Mock + import linkahead as db + +import caosadvancedtools from caosadvancedtools.models.parser import (TwiceDefinedException, YamlDefinitionError, parse_model_from_string, @@ -641,3 +645,43 @@ RT2: </RecordType> , 'bar': <RecordType name="bar"/> }""" + + +def test_sync_output(capfd): + model = parse_model_from_string(""" +RT: + obligatory_properties: + identifier: + datatype: TEXT +""") + + existing_entities = [db.RecordType(name="RT", id=25).add_property(name="identifier", + datatype="INTEGER", + importance="OBLIGATORY", + id=24), + db.Property(name="identifier", datatype="INTEGER", id=24)] + + def get_existing_entities(ent_cont): + return existing_entities + + class MockQuery: + def __init__(self, q): + self.q = q + + def execute(self, unique=True): + id = int(self.q.split("=")[1]) + for existing_ent in existing_entities: + if existing_ent.id == id: + return existing_ent + return None + + model.get_existing_entities = get_existing_entities + caosadvancedtools.models.parser.db.Query = MockQuery + caosadvancedtools.models.parser.db.Container.update = Mock() + + model.sync_data_model(True, True) + assert caosadvancedtools.models.parser.db.Container.update.called + output, err = capfd.readouterr() + print(output) + assert "version from the yaml file: TEXT" in output + assert "version from LinkAhead: INTEGER" in output -- GitLab From 3fe65738d4ba2f83270b56a21b90ef92acc4ad36 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Fri, 25 Oct 2024 11:38:55 +0200 Subject: [PATCH 018/106] reverted unwanted commit that also included indentation fix --- unittests/test_yaml_model_parser.py | 39 ----------------------------- 1 file changed, 39 deletions(-) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index bef2a1b5..370c8402 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -664,42 +664,3 @@ def test_setting_values(): assert model["Simulation"].name == "Simulation" assert model["Simulation"].get_property("parameter").value == 26 - -def test_sync_output(capfd): - model = parse_model_from_string(""" -RT: - obligatory_properties: - identifier: - datatype: TEXT -""") - - existing_entities = [db.RecordType(name="RT", id=25).add_property(name="identifier", - datatype="INTEGER", - importance="OBLIGATORY", - id=24), - db.Property(name="identifier", datatype="INTEGER", id=24)] - - def get_existing_entities(ent_cont): - return existing_entities - - class MockQuery: - def __init__(self, q): - self.q = q - - def execute(self, unique=True): - id = int(self.q.split("=")[1]) - for existing_ent in existing_entities: - if existing_ent.id == id: - return existing_ent - return None - - model.get_existing_entities = get_existing_entities - caosadvancedtools.models.parser.db.Query = MockQuery - caosadvancedtools.models.parser.db.Container.update = Mock() - - model.sync_data_model(True, True) - assert caosadvancedtools.models.parser.db.Container.update.called - output, err = capfd.readouterr() - print(output) - assert "version from the yaml file: TEXT" in output - assert "version from LinkAhead: INTEGER" in output -- GitLab From ac4cc18ecb3a26b092dfc1fb8b9bdfdfcf2848b0 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Fri, 25 Oct 2024 12:23:43 +0200 Subject: [PATCH 019/106] docs(apiutils): updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3be1b6de..624c2b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `TableImporter.check_missing` in case of array-valued fields in table * YAML model parser has better description handling. +* YAML model parser shows "LinkAhead" and "the yaml file" in its comparison display + instead of "old" and "new". ### Documentation ### -- GitLab From 499cbc7dc393fd74a36896a4fda9b7fcadaa69d1 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Fri, 25 Oct 2024 15:45:12 +0200 Subject: [PATCH 020/106] maint(yaml-model): remove breakpoint --- src/caosadvancedtools/models/data_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 7da52788..26641489 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -149,7 +149,6 @@ class DataModel(dict): ), name=ent.name)) if diff != "": - breakpoint() if verbose: print(diff) any_change = True -- GitLab From b65b8426c987abebb5e5fd2aabc5265e9bff7653 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Fri, 25 Oct 2024 16:28:06 +0200 Subject: [PATCH 021/106] tests(yaml-models): test for comparisons in yaml model parser --- unittests/test_yaml_model_parser.py | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index d6dbf718..574b41da 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -27,6 +27,8 @@ from caosadvancedtools.models.parser import (TwiceDefinedException, parse_model_from_string, parse_model_from_yaml) +from linkahead.apiutils import compare_entities + def to_file(string): f = NamedTemporaryFile(mode="w", delete=False) @@ -641,3 +643,71 @@ RT2: </RecordType> , 'bar': <RecordType name="bar"/> }""" + + +def test_comparison_yaml_model(): + """ + Test for this issue: + https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/130 + """ + model_string = """ +foo: + datatype: INTEGER + description: bla bla + unit: m + +RT1: + obligatory_properties: + foo: + RT2: + test_reference: + +RT2: + +test_reference: + datatype: RT2 + """ + model = parse_model_from_string(model_string) + + # Without the fix, foo will have no datatype, description and no unit **as part of RT1**, so the + # comparison with a version taken from a LinkAhead instance will have these attributes. + # Furthermore, RT2 will be set as the datatype **in object version** in the yaml definition, while + # it is an ID in case of the version from the LinkAhead instance. + + p_foo = db.Property(name="foo", datatype="INTEGER", description="bla bla", unit="m") + rt2 = db.RecordType(name="RT2") + rt1 = db.RecordType(name="RT1") + rt1.add_property(p_foo) + rt1.add_property(rt2) + + server_response = """ +<Entities> + <noscript> + </noscript> + <Property id="2272" name="foo" description="bla bla" datatype="INTEGER" unit="m"> + <Version id="7819eedaeba2aa7305e10c96e8cf7b9ac84aea4a" head="true"/> + </Property> + <RecordType id="2273" name="RT1"> + <Version id="0c1b9df6677ee40d1e1429b2123e078ee6c863e0" head="true"/> + <Property id="2272" name="foo" description="bla bla" datatype="INTEGER" unit="m" importance="OBLIGATORY" flag="inheritance:FIX"/> + <Property id="2274" name="RT2" datatype="RT2" importance="OBLIGATORY" flag="inheritance:FIX"/> + <Property id="2275" name="test_reference" datatype="RT2" importance="OBLIGATORY" flag="inheritance:FIX"/> + </RecordType> + <RecordType id="2274" name="RT2"> + <Version id="185940642680a7eba7f71914dd8dd7758dd13faa" head="true"/> + </RecordType> + <Property id="2275" name="test_reference" datatype="RT2"> + <Version id="03cf86061c78a079b376394dfecdf32566b72fb7" head="true"/> + </Property> +</Entities>""" + + entities = db.Container.from_xml(server_response) + + c1 = compare_entities(model["foo"], entities[0]) + c2 = compare_entities(model["RT1"], entities[1]) + c3 = compare_entities(model["RT2"], entities[2]) + c4 = compare_entities(model["test_reference"], entities[3]) + + + + -- GitLab From 6f2e80f3e5b66f65d9717c38c738bf82e8345978 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Mon, 28 Oct 2024 15:16:06 +0100 Subject: [PATCH 022/106] MAINT: Remove unused imports --- unittests/test_yaml_model_parser.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index 370c8402..c578cc33 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -21,11 +21,8 @@ from datetime import date from tempfile import NamedTemporaryFile from pytest import raises, mark -from unittest.mock import Mock - import linkahead as db -import caosadvancedtools from caosadvancedtools.models.parser import (TwiceDefinedException, YamlDefinitionError, parse_model_from_string, @@ -663,4 +660,3 @@ def test_setting_values(): assert model["Simulation"].role == "Record" assert model["Simulation"].name == "Simulation" assert model["Simulation"].get_property("parameter").value == 26 - -- GitLab From 811f08bf9c182410100cee0d29044de10d7a76b0 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Mon, 28 Oct 2024 15:23:45 +0100 Subject: [PATCH 023/106] MAINT: Remove as-of-now unsupported arguments --- src/caosadvancedtools/models/data_model.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index bda8cad6..bd3888b8 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -146,9 +146,7 @@ class DataModel(dict): query = db.Query(f"FIND ENTITY with id={ent.id}") ref = query.execute(unique=True) diff = (describe_diff(*compare_entities(ent, ref), - name=ent.name, - label_old="version from the yaml file", - label_new="version from LinkAhead")) + name=ent.name)) if diff != "": if verbose: -- GitLab From f11a466d28eca0b6f365e7cad117b9c330dc467c Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Wed, 30 Oct 2024 12:57:13 +0100 Subject: [PATCH 024/106] TST(yaml-model-parser): incomplete test for correct output of parser in case of no changes --- src/caosadvancedtools/models/data_model.py | 5 +- src/caosadvancedtools/models/parser.py | 57 +++++++++++----------- unittests/test_yaml_model_parser.py | 21 +++++++- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 26641489..1390cf2e 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -111,8 +111,11 @@ class DataModel(dict): existing_entities = db.Container().extend( DataModel.entities_without( self.values(), [e.name.lower() for e in non_existing_entities])) + self.sync_ids_by_name(tmp_exist) + + if len(non_existing_entities) > 0: if verbose: print("New entities:") @@ -174,7 +177,7 @@ class DataModel(dict): Args ---- entities : iterable - The entities to be retrieved. This object will not be moidified. + The entities to be retrieved. This object will not be modified. Raises ------ diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 964cf1f5..4fa529aa 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -341,37 +341,38 @@ debug : bool, optional f"invalid keyword in line {entity['__line__']}:", 1) raise ValueError(err_str, *err.args[1:]) from err + # TODO: functionality commented out, to be able to test failing test first. # Update properties that are part of record types: # e.g. add their datatypes, units etc.. # Otherwise comparison of existing models and the parsed model become difficult. - for name, ent in self.model.items(): - if not isinstance(ent, db.RecordType): - continue - props = ent.get_properties() - for prop in props: - if prop.name in self.model: - model_prop = self.model[prop.name] - # The information must be missing, we don't want to overwrite it accidentally: - if prop.datatype is not None and prop.datatype != model_prop.datatype: - # breakpoint() - raise RuntimeError("datatype must not be set, here. This is probably a bug.") - if prop.unit is not None and prop.unit != model_prop.unit: - # continue - raise RuntimeError("unit must not be set, here. This is probably a bug.") - if prop.description is not None and prop.description != model_prop.description: - # continue - raise RuntimeError("description must not be set, here. This is probably a bug.") - - # If this property has a more detailed definition in the model, - # copy over the information: - - if isinstance(model_prop, db.RecordType): - # in this case the datatype equals the name of the record type: - prop.datatype = prop.name - else: - prop.datatype = model_prop.datatype - prop.unit = model_prop.unit - prop.description = model_prop.description + # for name, ent in self.model.items(): + # if not isinstance(ent, db.RecordType): + # continue + # props = ent.get_properties() + # for prop in props: + # if prop.name in self.model: + # model_prop = self.model[prop.name] + # # The information must be missing, we don't want to overwrite it accidentally: + # if prop.datatype is not None and prop.datatype != model_prop.datatype: + # # breakpoint() + # raise RuntimeError("datatype must not be set, here. This is probably a bug.") + # if prop.unit is not None and prop.unit != model_prop.unit: + # # continue + # raise RuntimeError("unit must not be set, here. This is probably a bug.") + # if prop.description is not None and prop.description != model_prop.description: + # # continue + # raise RuntimeError("description must not be set, here. This is probably a bug.") + # + # # If this property has a more detailed definition in the model, + # # copy over the information: + # + # if isinstance(model_prop, db.RecordType): + # # in this case the datatype equals the name of the record type: + # prop.datatype = prop.name + # else: + # prop.datatype = model_prop.datatype + # prop.unit = model_prop.unit + # prop.description = model_prop.description return DataModel(self.model.values()) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index 574b41da..56c8672b 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -27,6 +27,8 @@ from caosadvancedtools.models.parser import (TwiceDefinedException, parse_model_from_string, parse_model_from_yaml) +from unittests.mock import Mock + from linkahead.apiutils import compare_entities @@ -645,7 +647,7 @@ RT2: }""" -def test_comparison_yaml_model(): +def test_comparison_yaml_model(capfd): """ Test for this issue: https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/130 @@ -707,7 +709,24 @@ test_reference: c2 = compare_entities(model["RT1"], entities[1]) c3 = compare_entities(model["RT2"], entities[2]) c4 = compare_entities(model["test_reference"], entities[3]) + for cs in (c1, c2, c3, c4): + assert "id" not in cs[0] + assert "id" in cs[1] + + mq = Mock() + def mq_init(self, query): + self.query = query + + def mq_execute(self, unique=True): + pass + + mq.__init__ = mq_init + mq.execute.side_effect = mq_execute + caosadvancedtools.models.parser.db.Query = mq + model.sync_data_model(True, True) + stdout, stderr = capfd.readouterr() + # TODO: test that there were no changes required -- GitLab From ba2c56a885b3710e6432ae4d342e46292400ddac Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 5 Nov 2024 11:59:15 +0100 Subject: [PATCH 025/106] STY: Docstring indentation --- .../table_json_conversion/convert.py | 199 +++++++++--------- 1 file changed, 99 insertions(+), 100 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 09882f96..48a0f676 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -55,10 +55,9 @@ class ForeignError(KeyError): class XLSXConverter: """Class for conversion from XLSX to JSON. -For a detailed description of the required formatting of the XLSX files, see ``specs.md`` in the -documentation. + For a detailed description of the required formatting of the XLSX files, see ``specs.md`` in the + documentation. """ - PARSER: dict[str, Callable] = { "string": str, "number": float, @@ -69,17 +68,17 @@ documentation. def __init__(self, xlsx: Union[str, BinaryIO], schema: Union[dict, str, TextIO], strict: bool = False): """ -Parameters ----------- -xlsx: Union[str, BinaryIO] - Path to the XLSX file or opened file object. + Parameters + ---------- + xlsx: Union[str, BinaryIO] + Path to the XLSX file or opened file object. -schema: Union[dict, str, TextIO] - Schema for validation of XLSX content. + schema: Union[dict, str, TextIO] + Schema for validation of XLSX content. -strict: bool, optional - If True, fail faster. -""" + strict: bool, optional + If True, fail faster. + """ self._workbook = load_workbook(xlsx) self._schema = read_or_dict(schema) self._defining_path_index = xlsx_utils.get_defining_paths(self._workbook) @@ -91,20 +90,20 @@ strict: bool, optional def to_dict(self, validate: bool = False, collect_errors: bool = True) -> dict: """Convert the xlsx contents to a dict. -Parameters ----------- -validate: bool, optional - If True, validate the result against the schema. + Parameters + ---------- + validate: bool, optional + If True, validate the result against the schema. -collect_errors: bool, optional - If True, do not fail at the first error, but try to collect as many errors as possible. After an - Exception is raised, the errors can be collected with ``get_errors()`` and printed with - ``get_error_str()``. + collect_errors: bool, optional + If True, do not fail at the first error, but try to collect as many errors as possible. After an + Exception is raised, the errors can be collected with ``get_errors()`` and printed with + ``get_error_str()``. -Returns -------- -out: dict - A dict representing the JSON with the extracted data. + Returns + ------- + out: dict + A dict representing the JSON with the extracted data. """ self._handled_sheets = set() self._result = {} @@ -177,17 +176,17 @@ out: dict def _handle_sheet(self, sheet: Worksheet, fail_later: bool = False) -> None: """Add the contents of the sheet to the result (stored in ``self._result``). -Each row in the sheet corresponds to one entry in an array in the result. Which array exactly is -defined by the sheet's "proper name" and the content of the foreign columns. + Each row in the sheet corresponds to one entry in an array in the result. Which array exactly is + defined by the sheet's "proper name" and the content of the foreign columns. -Look at ``xlsx_utils.get_path_position`` for the specification of the "proper name". + Look at ``xlsx_utils.get_path_position`` for the specification of the "proper name". -Parameters ----------- -fail_later: bool, optional - If True, do not fail with unresolvable foreign definitions, but collect all errors. -""" + Parameters + ---------- + fail_later: bool, optional + If True, do not fail with unresolvable foreign definitions, but collect all errors. + """ row_type_column = xlsx_utils.get_row_type_column_index(sheet) foreign_columns = xlsx_utils.get_foreign_key_columns(sheet) foreign_column_paths = {col.index: col.path for col in foreign_columns.values()} @@ -267,9 +266,9 @@ fail_later: bool, optional def _get_parent_dict(self, parent_path: list[str], foreign: list[list]) -> dict: """Return the dict into which values can be inserted. -This method returns, from the current result-in-making, the entry at ``parent_path`` which matches -the values given in the ``foreign`` specification. -""" + This method returns, from the current result-in-making, the entry at ``parent_path`` which matches + the values given in the ``foreign`` specification. + """ foreign_groups = _group_foreign_paths(foreign, common=parent_path) current_object = self._result @@ -296,9 +295,9 @@ the values given in the ``foreign`` specification. def _validate_and_convert(self, value: Any, path: list[str]): """Apply some basic validation and conversion steps. -This includes: -- Validation against the type given in the schema -- List typed values are split at semicolons and validated individually + This includes: + - Validation against the type given in the schema + - List typed values are split at semicolons and validated individually """ if value is None: return value @@ -340,29 +339,29 @@ This includes: def _group_foreign_paths(foreign: list[list], common: list[str]) -> list[SimpleNamespace]: """Group the foreign keys by their base paths. -Parameters ----------- -foreign: list[list] - A list of foreign definitions, consisting of path components, property and possibly value. - -common: list[list[str]] - A common path which defines the final target of the foreign definitions. This helps to understand - where the ``foreign`` paths shall be split. - -Returns -------- -out: list[dict[str, list[list]]] - - A list of foreign path segments, grouped by their common segments. Each element is a namespace - with detailed information of all those elements which form the group. The namespace has the - following attributes: - - - ``path``: The full path to this path segment. This is always the previous segment's ``path`` - plus this segment's ``subpath``. - - ``stringpath``: The stringified ``path``, might be useful for comparison or sorting. - - ``subpath``: The path, relative from the previous segment. - - ``definitions``: A list of the foreign definitions for this segment, but stripped of the - ``path`` components. + Parameters + ---------- + foreign: list[list] + A list of foreign definitions, consisting of path components, property and possibly value. + + common: list[list[str]] + A common path which defines the final target of the foreign definitions. This helps to understand + where the ``foreign`` paths shall be split. + + Returns + ------- + out: list[dict[str, list[list]]] + + A list of foreign path segments, grouped by their common segments. Each element is a namespace + with detailed information of all those elements which form the group. The namespace has the + following attributes: + + - ``path``: The full path to this path segment. This is always the previous segment's ``path`` + plus this segment's ``subpath``. + - ``stringpath``: The stringified ``path``, might be useful for comparison or sorting. + - ``subpath``: The path, relative from the previous segment. + - ``definitions``: A list of the foreign definitions for this segment, but stripped of the + ``path`` components. """ # Build a simple dict first, without subpath. results = {} @@ -405,31 +404,31 @@ def _set_in_nested(mydict: dict, path: list, value: Any, prefix: list = [], skip overwrite: bool = False, append_to_list: bool = False) -> dict: """Set a value in a nested dict. -Parameters ----------- -mydict: dict - The dict into which the ``value`` shall be inserted. -path: list - A list of keys, denoting the location of the value. -value - The value which shall be set inside the dict. -prefix: list - A list of keys which shall be removed from ``path``. A KeyError is raised if ``path`` does not - start with the elements of ``prefix``. -skip: int = 0 - Remove this many additional levels from the path, *after* removing the prefix. -overwrite: bool = False - If True, allow overwriting existing content. Otherwise, attempting to overwrite existing values - leads to an exception. -append_to_list: bool = False - If True, assume that the element at ``path`` is a list and append the value to it. If the list - does not exist, create it. If there is a non-list at ``path`` already, overwrite it with a new - list, if ``overwrite`` is True, otherwise raise a ValueError. - -Returns -------- -mydict: dict - The same dictionary that was given as a parameter, but modified. + Parameters + ---------- + mydict: dict + The dict into which the ``value`` shall be inserted. + path: list + A list of keys, denoting the location of the value. + value + The value which shall be set inside the dict. + prefix: list + A list of keys which shall be removed from ``path``. A KeyError is raised if ``path`` does not + start with the elements of ``prefix``. + skip: int = 0 + Remove this many additional levels from the path, *after* removing the prefix. + overwrite: bool = False + If True, allow overwriting existing content. Otherwise, attempting to overwrite existing values + leads to an exception. + append_to_list: bool = False + If True, assume that the element at ``path`` is a list and append the value to it. If the list + does not exist, create it. If there is a non-list at ``path`` already, overwrite it with a new + list, if ``overwrite`` is True, otherwise raise a ValueError. + + Returns + ------- + mydict: dict + The same dictionary that was given as a parameter, but modified. """ for idx, el in enumerate(prefix): if path[idx] != el: @@ -473,25 +472,25 @@ def to_dict(xlsx: Union[str, BinaryIO], schema: Union[dict, str, TextIO], validate: bool = None, strict: bool = False) -> dict: """Convert the xlsx contents to a dict, it must follow a schema. -Parameters ----------- -xlsx: Union[str, BinaryIO] - Path to the XLSX file or opened file object. + Parameters + ---------- + xlsx: Union[str, BinaryIO] + Path to the XLSX file or opened file object. -schema: Union[dict, str, TextIO] - Schema for validation of XLSX content. + schema: Union[dict, str, TextIO] + Schema for validation of XLSX content. -validate: bool, optional - If True, validate the result against the schema. + validate: bool, optional + If True, validate the result against the schema. -strict: bool, optional - If True, fail faster. + strict: bool, optional + If True, fail faster. -Returns -------- -out: dict - A dict representing the JSON with the extracted data. + Returns + ------- + out: dict + A dict representing the JSON with the extracted data. """ converter = XLSXConverter(xlsx, schema, strict=strict) return converter.to_dict() -- GitLab From 26079795e14165e121690918dfda69147be9652b Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Thu, 7 Nov 2024 14:30:37 +0100 Subject: [PATCH 026/106] STY: Docstring indentation --- .../table_json_conversion/xlsx_utils.py | 158 +++++++++--------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/xlsx_utils.py b/src/caosadvancedtools/table_json_conversion/xlsx_utils.py index 5002f3ac..3cb2de68 100644 --- a/src/caosadvancedtools/table_json_conversion/xlsx_utils.py +++ b/src/caosadvancedtools/table_json_conversion/xlsx_utils.py @@ -68,22 +68,22 @@ class RowType(Enum): def array_schema_from_model_schema(model_schema: dict) -> dict: """Convert a *data model* schema to a *data array* schema. -Practically, this means that the top level properties are converted into lists. In a simplified -notation, this can be expressed as: - -``array_schema = { elem: [elem typed data...] for elem in model_schema }`` - -Parameters ----------- -model_schema: dict - The schema description of the data model. Must be a json schema *object*, with a number of - *object* typed properties. - -Returns -------- -array_schema: dict - A corresponding json schema, where the properties are arrays with the types of the input's - top-level properties. + Practically, this means that the top level properties are converted into lists. In a simplified + notation, this can be expressed as: + + ``array_schema = { elem: [elem typed data...] for elem in model_schema }`` + + Parameters + ---------- + model_schema: dict + The schema description of the data model. Must be a json schema *object*, with a number of + *object* typed properties. + + Returns + ------- + array_schema: dict + A corresponding json schema, where the properties are arrays with the types of the input's + top-level properties. """ assert model_schema["type"] == "object" result = deepcopy(model_schema) @@ -100,30 +100,30 @@ array_schema: dict def get_defining_paths(workbook: Workbook) -> dict[str, list[list[str]]]: """For all sheets in ``workbook``, list the paths which they define. -A sheet is said to define a path, if it has data columns for properties inside that path. For -example, consider the following worksheet: - -| `COL_TYPE` | `SCALAR` | `SCALAR` | `LIST` | `SCALAR` | -| `PATH` | `Training` | `Training` | `Training` | `Training` | -| `PATH` | `url` | `date` | `subjects` | `supervisor` | -| `PATH` | | | | `email` | -|------------|----------------|---------------|--------------|--------------------| -| | example.com/mp | 2024-02-27 | Math;Physics | steve@example.com | -| | example.com/m | 2024-02-27 | Math | stella@example.com | - -This worksheet defines properties for the paths `["Training"]` and `["Training", "supervisor"]`, and -thus these two path lists would be returned for the key with this sheet's sheetname. - -Parameters ----------- -workbook: Workbook - The workbook to analyze. - -Returns -------- -out: dict[str, list[list[str]] - A dict with worksheet names as keys and lists of paths (represented as string lists) as values. -""" + A sheet is said to define a path, if it has data columns for properties inside that path. For + example, consider the following worksheet: + + | `COL_TYPE` | `SCALAR` | `SCALAR` | `LIST` | `SCALAR` | + | `PATH` | `Training` | `Training` | `Training` | `Training` | + | `PATH` | `url` | `date` | `subjects` | `supervisor` | + | `PATH` | | | | `email` | + |------------|----------------|---------------|--------------|--------------------| + | | example.com/mp | 2024-02-27 | Math;Physics | steve@example.com | + | | example.com/m | 2024-02-27 | Math | stella@example.com | + + This worksheet defines properties for the paths `["Training"]` and `["Training", "supervisor"]`, and + thus these two path lists would be returned for the key with this sheet's sheetname. + + Parameters + ---------- + workbook: Workbook + The workbook to analyze. + + Returns + ------- + out: dict[str, list[list[str]] + A dict with worksheet names as keys and lists of paths (represented as string lists) as values. + """ result: dict[str, list[list[str]]] = {} for sheet in workbook.worksheets: paths = [] @@ -140,11 +140,11 @@ out: dict[str, list[list[str]] def get_data_columns(sheet: Worksheet) -> dict[str, SimpleNamespace]: """Return the data paths of the worksheet. -Returns -------- -out: dict[str, SimpleNamespace] - The keys are the stringified paths. The values are SimpleNamespace objects with ``index``, - ``path`` and ``column`` attributes. + Returns + ------- + out: dict[str, SimpleNamespace] + The keys are the stringified paths. The values are SimpleNamespace objects with ``index``, + ``path`` and ``column`` attributes. """ column_types = _get_column_types(sheet) path_rows = get_path_rows(sheet) @@ -171,11 +171,11 @@ out: dict[str, SimpleNamespace] def get_foreign_key_columns(sheet: Worksheet) -> dict[str, SimpleNamespace]: """Return the foreign keys of the worksheet. -Returns -------- -out: dict[str, SimpleNamespace] - The keys are the stringified paths. The values are SimpleNamespace objects with ``index``, - ``path`` and ``column`` attributes. + Returns + ------- + out: dict[str, SimpleNamespace] + The keys are the stringified paths. The values are SimpleNamespace objects with ``index``, + ``path`` and ``column`` attributes. """ column_types = _get_column_types(sheet) path_rows = get_path_rows(sheet) @@ -198,20 +198,20 @@ out: dict[str, SimpleNamespace] def get_path_position(sheet: Worksheet) -> tuple[list[str], str]: """Return a path which represents the parent element, and the sheet's "proper name". -For top-level sheets / entries (those without foreign columns), the path is an empty list. + For top-level sheets / entries (those without foreign columns), the path is an empty list. -A sheet's "proper name" is detected from the data column paths: it is the first component after the -parent components. + A sheet's "proper name" is detected from the data column paths: it is the first component after the + parent components. -Returns -------- -parent: list[str] - Path to the parent element. Note that there may be list elements on the path which are **not** - represented in this return value. + Returns + ------- + parent: list[str] + Path to the parent element. Note that there may be list elements on the path which are **not** + represented in this return value. -proper_name: str - The "proper name" of this sheet. This defines an array where all the data lives, relative to the - parent path. + proper_name: str + The "proper name" of this sheet. This defines an array where all the data lives, relative to the + parent path. """ # Parent element: longest common path shared among any foreign column and all the data columns parent: list[str] = [] @@ -285,7 +285,7 @@ def is_exploded_sheet(sheet: Worksheet) -> bool: """Return True if this is a an "exploded" sheet. An exploded sheet is a sheet whose data entries are LIST valued properties of entries in another - sheet. A sheet is detected as exploded iff it has FOREIGN columns. + sheet. A sheet is detected as exploded if it has FOREIGN columns. """ column_types = _get_column_types(sheet) return ColumnType.FOREIGN.name in column_types.values() @@ -308,22 +308,22 @@ def p2s(path: list[str]) -> str: def parse_multiple_choice(value: Any) -> bool: """Interpret ``value`` as a multiple choice input. -*Truthy* values are: -- The boolean ``True``. -- The number "1". -- The (case-insensitive) strings ``true``, ``wahr``, ``x``, ``√``, ``yes``, ``ja``, ``y``, ``j``. - -*Falsy* values are: -- The boolean ``False``. -- ``None``, empty strings, lists, dicts. -- The number "0". -- The (case-insensitive) strings ``false``, ``falsch``, ``-``, ``no``, ``nein``, ``n``. -- Everything else. - -Returns -------- -out: bool - The interpretation result of ``value``. + *Truthy* values are: + - The boolean ``True``. + - The number "1". + - The (case-insensitive) strings ``true``, ``wahr``, ``x``, ``√``, ``yes``, ``ja``, ``y``, ``j``. + + *Falsy* values are: + - The boolean ``False``. + - ``None``, empty strings, lists, dicts. + - The number "0". + - The (case-insensitive) strings ``false``, ``falsch``, ``-``, ``no``, ``nein``, ``n``. + - Everything else. + + Returns + ------- + out: bool + The interpretation result of ``value``. """ # Non-string cases first: # pylint: disable-next=too-many-boolean-expressions @@ -349,7 +349,7 @@ out: bool def read_or_dict(data: Union[dict, str, TextIO]) -> dict: """If data is a json file name or input stream, read data from there. -If it is a dict already, just return it.""" + If it is a dict already, just return it.""" if isinstance(data, dict): return data -- GitLab From 5ceee474254b96a769ce908d307e9bc9efd9a2ae Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 12 Nov 2024 09:42:52 +0100 Subject: [PATCH 027/106] ENH: convert.to_dict() now outputs encountered type errors in a table --- .../table_json_conversion/convert.py | 182 ++++++++++++++---- .../data/simple_data_broken.xlsx | Bin 0 -> 8982 bytes .../table_json_conversion/test_read_xlsx.py | 21 ++ 3 files changed, 170 insertions(+), 33 deletions(-) create mode 100644 unittests/table_json_conversion/data/simple_data_broken.xlsx diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 48a0f676..e874c535 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -46,6 +46,114 @@ def _strict_bool(value: Any) -> bool: raise TypeError(f"Not a good boolean: {repr(value)}") +def format_exception_table(exceptions: list(tuple), worksheet_title: str, + column_names: Optional[dict, list] = None, + max_line_length: Optional[int] = 120) -> str: + """ + Given a list of tuples containing a row and column number as well as an + exception in that order, and the title of the current worksheet, returns + a formatted table of the exceptions. + + Optionally takes a dict of column names, if given a header will be + generated for each column and exceptions will be clustered by column. + + Default line length is 120 and can be overwritten by max_line_length. + + Params + ------ + exceptions: list of tuples containing row, column, and exception + Data to be formatted + worksheet_title: str + Name of the current worksheet + column_names: dict or list, optional + column_names[column_num] should return the name of + column column_names. + If given, exceptions will be clustered by column. + max_line_length: int + Soft cap for the line length of the resulting table + + Return + ------ + string_rep: str + Table containing the given exceptions + """ + def to_char(num): + if num < 0: + return "" + return to_char(int(num / 26) - 1) + chr(int(num % 26) + 65) + max_line_length -= 40 # Estimate of Field + Type space use + + headers = {"loc": "Field", "type": "Error Type", "mess": ["Message"]} + lengths = {key: len(headers[key]) for key in headers} + new_data = [] + + current_column = None + exceptions.sort(key=lambda tup: tup[1]) + for row_i, col_i, excep in exceptions: + if column_names is not None: + # Update Names + if current_column != col_i: + current_column = col_i + new_data.append({ + "loc": f"\nErrors in column '{column_names[col_i]}':", + "type": "", "mess": [""] + }) + # Setup + row = {} + new_data.append(row) + # Field + if isinstance(row_i, int): + row["loc"] = f"{to_char(col_i)}{row_i + 1}" + else: + row["loc"] = f"{to_char(col_i)}" + lengths["loc"] = max(lengths["loc"], len(row["loc"])) + # Code + row["type"] = type(excep).__name__ + lengths["type"] = max(lengths["type"], len(row["type"])) + # Message + lines = str(excep).split('\n') + new_lines = [] + for line in lines: + if len(line) > max_line_length: + words = line.split(' ') + current = "" + for word, next_word in zip(words, words[1:] + [""]): + if current != "": + current += " " + current += word + if len(current + next_word) > max_line_length: + lengths["mess"] = max(lengths["mess"], len(current)) + new_lines.append(current) + current = "" + if current != "": + lengths["mess"] = max(lengths["mess"], len(current)) + new_lines.append(current) + elif len(line) > 0: + lengths["mess"] = max(lengths["mess"], len(line)) + new_lines.append(line) + if new_lines == []: + new_lines = [""] + row["mess"] = new_lines + + dividers = {key: '–' * l for key, l in lengths.items()} + dividers["mess"] = [dividers["mess"]] + + # Fill for the messages is set to 0, if we want another column or align + # right we need to use lengths["mess"] + string_rep = f"There were failures during validation of worksheet '{worksheet_title}':\n\n" + for row in [headers, dividers] + new_data: + string_rep += ' {loc: <{fill}} '.format(loc=row["loc"], + fill=lengths["loc"]) + string_rep += ' {typ: <{fill}} '.format(typ=row["type"], + fill=lengths["type"]) + string_rep += ' {mes: <{fill}}\n'.format(mes=row["mess"][0], fill=0) + for line in row["mess"][1:]: + # Front padding + string_rep += ' ' * (lengths["loc"] + lengths["type"] + 7) + string_rep += ' {mes: <{fill}}\n'.format(mes=line, fill=0) + return string_rep + + class ForeignError(KeyError): def __init__(self, *args, definitions: list, message: str = ""): super().__init__(message, *args) @@ -205,9 +313,13 @@ class XLSXConverter: # # - data: The actual data of this entry, a dict. # entries: dict[str, list[SimpleNamespace]] = {} + exceptions = [] + col_names = None for row_idx, row in enumerate(sheet.iter_rows(values_only=True)): - # Skip non-data rows. + # Skip non-data rows and save the row containing column names if row[row_type_column] is not None: + if row[row_type_column] == "IGNORE" and col_names is None: + col_names = row continue foreign_repr = "" foreign = [] # A list of lists, each of which is: [path1, path2, ..., leaf, value] @@ -219,24 +331,27 @@ class XLSXConverter: foreign.append(foreign_column_paths[col_idx] + [value]) continue - if col_idx in data_column_paths: - path = data_column_paths[col_idx] - if self._is_multiple_choice(path): - real_value = path.pop() # Last component is the enum value, insert above - # set up list - try: - _set_in_nested(mydict=data, path=path, value=[], prefix=parent, skip=1) - except ValueError as err: - if not str(err).startswith("There is already some value at"): - raise - if not xlsx_utils.parse_multiple_choice(value): - continue - _set_in_nested(mydict=data, path=path, value=real_value, prefix=parent, - skip=1, append_to_list=True) - else: - value = self._validate_and_convert(value, path) - _set_in_nested(mydict=data, path=path, value=value, prefix=parent, skip=1) - continue + try: + if col_idx in data_column_paths: + path = data_column_paths[col_idx] + if self._is_multiple_choice(path): + real_value = path.pop() # Last component is the enum value, insert above + # set up list + try: + _set_in_nested(mydict=data, path=path, value=[], prefix=parent, skip=1) + except ValueError as err: + if not str(err).startswith("There is already some value at"): + raise + if not xlsx_utils.parse_multiple_choice(value): + continue + _set_in_nested(mydict=data, path=path, value=real_value, prefix=parent, + skip=1, append_to_list=True) + else: + value = self._validate_and_convert(value, path) + _set_in_nested(mydict=data, path=path, value=value, prefix=parent, skip=1) + continue + except (ValueError, jsonschema.ValidationError) as e: + exceptions.append((row_idx, col_idx, e)) try: # Find current position in tree @@ -250,6 +365,12 @@ class XLSXConverter: if not fail_later: raise self._errors[(sheet.title, row_idx)] = kerr.definitions + + if exceptions != []: + exception_table = format_exception_table(exceptions, sheet.title, + col_names) + raise jsonschema.ValidationError(exception_table) + self._handled_sheets.add(sheet.title) def _is_multiple_choice(self, path: list[str]) -> bool: @@ -308,20 +429,15 @@ class XLSXConverter: if isinstance(value, str) and ";" in value: values = [self.PARSER[array_type](v) for v in value.split(";")] return values - try: - # special case: datetime or date - if ("anyOf" in subschema): - if isinstance(value, datetime.datetime) and ( - {'type': 'string', 'format': 'date-time'} in subschema["anyOf"]): - return value - if isinstance(value, datetime.date) and ( - {'type': 'string', 'format': 'date'} in subschema["anyOf"]): - return value - jsonschema.validate(value, subschema) - except jsonschema.ValidationError as verr: - print(verr) - print(path) - raise + # special case: datetime or date + if ("anyOf" in subschema): + if isinstance(value, datetime.datetime) and ( + {'type': 'string', 'format': 'date-time'} in subschema["anyOf"]): + return value + if isinstance(value, datetime.date) and ( + {'type': 'string', 'format': 'date'} in subschema["anyOf"]): + return value + jsonschema.validate(value, subschema) # Finally: convert to target type return self.PARSER[subschema.get("type", "string")](value) diff --git a/unittests/table_json_conversion/data/simple_data_broken.xlsx b/unittests/table_json_conversion/data/simple_data_broken.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..361953f660f12cb37d979ff3b4c49895265131e3 GIT binary patch literal 8982 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 literal 0 HcmV?d00001 diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index 0eec2e9c..6ee744ef 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -27,6 +27,7 @@ import re from types import SimpleNamespace +import jsonschema import pytest from caosadvancedtools.table_json_conversion import convert @@ -112,6 +113,26 @@ def test_missing_columns(): assert expected in messages +def test_wrong_datatype(): + with pytest.raises(jsonschema.ValidationError) as caught: + convert.to_dict(xlsx=rfp("data/simple_data_broken.xlsx"), + schema=rfp("data/simple_schema.json")) + # Correct Errors + assert "'Not a num' is not of type 'number'" in str(caught.value) + assert "1.5 is not of type 'integer'" in str(caught.value) + # Correct Locations + for line in str(caught.value).split('\n'): + if "'Not a num' is not of type 'number'" in line: + assert "J7" in line + if "1.5 is not of type 'integer'" in line: + assert "K7" in line + # No additional type errors + if "is not of type 'boolean'" in str(caught.value): # ToDo: Remove when boolean is fixed + assert str(caught.value).count("is not of type") == 3 + else: + assert str(caught.value).count("is not of type") == 2 + + def test_faulty_foreign(): # Simple wrong foreign key converter = convert.XLSXConverter(xlsx=rfp("data/simple_data_wrong_foreign.xlsx"), -- GitLab From 3b55e553fbde2c2ec36c54ef038ee174d8a3494d Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 12 Nov 2024 10:48:49 +0100 Subject: [PATCH 028/106] ENH: Added error message to convert.to_dict() when trying to parse a column not in the schema --- .../table_json_conversion/convert.py | 30 ++++++++++++------- .../table_json_conversion/test_read_xlsx.py | 14 +++++++++ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index e874c535..84e3b954 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -83,7 +83,7 @@ def format_exception_table(exceptions: list(tuple), worksheet_title: str, return to_char(int(num / 26) - 1) + chr(int(num % 26) + 65) max_line_length -= 40 # Estimate of Field + Type space use - headers = {"loc": "Field", "type": "Error Type", "mess": ["Message"]} + headers = {"loc": "Location", "type": "Error Type", "mess": ["Message"]} lengths = {key: len(headers[key]) for key in headers} new_data = [] @@ -103,9 +103,9 @@ def format_exception_table(exceptions: list(tuple), worksheet_title: str, new_data.append(row) # Field if isinstance(row_i, int): - row["loc"] = f"{to_char(col_i)}{row_i + 1}" + row["loc"] = f"Cell {to_char(col_i)}{row_i + 1}" else: - row["loc"] = f"{to_char(col_i)}" + row["loc"] = f"Column {to_char(col_i)}" lengths["loc"] = max(lengths["loc"], len(row["loc"])) # Code row["type"] = type(excep).__name__ @@ -140,7 +140,7 @@ def format_exception_table(exceptions: list(tuple), worksheet_title: str, # Fill for the messages is set to 0, if we want another column or align # right we need to use lengths["mess"] - string_rep = f"There were failures during validation of worksheet '{worksheet_title}':\n\n" + string_rep = f"There were errors during the validation of worksheet '{worksheet_title}':\n\n" for row in [headers, dividers] + new_data: string_rep += ' {loc: <{fill}} '.format(loc=row["loc"], fill=lengths["loc"]) @@ -314,12 +314,10 @@ class XLSXConverter: # entries: dict[str, list[SimpleNamespace]] = {} exceptions = [] - col_names = None + col_names = {} for row_idx, row in enumerate(sheet.iter_rows(values_only=True)): - # Skip non-data rows and save the row containing column names + # Skip non-data rows if row[row_type_column] is not None: - if row[row_type_column] == "IGNORE" and col_names is None: - col_names = row continue foreign_repr = "" foreign = [] # A list of lists, each of which is: [path1, path2, ..., leaf, value] @@ -334,6 +332,7 @@ class XLSXConverter: try: if col_idx in data_column_paths: path = data_column_paths[col_idx] + col_names[col_idx] = '.'.join(path) if self._is_multiple_choice(path): real_value = path.pop() # Last component is the enum value, insert above # set up list @@ -350,8 +349,14 @@ class XLSXConverter: value = self._validate_and_convert(value, path) _set_in_nested(mydict=data, path=path, value=value, prefix=parent, skip=1) continue - except (ValueError, jsonschema.ValidationError) as e: - exceptions.append((row_idx, col_idx, e)) + except (ValueError, KeyError, jsonschema.ValidationError) as e: + # Append error for entire column only once + if isinstance(e, KeyError) and 'column' in str(e): + if len([err for ri, ci, err in exceptions + if ci == col_idx and isinstance(err, KeyError)]) == 0: + exceptions.append((None, col_idx, e)) + else: + exceptions.append((row_idx, col_idx, e)) try: # Find current position in tree @@ -422,7 +427,10 @@ class XLSXConverter: """ if value is None: return value - subschema = self._get_subschema(path) + try: + subschema = self._get_subschema(path) + except KeyError as e: + raise KeyError("There is no entry in the schema that corresponds to this column.") # Array handling only if schema says it's an array. if subschema.get("type") == "array": array_type = subschema["items"]["type"] diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index 6ee744ef..897cd10b 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -133,6 +133,20 @@ def test_wrong_datatype(): assert str(caught.value).count("is not of type") == 2 +def test_additional_column(): + with pytest.raises(jsonschema.ValidationError) as caught: + convert.to_dict(xlsx=rfp("data/simple_data_broken.xlsx"), + schema=rfp("data/simple_schema.json")) + # Correct Error + assert "no entry in the schema that corresponds to this column" in str(caught.value) + # Correct Location + for line in str(caught.value).split('\n'): + if "no entry in the schema that corresponds to this column" in line: + assert " M " in line + # No additional column errors + assert str(caught.value).count("no entry in the schema that corresponds to this column") == 1 + + def test_faulty_foreign(): # Simple wrong foreign key converter = convert.XLSXConverter(xlsx=rfp("data/simple_data_wrong_foreign.xlsx"), -- GitLab From 7d4e51cdd74552cb54c0ca557dc0aea599d1401b Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 12 Nov 2024 11:34:53 +0100 Subject: [PATCH 029/106] STY: Style fixes --- src/caosadvancedtools/table_json_conversion/convert.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 84e3b954..1f87bc7f 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -28,7 +28,7 @@ import sys from functools import reduce from operator import getitem from types import SimpleNamespace -from typing import Any, BinaryIO, Callable, TextIO, Union +from typing import Any, BinaryIO, Callable, TextIO, Union, Optional from warnings import warn import jsonschema @@ -430,7 +430,7 @@ class XLSXConverter: try: subschema = self._get_subschema(path) except KeyError as e: - raise KeyError("There is no entry in the schema that corresponds to this column.") + raise KeyError("There is no entry in the schema that corresponds to this column.") from e # Array handling only if schema says it's an array. if subschema.get("type") == "array": array_type = subschema["items"]["type"] -- GitLab From 865aa2655b542b8333916f1611269c6e044d98d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com> Date: Tue, 12 Nov 2024 12:11:23 +0100 Subject: [PATCH 030/106] FIX: correct argument names --- src/caosadvancedtools/models/data_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index bda8cad6..3be56002 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -147,8 +147,8 @@ class DataModel(dict): ref = query.execute(unique=True) diff = (describe_diff(*compare_entities(ent, ref), name=ent.name, - label_old="version from the yaml file", - label_new="version from LinkAhead")) + label_e0="version from the yaml file", + label_e1="version from LinkAhead")) if diff != "": if verbose: -- GitLab From a6910d390a22d418307f0cfef9a798ab6e05544e Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 12 Nov 2024 12:59:17 +0100 Subject: [PATCH 031/106] MNT: Added a warning when column metadata is not configured, and a better error message when a column has a type but no path. --- .../table_json_conversion/convert.py | 35 ++++++++++++------- .../table_json_conversion/xlsx_utils.py | 10 ++++++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 1f87bc7f..f650fdd9 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -45,10 +45,16 @@ def _strict_bool(value: Any) -> bool: return value raise TypeError(f"Not a good boolean: {repr(value)}") - -def format_exception_table(exceptions: list(tuple), worksheet_title: str, - column_names: Optional[dict, list] = None, - max_line_length: Optional[int] = 120) -> str: +def _column_id_to_chars(num): + """Converts a column id (zero based) to the corresponding string + representation, e.g. 0 -> 'A', 97 -> 'CT'""" + if num < 0: + return "" + return _column_id_to_chars(int(num / 26) - 1) + chr(int(num % 26) + 65) + +def _format_exception_table(exceptions: list(tuple), worksheet_title: str, + column_names: Optional[dict, list] = None, + max_line_length: Optional[int] = 120) -> str: """ Given a list of tuples containing a row and column number as well as an exception in that order, and the title of the current worksheet, returns @@ -77,10 +83,6 @@ def format_exception_table(exceptions: list(tuple), worksheet_title: str, string_rep: str Table containing the given exceptions """ - def to_char(num): - if num < 0: - return "" - return to_char(int(num / 26) - 1) + chr(int(num % 26) + 65) max_line_length -= 40 # Estimate of Field + Type space use headers = {"loc": "Location", "type": "Error Type", "mess": ["Message"]} @@ -103,9 +105,9 @@ def format_exception_table(exceptions: list(tuple), worksheet_title: str, new_data.append(row) # Field if isinstance(row_i, int): - row["loc"] = f"Cell {to_char(col_i)}{row_i + 1}" + row["loc"] = f"Cell {_column_id_to_chars(col_i)}{row_i + 1}" else: - row["loc"] = f"Column {to_char(col_i)}" + row["loc"] = f"Column {_column_id_to_chars(col_i)}" lengths["loc"] = max(lengths["loc"], len(row["loc"])) # Code row["type"] = type(excep).__name__ @@ -296,12 +298,17 @@ class XLSXConverter: If True, do not fail with unresolvable foreign definitions, but collect all errors. """ row_type_column = xlsx_utils.get_row_type_column_index(sheet) + col_type_row = xlsx_utils.get_column_type_row_index(sheet) foreign_columns = xlsx_utils.get_foreign_key_columns(sheet) foreign_column_paths = {col.index: col.path for col in foreign_columns.values()} data_columns = xlsx_utils.get_data_columns(sheet) data_column_paths = {col.index: col.path for col in data_columns.values()} # Parent path, insert in correct order. - parent, proper_name = xlsx_utils.get_path_position(sheet) + try: + parent, proper_name = xlsx_utils.get_path_position(sheet) + except UnboundLocalError as e: + raise jsonschema.ValidationError(f"Malformed metadata: Cannot parse " + f"paths in worksheet '{sheet.title}'.") from e if parent: parent_sheetname = xlsx_utils.get_worksheet_for_path(parent, self._defining_path_index) if parent_sheetname not in self._handled_sheets: @@ -349,6 +356,8 @@ class XLSXConverter: value = self._validate_and_convert(value, path) _set_in_nested(mydict=data, path=path, value=value, prefix=parent, skip=1) continue + elif sheet.cell(col_type_row+1, col_idx+1).value is None: + warn(f"No metadata configured for column {_column_id_to_chars(col_idx)}.") except (ValueError, KeyError, jsonschema.ValidationError) as e: # Append error for entire column only once if isinstance(e, KeyError) and 'column' in str(e): @@ -372,8 +381,8 @@ class XLSXConverter: self._errors[(sheet.title, row_idx)] = kerr.definitions if exceptions != []: - exception_table = format_exception_table(exceptions, sheet.title, - col_names) + exception_table = _format_exception_table(exceptions, sheet.title, + col_names) raise jsonschema.ValidationError(exception_table) self._handled_sheets.add(sheet.title) diff --git a/src/caosadvancedtools/table_json_conversion/xlsx_utils.py b/src/caosadvancedtools/table_json_conversion/xlsx_utils.py index 3cb2de68..7efe15c8 100644 --- a/src/caosadvancedtools/table_json_conversion/xlsx_utils.py +++ b/src/caosadvancedtools/table_json_conversion/xlsx_utils.py @@ -258,6 +258,16 @@ def get_row_type_column_index(sheet: Worksheet): raise ValueError("The column which defines row types (COL_TYPE, PATH, ...) is missing") +def get_column_type_row_index(sheet: Worksheet): + """Return the row index (0-indexed) of the row which defines the column types. + """ + for row in sheet.rows: + for cell in row: + if cell.value == RowType.COL_TYPE.name: + return cell.row - 1 + raise ValueError("The column which defines row types (COL_TYPE, SCALAR, ...) is missing") + + def get_subschema(path: list[str], schema: dict) -> dict: """Return the sub schema at ``path``.""" if path: -- GitLab From 0519fc38facce016711a09dc9d8e98732b909b21 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 12 Nov 2024 13:09:53 +0100 Subject: [PATCH 032/106] STY: style fix --- src/caosadvancedtools/table_json_conversion/convert.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index f650fdd9..a8df7ec2 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -45,6 +45,7 @@ def _strict_bool(value: Any) -> bool: return value raise TypeError(f"Not a good boolean: {repr(value)}") + def _column_id_to_chars(num): """Converts a column id (zero based) to the corresponding string representation, e.g. 0 -> 'A', 97 -> 'CT'""" @@ -52,6 +53,7 @@ def _column_id_to_chars(num): return "" return _column_id_to_chars(int(num / 26) - 1) + chr(int(num % 26) + 65) + def _format_exception_table(exceptions: list(tuple), worksheet_title: str, column_names: Optional[dict, list] = None, max_line_length: Optional[int] = 120) -> str: -- GitLab From 22dac5d167ec702890e3d6d0675a400e3cf9657e Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Thu, 14 Nov 2024 12:47:14 +0100 Subject: [PATCH 033/106] WIP: XLSX converter errors. --- .../table_json_conversion/convert.py | 10 +++++----- .../data/simple_data_broken.xlsx | Bin 8982 -> 9175 bytes .../table_json_conversion/test_read_xlsx.py | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index a8df7ec2..37c39aae 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -54,9 +54,9 @@ def _column_id_to_chars(num): return _column_id_to_chars(int(num / 26) - 1) + chr(int(num % 26) + 65) -def _format_exception_table(exceptions: list(tuple), worksheet_title: str, - column_names: Optional[dict, list] = None, - max_line_length: Optional[int] = 120) -> str: +def _format_exception_table(exceptions: list[tuple], worksheet_title: str, + column_names: Optional[Union[dict, list]] = None, + max_line_length: int = 120) -> str: """ Given a list of tuples containing a row and column number as well as an exception in that order, and the title of the current worksheet, returns @@ -77,7 +77,7 @@ def _format_exception_table(exceptions: list(tuple), worksheet_title: str, column_names[column_num] should return the name of column column_names. If given, exceptions will be clustered by column. - max_line_length: int + max_line_length: int, default=120 Soft cap for the line length of the resulting table Return @@ -382,7 +382,7 @@ class XLSXConverter: raise self._errors[(sheet.title, row_idx)] = kerr.definitions - if exceptions != []: + if exceptions: exception_table = _format_exception_table(exceptions, sheet.title, col_names) raise jsonschema.ValidationError(exception_table) diff --git a/unittests/table_json_conversion/data/simple_data_broken.xlsx b/unittests/table_json_conversion/data/simple_data_broken.xlsx index 361953f660f12cb37d979ff3b4c49895265131e3..0221570c942fc28f2b59a282f751781ff4a504fa 100644 GIT binary patch delta 6743 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 delta 6534 zcmZ8m2Q*w;+ZKe8=p}j?3<eR57D4oG)F?sp7JZcHqlM9fL3D{u^xjJ_O0)>0M(;!j z21)qceD_=bz283Tth4t%&)NH|cklOE@B3`DQmP`6mKqK&B^Cexz)I3^sv%;(gLC_= z6S|{|{Z}P98iyM`yKs+yfXFe4yKq?CA*1Z8vGeD8e0)L~VG#&4^AtUfj}y|@xnEm; zu6SQNJTSh?Ly9@q3ITz)JSzE-h~VCK3Q-)F*dTrIgWYZpyQ9nOhF=Z}5>VscjOCpO z(c9TPY4Zh<AQznp660&T%kIvr8eQ+SK5GZvt;{)2;x8mtY2m8YGfixH1_nU6v65wQ zY2d6%%Rx}eCi74RXTG(l_a_t<^5)Sd>npo%-!bsR=78gcz0oI2eimdO47wH-Ts`S| z+lU%AB{mNR-J<KwA6H2|VHSAC)R6(;Lwu`}uWTu79^93=k77YI8R~Jn(CI&!EaKze zF@*#yhM`3fFsK8y4YNZJ?1d#b%G`0<9iDOi`<>qYu%7-)$XPR-CYvCDCa&0wxI}D} z!aPwS3$}`Is*~QodVbg3)}s>fem-d2cDtgp)X1e-S#PxA2g5u44fe-lVjoWfTcp87 zR5IB+!Z&@-S7A^U?iBh&JL6`x7ufWCphtT7{a9qqEsk6mfp@3G_bxD}h8{VBt#Hlp z`|;C^4Ue!eMWqjg8BJ18tGCSMqZu7=tM-66lhIqWJcC2sO`&S!BYrof{UeWE@WqY! zPR56Y3e;x4JaIA*Opqzqj$u$aKVeKWG}g|NA~5;NV?o`Q1!}M=EN^7BWBzt2e)NS~ z-A3u-JBe%Qq|^-&P0D)F&r8Lei6`)QcREwL;)rdBysNdKf_b54Cc$-j+WYA-j{AyR z|GmfsDQ>`$V9tEbe%q6R+1On2%<uHc?mw%Ju53CnOw1-%bX}U`>6pu3N_*&Y=uJwm z?IrLO9y`CDGW1Nz85T32rs(WfKA}`Tah$(3e}+HmoKxO0RoerBHztd_4Yx>l^;$p< z`<?4XN<XE4YuOG)P~UYyB^2QVyWSOp`@p^P%(3pp=4F$H_eT={2nbG>2&cWsAaWbm zXl|14dr2g&EEc?@i?-sYVuC`a8B<*}lS+1@ogiYmXM6W2is=H=g+*ewd(a>5WRE7q zg%IJu>TGSZ6Sha;ALu61E9UqiJa`+n8XG;REmSPQv`vl!%~cTTENj{L&^V2JWAojR z?YR$g&3AgY@Fjk?87>$s<N!&wL!333he;RI57X^4OC@LW1W<<;Xw>D)g<tmBa|sV$ z)sGc~WC>aYFzZhbjOzDzYtYOKy@}akAi{?1^9LvR20A^HTl;BYKZ7;!sT<==SEAT9 zFn}dCD-`rQ3#NJQ+O&jTTF>np>AIt(h7TaCW|f@8!NPK2!ovEOuP4XhbHfcxJ?6zI z1DDNKkL7Y3X#mVBFL$hgbKV?8=}9hjR~)>wj;v~x>~e!u%RECO14Y28F?NzWri{z} z-&z{I08ga~KP`}!maI^8p?9yCRuj9CRh-vNk(rq7&SIf88iAgnzGbpac-A$Q%j*C= z0^ocYu8GDk`TYYyfFAM<CA>6#5D=MdI7sPWIP8@ts6yIEUC6uhsx6;I0r`{fV_|>> zF&RpT)q`vkygCm`3<naOK9hw!v-R(-8jb|b%a((3>H1q1N>9%4DgwZ91zM~#*~$fX z8@$t~d-`Q^9Zu;i!AS|e=S<{w6N}M;Wv^26pAtEr`0w^39ay^na6*qLGF{wr!Fmq0 z_gyyLW=|3R0OUfC5MgvoF|df`9c>$@io|i1UmBV%tUCCHYp!hml_tp2ALkb=LN9#` z?<R$ESqI8eX7d8KEBa8qT9XBL(daCW8JCg=C#jOc+(*sQwD6041ADA|#!8rAj0vQq zcCnDBr;PAzAD7)c+%4EoHuacDE9YWyXNaYEP(6;;;?wD_e_~Hi1a^MNk>veEKDIvT z!WT`(#>;afncDf=59gy6_jC?2iY-8W`2^|hrV!9V#H6U)))3h6f+=(-g3?LxtfB3T z?$afC#h)SReP>6TPA&%zaq9SxSX7<5A1GF)_hZLUA640C;6t32xRDh>_&IxaGzzrf z@CVQh<60o$_f&OByg5_X9+_hYKq&XmW#tjAqL))KutJ6B)v$FHu7U8ha=*LAf(n|_ z<Wk_KT-BokPwDNlrq$W#^?Pmj4;+Mu3TOR3Tbi1pYFO)BZ{CFAq``iL8kCFL&rw2} zkhQ|A&+kr-!t3er=;f-Ue@!W#5|h;>BQ90?&eRZC$kL77u2PBL4=RG>azxfX0LNAO zezC7zf%-xu>|D9W=Tv;>5i+;0EN9;o$I%FHIIs<%Hfh_R=Y$z_AMHWxkHuYgrWA$F z9N03h>d7<$=MiQ*kO1Sr2+rFsKDv$+MBe1^&N%$}V_0ST?1+=K@9Dm4^+3625boyy z5~h$-`uuw@?G!n{=$KD_%8%|$VRyQ^!e;!#recF9%i@KAyLBscHMBIktd96B&5j!R z=ZY(f^VIBU%6kyUu-5Dv$%aCTYLigk>TdzF%m#3lYgK!#pR-WQ4z!dEZ+K-z*f4mD z_5z+9I|vGlfSh9^%YA|SENXJvygbya{v7?X^Wuh1mvXWf*sZTa)b5QwH;_7p02|~f zv&N&}?Hot19}!HafX}+a(1hl=QuZ7=R!1o{Zdq?zbsVhPznyq0EFS0Zz@`XAl?2AQ z+COQqZ4#a*DqACwn0DR$ftMQ=bSQq#O1Sg2<fveK_k~|w*Jkm%?pdRy-6u#}X4~_d zw%nEpW~Odyo+DzyQ-eg-Ys}|sWYX;6bMvaBx$$!TSx&*njM>Yh4xa8&N6u@k#x!62 zU)!9?xm-Q{i+1?AUIs&Pv9Jh<|A%&ru>Mh!Gw`Y5f_y&CP95paw@gHeT3#;xexb1K zvK3w9%U>_e`I<CIb_%@fwe=O;$RJen(BQ$u#?&j&Q*-OWu`|^Z?CR4W*RKqC`g!wT zE$2_nTBMTGC1|uwix4sRf8jh{n*9ZXz$N+PkomJpz_{btfbP;umlKq|=3HQF&s%zP z7AOk774c&u&Zh7yo)VYyBrb}dLhAvLIPG9el_DbXk!!T<h(ps){cvR`+Xr8(w`cQY zq$MQszl!t<jK}gbuo8bOrcWw(-EeeWcW_B~2>jBU8y!>UR8(*G%JH0aO(5fQaFYbx zX61A~!}E{%Vr)l`;}sA~uE}U~v5*xP73GUC_~~R;Y{9YSCxG&xfU!373`p7{+JaB! zl~3Gdn*7)g`YQswXa`5Z+LKI9wp{6Z{k8Oj_*OqY1=Z03WU+5Z+ckM|<2>as9^YN* z-`DeV;y<D}PGcY7AD$Co{-uu5rQ>5E(=wWlf(uxGpfTTY!C~Ta?^a7@SgLeKNXGx( zg9oCGnL-DzfUSiV4&A6b^ARS^STH2j`jhWIP6Mpjz_$faZ{Du)Q(9z1aL%e#FCS$L zuoX_u%K_PkT$*^$%$tXMCCc06k`oo`YEnERA0HNCER|=SV-%9K5vLr=PFaihr=<B? zKc<U9igg(WzX^YKg(>t|w^;Uio_W-W!99#1)w8~QEF@-8<Dx6+OM93l3;4?UuzF7` zZ}p(K`jdyV^9j{V{mPx#LTYE^M{a=j(-LvKdq&|ii8#q*1;Qy+tUW+gotp3#ZP!c~ z-DZwWOg*qOVSTNvj0MDY%9s`YihKlvd^#u`>Xdfe(8elrW28;7BlCF(#29A{M>))K zzB$-PVvH-8a%s7(ZY7zTS}x73V0g}9{W;J{2O>?<f=sn@FW=Wo?x9@xEgRC0=G@_3 z8~kYud+ba4+qh8;3;mr=j`H}N1XFzDp`64x+ms;>ibE=%5FbECQaL@nPizv15cxxh z$&McO46t3KHP~AWo<Pz=$Oj)==Oi9@?nzotN^vu%Q%Zm-;&08YSDJw~r%@d3hX<;w z(?=PxxmN<kQG@N1g9>al_UwH0QRRwja%?qD?E18mGvp7Dsz#5-VrF7=Jr=e13Zb*6 zh2|NFMiAK7*iV^>F}Bu|u_hvH2BU+Kw$^j8AA+J8QlQ%kYQ<BA;&3n7iY##p403pq zC9n`CgecdG$D`#+nTqAjNF1@<Pz@tY8J^tGe~e0_lb7@e+8fc{^far7wQ8h5swnoP zswh-fdH2F~MAN)v!I>!ox=Oh{U+W+~r(!4N;Dc!f-LiwgY%Ni<>=I`wqW3O;-JRlV zTqHQux5G6GBj9V_3h}fTJ3cp;yGX@RdHrx8_4;9>TpZne^?A3;Y4?;~tr*G$&X^%k z5)hnXiB7p3_ly_Zxb7m9JoCBHi!O2*t%=vU10i}Zh2u!NnblUp*2r2v!LkRb#M2J1 z6zb$M{w_xq1>t#U6ZQ~NWGomGBB5vN8q{c#dvl2%yayLDlhAkBBoNcbe42!jyzp)@ z2y3<51G_%!oCU@9{Sr?+w6zLL+(~A>diN^wMTvOrz^3<-mLikGCvCBQ0n~>RNv}v+ z&KH5b!*p#tecu3p$Xcs;mzLTlRP98J8kAyg@aVD2CBF7o9b(_lqfXYD=jJSVNQ26X z+R}E7SX?;hZN(7V*cDMqXQ`72bp`5I?SXJc1i$-eLA)mBcoYwXCVj|D#YXzUX(eGa zTyTtZb;SkI{<CiOrWM$JU`8(`m-3<}@}rw7+p(H7_k72(Hq4G71Y+2%Z+*tUHW_Yi zbWCdc;KoGJ`GOt5@<Sk(B9*CNc-3+F=`!Q6tDxQc&fK#W&MGZrd-gEeV7U?5)d3`f z#wGZ;1{9G+-@F)E)_$8isyg9Kco`&8OB@kC`YGG20o?i}eO2?bn~SscGppAlCk9zV zB!3aVX-j2C>s>4?0=oYp{@ZwyJ-M44A3g+I5F_mvH>ma*bYOjH#-IXLs?E}ST*Cw7 zc;*qNtR<h0OM{i<1ph76tw1TAnG=f=N64<%m|+~>$XZ<;OGRZ%ZiVuTdpxOV+&AB= z3!XUq^xM77@2NK<kc>#{6IV_PiD5JIHe8(~b~y@QwHu7XZR^5r<G1D8o8T5I505E) z+p9k46Ut6_IYR+PaZQMVYS7M2kuO34UJw$yUmz(%8gk}G>0N64Dd`mPR_wq4vP3<~ zuiwI`FYk+qOP47~q>!e~sqa=zHT?qhZL3#nH3p<^yqhzEwhyV~MBOBHllL8Y@A|uC z$-?N#DK7J@JhycZe?>e2MuE1>;6_+p1lqj(p9<|`(1zE_XYK7aqUKyh9hYB5Tyr#W zu*u76pD;v1Fzp`RkM#jW7cnbgCBMAo`-piEuGDPW%~Jzv&`=&(0YlL8=D^WGwfV6f zDYm}8*P1I~G!-7Skxbs_wVY8a(!Op$;2cB@wXb|7h?jaMS8L(E3+x8M=lgZ~u>xYL z&n3epJW4-9@N#*dG2CZBaciQFsm||{68^0GF=$wOu1(18HGepKk=eOa&n;OsfwSOX zdSY}Y<V4e^%dy#1QC2XebycJ+`Pi4TGOW85Wh6wM?LPfxX&+(M%KoyJHyvjB+f>i4 zkeW#E2^!n;LIs;v#yWcj?j}Kp<d)HvvI0F;_cHGO3FznIZTZ5Re0lH4ozRC-V;b*k z-9bCW$t5K_)s=A+eZHRF-u6+rwF=WS{X7KjoudAd;XE*fCy7jNidG=ii3}Pa$>%{I zixj)bsNtAovw2i}FryuBmRptk<IM5GuVZH8j28d#dY;Hf{p~Yac;w^t>Uj4rSIl~h zo3Z(JdS|tFGduPY<$r+f@FN}V2Qn)TllCrVvnrPeO(YaGKiKhzDjOx1rX@~fxm989 z2Yt=)^QU?de__q$_gi=HJ#B40Fk81zfz5In(Hua$8q!%fxFkx|;`n-6SiX^rQFp_3 zu$C4!NoXW2$Cvv$3l3QF*L~+7C%b?c>n3f*6BG(>1WJA!QGi%a6Sf3AfU$bsXuSR= zO3+bHwxv@~RwOOb%hgvHM>9PF@u`vEJi1<<wlnV+7I|P9L8Hgx$lg>E5=)rk%%p2W zZ&BvNrk>*5N5M_9tiNfIKP>XzPWr*<n?j=WFWXPATrZzCl)`;fgEiTnc&{J%YvZKT zsP#ph5<M!XLtHK!<Lu6q3k6xF42*J5OMm(uMO33#7II3M@{*-U^@WY*TbS&oSD7Yt z7GT~;wh49q%HJta<9_|hW@?K2$zX~6F}CgwnumT-ax3ZLJUs2}*o<tMoF(2XY|$mo zQxsJvNGWH}a|Ul2&3nTA^v!03N{P{udO_Pse%KoUBU=AW+FribW5WFb8cY`VCGTu< zo7PGhbJ2|k7<#8w=9`#!j8atNbj0y@L^xT@xnU3O{m4kq6y$r%Izi!Txv`u*wPGi4 z?Q61%%kV57FTnl{HLo`QQ(0lmsr;gis(D+!ERUY#^MF)1`G<YtIh)HW&l#w6FDbGZ zrqC>=ld`qX(mcz|{Q44kSH}B;06a43^rI}i>t}=2$;XE()oz`uVL!4#i0hUal&!>| zt#I{}*Xdcn9wQ?-*GQ~uUpHIDI^MN@eR1JS`PRLUClfB$f9P<wqmN<jHV(d^_%9ve z|E;yvO;L0F5!;e~(Qv}mTo?EWgO7evg%Y<-d)JxMJVz-!5Hb#~Cm_dE>-G%CR?MVI zXhSpLW-V2hLj1ubNxzT5Nie^&#V?i#@%6$KzDyvUJnhDbqO8HTfS_}^dne}iN-BDy zBv^;a57bmQ6i9`I5>qgT3Jl3*)pw$uVmJckjL^X(#s&jl#KYmC-15s`j=5AiQAGA^ zuWPf9dk%cq73@xziS1ln2dvTy3+hg%hwnDzg&yZcOdM+4)=i&C-PCnLt#S+9Nv`p~ zjunmUM!c>pzI0`x(Xl1EFFe6=e^DlXe_b;3(HRpFvsnvyEXVhZ-HSE!;meO|?l0c$ zFp_z51{k_(85scJuKhUosG!SMJx_QN{9lMkmiq3j*^aHH#yF4NN54KHde|EpLn?9q zz+`l-#NS7LGm4<e;@yyVPF?mowetNj$3kO%bvp);)O12F-^H#AR&P#1Yv^H1$WGLu z=o^U^3jEr|_EW|=gRe?TSD2)@+0U;sK{1S=d{?_6UmwE@_^KPC9xMbd5zuM0P+1DD z;zLg-)~}_^SDayo@A~X*TTHxmM_H!aeU>f6!Fmq3K$?$Z%OCsIL|08bZ~dk9y>Wd> zQ{Sz^IXC{(l%K6Tx-M5D&~Jj%{Q@)i;#POT2M|99<5;|dh1CN1??(80AN)y(l6B~r z;ij6s{FH$h1KvPpQ&eQpoZ|bzWOfcqq0Z@Z?CA!_dF+#;LlF@zm4LSGoGFj442>>5 z+QV*fqg{qXnNZe=c5<C6kJI)nlqeT0$DwCfRW6=*Wum@$xcOas?RR?~oEbGYZT`>k zu;lzWOoZjZ1s<hGSl&d4$uoTc<~&m?_{R%QV;pF*btsh&$6LE*kywo*M0{!}Ce_w) zWI)=D5X3d{)k2WvqTtLtrR^fmVhpKz6&4cnIsRbU40_)CJLu^w3BAKk?h3m9qb}qn zuU7{*amiqOoR&+7FR3<vo^wmQFYVXSR1duZ74hg~A!y_Xa^m<c$B=OZyrYT;zR+B& zFq$KcxGUyTc)S|%@RE(pZRpgG{=o|X!VVKxpgCR4oBkul?KB0~-5<b24Kr2Rd;8Os zUDh&*PeoRVO}t%-z7%55Z9F@4bwstUqT7J-T5$P!eP^)=a>mm4;);CUlluDdO~2@$ z4Aq>f@#XD;EMot?Ab|g>;K|sGY;X<NUVg%eTZeqs*PsD5j?tp4cbF$|c;ac_#I0sB zh<pSBbKeBr5n7SRJwVS`{RHi+lpkP8DLXzFdZdaBS=CprbDXrpq(0JqzzPWkJLV}U z0qixH2P2z^1CXS(^8D`<e$p)6Tkpo?8FA?>6pWd7*b1ZsMIQ1i6IZ1s!0FWco*B*1 z6af^22bZW2e0|fvYie%Zr%Tk0OOqfb5TkvuA+GB8hlftqWyy5*Q|!N=C)#ZzH+VVJ zb`*pBeV!h5Yt(RMyw7khpe??3G{T%&d5caIGY17LwR71$%GYD90(3@Z4=%)@J+JkU z;4vIHU5}{o?xVkKLy4h=_FUa2>Y29&`nPKMglYQE2>}Ij<$u_#k45CqNx^RxapKz( z1Ec>J9FrA*51Ie!`llE`^N;i&3o9x)5y<%m^Ut{P-x$VZ^xv3&lIj0q7+L=_4h(F_ zyLvmv(_78+HU#}gQAoC81^=1rpT0=>4+IvLOL93Y8_S=6{>Szp`xhpbF8LcP^Phnz uG5>ES(tm-3lX=;g|JVh}Mvv{xnC!>~{L@UhZ7MJ&e_#XQoihLR$^QY&_YL9z diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index 897cd10b..8fbf8a2a 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -126,11 +126,14 @@ def test_wrong_datatype(): assert "J7" in line if "1.5 is not of type 'integer'" in line: assert "K7" in line + if "1.2345 is not of type 'integer'" in line: + assert "K8" in line # No additional type errors if "is not of type 'boolean'" in str(caught.value): # ToDo: Remove when boolean is fixed assert str(caught.value).count("is not of type") == 3 else: - assert str(caught.value).count("is not of type") == 2 + assert str(caught.value).count("is not of type") == 2 # FIXME when everything works as + # # expected, set correct number. def test_additional_column(): -- GitLab From cf4f96cef6d90838679858ea770bfb111b5fc77d Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Thu, 14 Nov 2024 13:27:05 +0100 Subject: [PATCH 034/106] WIP: More renaming CaosDB -> LinkAhead --- .docker/cert.sh | 2 +- .gitlab-ci.yml | 2 +- Makefile | 2 +- RELEASE_GUIDELINES.md | 2 +- extra/emacs/snippets/yaml-mode/RecordType | 2 +- integrationtests/clear_database.py | 4 +- integrationtests/crawl.py | 4 +- integrationtests/create_analysis.py | 4 +- integrationtests/example_hdf5cfood.py | 4 +- integrationtests/insert_model.py | 2 +- integrationtests/insert_some.py | 2 +- integrationtests/test_assure_functions.py | 4 +- .../test_base_table_exporter_integration.py | 4 +- integrationtests/test_cache.py | 4 +- .../test_crawl_with_datamodel_problems.py | 4 +- integrationtests/test_crawler_basics.py | 4 +- integrationtests/test_crawler_with_cfoods.py | 6 +- integrationtests/test_data_model.py | 2 +- integrationtests/test_datamodel_problems.py | 6 +- integrationtests/test_im_und_export.py | 4 +- .../test_json_schema_datamodel_parser.py | 4 +- integrationtests/test_json_schema_exporter.py | 2 +- integrationtests/test_table.py | 4 +- integrationtests/test_yaml_parser.py | 4 +- integrationtests/update_analysis.py | 4 +- manual_tests/test_labfolder_import.py | 2 +- manual_tests/test_labfolder_retrieve.py | 2 +- setup.py | 2 +- src/caosadvancedtools/cache.py | 4 +- src/caosadvancedtools/cfood.py | 28 +++++----- src/caosadvancedtools/cfoods/__init__.py | 2 +- src/caosadvancedtools/cfoods/h5.py | 6 +- src/caosadvancedtools/collect_datamodel.py | 6 +- .../converter/labfolder_api.py | 4 +- .../converter/labfolder_export.py | 4 +- src/caosadvancedtools/crawler.py | 56 +++++++++---------- src/caosadvancedtools/datainconsistency.py | 2 +- src/caosadvancedtools/datamodel_problems.py | 4 +- src/caosadvancedtools/example_cfood.py | 4 +- src/caosadvancedtools/export_related.py | 12 ++-- src/caosadvancedtools/guard.py | 4 +- src/caosadvancedtools/import_from_xml.py | 6 +- src/caosadvancedtools/json_schema_exporter.py | 2 +- src/caosadvancedtools/loadFiles.py | 4 +- src/caosadvancedtools/models/data_model.py | 22 ++++---- src/caosadvancedtools/models/parser.py | 16 +++--- src/caosadvancedtools/pandoc_header_tools.py | 2 +- src/caosadvancedtools/read_md_header.py | 4 +- .../scifolder/analysis_cfood.py | 4 +- .../scifolder/experiment_cfood.py | 2 +- .../scifolder/publication_cfood.py | 2 +- .../scifolder/result_table_cfood.py | 2 +- .../scifolder/simulation_cfood.py | 2 +- .../scifolder/software_cfood.py | 2 +- src/caosadvancedtools/scifolder/utils.py | 2 +- src/caosadvancedtools/scifolder/withreadme.py | 2 +- .../serverside/examples/example_script.py | 10 ++-- .../serverside/generic_analysis.py | 4 +- src/caosadvancedtools/serverside/helper.py | 24 ++++---- src/caosadvancedtools/structure_mapping.py | 8 +-- src/caosadvancedtools/table_converter.py | 4 +- src/caosadvancedtools/table_export.py | 8 +-- src/caosadvancedtools/utils.py | 6 +- src/doc/Makefile | 2 +- src/doc/crawler.rst | 2 +- unittests/create_filetree.py | 2 +- ...ignore-example => linkaheadignore-example} | 0 unittests/test_base_table_exporter.py | 4 +- unittests/test_cache.py | 4 +- unittests/test_caosdbignore.py | 6 +- unittests/test_cfood.py | 4 +- unittests/test_crawler.py | 4 +- unittests/test_data_model.py | 2 +- unittests/test_generic_analysis.py | 4 +- unittests/test_json_schema_exporter.py | 2 +- unittests/test_json_schema_model_parser.py | 6 +- unittests/test_read_md_header.py | 4 +- unittests/test_result_table_cfood.py | 4 +- unittests/test_sss_helper.py | 10 ++-- unittests/test_structure_mapping.py | 6 +- unittests/test_suppressKnown.py | 2 +- unittests/test_table_converter.py | 6 +- unittests/test_update_cache.py | 4 +- unittests/test_utils.py | 10 ++-- unittests/test_yaml_model_parser.py | 2 +- 85 files changed, 228 insertions(+), 228 deletions(-) rename unittests/{caosdbignore-example => linkaheadignore-example} (100%) diff --git a/.docker/cert.sh b/.docker/cert.sh index e22cfba2..c7253c77 100755 --- a/.docker/cert.sh +++ b/.docker/cert.sh @@ -1,7 +1,7 @@ #!/bin/bash # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2019 Daniel Hornung, Göttingen # diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 65698d86..f9702235 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen diff --git a/Makefile b/Makefile index 26f5c818..c53f7013 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> diff --git a/RELEASE_GUIDELINES.md b/RELEASE_GUIDELINES.md index adeab4dd..11c84446 100644 --- a/RELEASE_GUIDELINES.md +++ b/RELEASE_GUIDELINES.md @@ -1,7 +1,7 @@ # Release Guidelines for the CaosDB Python Client Library This document specifies release guidelines in addition to the general release -guidelines of the CaosDB Project +guidelines of the LinkAhead project ([RELEASE_GUIDELINES.md](https://gitlab.com/caosdb/caosdb/blob/dev/RELEASE_GUIDELINES.md)) ## General Prerequisites diff --git a/extra/emacs/snippets/yaml-mode/RecordType b/extra/emacs/snippets/yaml-mode/RecordType index 6b4a9c26..8c0382d5 100644 --- a/extra/emacs/snippets/yaml-mode/RecordType +++ b/extra/emacs/snippets/yaml-mode/RecordType @@ -1,5 +1,5 @@ # -*- mode: snippet -*- -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2022 Daniel Hornung <d.hornung@indiscale.com> diff --git a/integrationtests/clear_database.py b/integrationtests/clear_database.py index 138cf4e6..b0b5020f 100644 --- a/integrationtests/clear_database.py +++ b/integrationtests/clear_database.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -23,7 +23,7 @@ # ** end header # """Clear the database before and after the integration tests.""" -import caosdb as db +import linkahead as db def clear_all(): diff --git a/integrationtests/crawl.py b/integrationtests/crawl.py index defed2cb..a3e43a19 100755 --- a/integrationtests/crawl.py +++ b/integrationtests/crawl.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -28,7 +28,7 @@ import logging import sys from argparse import RawTextHelpFormatter -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import fileguide from caosadvancedtools.crawler import FileCrawler from caosadvancedtools.guard import INSERT, UPDATE diff --git a/integrationtests/create_analysis.py b/integrationtests/create_analysis.py index 1b7aa0d2..ec2c707c 100644 --- a/integrationtests/create_analysis.py +++ b/integrationtests/create_analysis.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -31,7 +31,7 @@ automated analysis pipeline. import sys from datetime import datetime -import caosdb as db +import linkahead as db def main(): diff --git a/integrationtests/example_hdf5cfood.py b/integrationtests/example_hdf5cfood.py index 5485402d..73688581 100644 --- a/integrationtests/example_hdf5cfood.py +++ b/integrationtests/example_hdf5cfood.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2021 IndiScale GmbH <www.indiscale.com> # Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -27,7 +27,7 @@ An exemplary definition of a HDF5 CFood for integration testing """ -import caosdb as db +import linkahead as db from caosadvancedtools.cfoods.h5 import H5CFood from caosadvancedtools.scifolder import ExperimentCFood from caosadvancedtools.scifolder.generic_pattern import readme_pattern diff --git a/integrationtests/insert_model.py b/integrationtests/insert_model.py index 26bf478c..170adbc8 100755 --- a/integrationtests/insert_model.py +++ b/integrationtests/insert_model.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import caosdb as db +import linkahead as db import h5py from caosadvancedtools.cfoods.h5 import H5CFood from caosadvancedtools.models.data_model import DataModel diff --git a/integrationtests/insert_some.py b/integrationtests/insert_some.py index cf16a45d..19a4c1f2 100644 --- a/integrationtests/insert_some.py +++ b/integrationtests/insert_some.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import caosdb as db +import linkahead as db from caosadvancedtools.scifolder.experiment_cfood import dm # This inserts two identifiables. When no dependencies are possible among diff --git a/integrationtests/test_assure_functions.py b/integrationtests/test_assure_functions.py index e04d481f..91ec1440 100644 --- a/integrationtests/test_assure_functions.py +++ b/integrationtests/test_assure_functions.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2021 University Medical Center Göttingen, Institute for Medical Informatics @@ -25,7 +25,7 @@ no `to_be_updated` is specified. """ -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (assure_object_is_in_list) from caosadvancedtools.guard import (global_guard, RETRIEVE, UPDATE) diff --git a/integrationtests/test_base_table_exporter_integration.py b/integrationtests/test_base_table_exporter_integration.py index 5af9caa3..286c4ac3 100644 --- a/integrationtests/test_base_table_exporter_integration.py +++ b/integrationtests/test_base_table_exporter_integration.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Florian Sprecklelsen <f.spreckelsen@indiscale.com> @@ -22,7 +22,7 @@ # # ** end header # -import caosdb as db +import linkahead as db import pytest from caosadvancedtools import table_export as te diff --git a/integrationtests/test_cache.py b/integrationtests/test_cache.py index aacef179..13470b8b 100644 --- a/integrationtests/test_cache.py +++ b/integrationtests/test_cache.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -26,7 +26,7 @@ import os import unittest from tempfile import NamedTemporaryFile -import caosdb as db +import linkahead as db from caosadvancedtools.cache import UpdateCache diff --git a/integrationtests/test_crawl_with_datamodel_problems.py b/integrationtests/test_crawl_with_datamodel_problems.py index 8623d57d..c2b19a95 100644 --- a/integrationtests/test_crawl_with_datamodel_problems.py +++ b/integrationtests/test_crawl_with_datamodel_problems.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (c) 2020 IndiScale GmbH <info@indiscale.com> # Copyright (c) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -25,7 +25,7 @@ """ -import caosdb as db +import linkahead as db from caosadvancedtools import loadFiles from caosadvancedtools.cfood import fileguide from caosadvancedtools.crawler import FileCrawler diff --git a/integrationtests/test_crawler_basics.py b/integrationtests/test_crawler_basics.py index 60c09d73..04eb5459 100644 --- a/integrationtests/test_crawler_basics.py +++ b/integrationtests/test_crawler_basics.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -29,7 +29,7 @@ cfoods. This is tested in test_crawler_with_cfoods.py. """ import unittest -import caosdb as db +import linkahead as db from caosadvancedtools.crawler import Crawler from caosadvancedtools.guard import INSERT diff --git a/integrationtests/test_crawler_with_cfoods.py b/integrationtests/test_crawler_with_cfoods.py index 1fa5eaa5..472eee0e 100755 --- a/integrationtests/test_crawler_with_cfoods.py +++ b/integrationtests/test_crawler_with_cfoods.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -25,8 +25,8 @@ import os import unittest -import caosdb as db -from caosdb.apiutils import retrieve_entity_with_id +import linkahead as db +from linkahead.apiutils import retrieve_entity_with_id def get_entity_with_id(eid): diff --git a/integrationtests/test_data_model.py b/integrationtests/test_data_model.py index bd74a40b..bde9eda9 100644 --- a/integrationtests/test_data_model.py +++ b/integrationtests/test_data_model.py @@ -1,7 +1,7 @@ import unittest import pytest -import caosdb as db +import linkahead as db from caosadvancedtools.models.data_model import DataModel diff --git a/integrationtests/test_datamodel_problems.py b/integrationtests/test_datamodel_problems.py index 85517033..1ac32bb8 100644 --- a/integrationtests/test_datamodel_problems.py +++ b/integrationtests/test_datamodel_problems.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -27,10 +27,10 @@ during crawling that tests the integrations of the DataModelProblems class in crawler.py and cfood.py can be found in full-tests. """ -import caosdb as db +import linkahead as db import pytest from caosadvancedtools.datamodel_problems import DataModelProblems -from caosdb.exceptions import (TransactionError, +from linkahead.exceptions import (TransactionError, UnqualifiedParentsError, UnqualifiedPropertiesError) diff --git a/integrationtests/test_im_und_export.py b/integrationtests/test_im_und_export.py index 407faa1a..5d0aa26b 100644 --- a/integrationtests/test_im_und_export.py +++ b/integrationtests/test_im_und_export.py @@ -2,7 +2,7 @@ import os from tempfile import TemporaryDirectory -import caosdb as db +import linkahead as db from caosadvancedtools.export_related import export_related_to from caosadvancedtools.import_from_xml import import_xml @@ -19,7 +19,7 @@ if __name__ == "__main__": assert 0 == len(db.execute_query("FIND File which is stored at " "**/poster.pdf")) print("Importing stored elements") - import_xml(os.path.join(directory.name, "caosdb_data.xml"), interactive=False) + import_xml(os.path.join(directory.name, "linkahead_data.xml"), interactive=False) # The following tests the existence of some required entities. # However, this is not a full list. diff --git a/integrationtests/test_json_schema_datamodel_parser.py b/integrationtests/test_json_schema_datamodel_parser.py index 21ae8d2d..074c4a06 100644 --- a/integrationtests/test_json_schema_datamodel_parser.py +++ b/integrationtests/test_json_schema_datamodel_parser.py @@ -1,5 +1,5 @@ # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -20,7 +20,7 @@ import os -import caosdb as db +import linkahead as db from caosadvancedtools.models.parser import parse_model_from_json_schema diff --git a/integrationtests/test_json_schema_exporter.py b/integrationtests/test_json_schema_exporter.py index 44b42826..5b0d758e 100644 --- a/integrationtests/test_json_schema_exporter.py +++ b/integrationtests/test_json_schema_exporter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2023 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2023 Florian Spreckelsen <f.spreckelsen@indiscale.com> diff --git a/integrationtests/test_table.py b/integrationtests/test_table.py index b8dfe349..4e87a7db 100644 --- a/integrationtests/test_table.py +++ b/integrationtests/test_table.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Henrik tom Wörden # @@ -20,7 +20,7 @@ import logging -import caosdb as db +import linkahead as db import pandas as pd from caosadvancedtools.crawler import TableCrawler diff --git a/integrationtests/test_yaml_parser.py b/integrationtests/test_yaml_parser.py index e2a2c4c0..9718c4a2 100644 --- a/integrationtests/test_yaml_parser.py +++ b/integrationtests/test_yaml_parser.py @@ -1,6 +1,6 @@ # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -19,7 +19,7 @@ # with this program. If not, see <https://www.gnu.org/licenses/>. # -import caosdb as db +import linkahead as db from caosadvancedtools.models.parser import parse_model_from_string diff --git a/integrationtests/update_analysis.py b/integrationtests/update_analysis.py index ddebc049..18ae8332 100644 --- a/integrationtests/update_analysis.py +++ b/integrationtests/update_analysis.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -34,7 +34,7 @@ entities that where changed within a certain period of time. import sys -import caosdb as db +import linkahead as db from caosadvancedtools.serverside.generic_analysis import run diff --git a/manual_tests/test_labfolder_import.py b/manual_tests/test_labfolder_import.py index c767feb5..abc5eb11 100644 --- a/manual_tests/test_labfolder_import.py +++ b/manual_tests/test_labfolder_import.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (c) 2020 IndiScale GmbH # Copyright (c) 2020 Daniel Hornung <d.hornung@indiscale.com> diff --git a/manual_tests/test_labfolder_retrieve.py b/manual_tests/test_labfolder_retrieve.py index 5bbaf91d..a7f56e80 100644 --- a/manual_tests/test_labfolder_retrieve.py +++ b/manual_tests/test_labfolder_retrieve.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (c) 2020 IndiScale GmbH # diff --git a/setup.py b/setup.py index bee11751..a7146ead 100755 --- a/setup.py +++ b/setup.py @@ -149,7 +149,7 @@ def setup_package(): metadata = dict( name='caosadvancedtools', version=get_version_info()[0], - description='advanced utilities for caosdb', + description='Advanced utilities for LinkAhead', long_description=long_description, long_description_content_type="text/markdown", author='Henrik tom Wörden', diff --git a/src/caosadvancedtools/cache.py b/src/caosadvancedtools/cache.py index bf1287ba..749239fa 100644 --- a/src/caosadvancedtools/cache.py +++ b/src/caosadvancedtools/cache.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -33,7 +33,7 @@ from abc import ABC, abstractmethod from copy import deepcopy from hashlib import sha256 -import caosdb as db +import linkahead as db from lxml import etree diff --git a/src/caosadvancedtools/cfood.py b/src/caosadvancedtools/cfood.py index 588476bd..e79f0373 100644 --- a/src/caosadvancedtools/cfood.py +++ b/src/caosadvancedtools/cfood.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -23,9 +23,9 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -""" Defines how something that shall be inserted into CaosDB is treated. +""" Defines how something that shall be inserted into LinkAhead is treated. -CaosDB can automatically be filled with Records based on some structure, a file +LinkAhead can automatically be filled with Records based on some structure, a file structure, a table or similar. The Crawler will iterate over the respective items and test for each item @@ -33,9 +33,9 @@ whether a CFood class exists that matches the file path, i.e. whether CFood class wants to treat that pariticular item. If one does, it is instanciated to treat the match. This occurs in basically three steps: -1. Create a list of identifiables, i.e. unique representation of CaosDB Records +1. Create a list of identifiables, i.e. unique representation of LinkAhead Records (such as an experiment belonging to a project and a date/time). -2. The identifiables are either found in CaosDB or they are created. +2. The identifiables are either found in LinkAhead or they are created. 3. The identifiables are update based on the date in the file structure. """ @@ -45,10 +45,10 @@ import warnings from abc import ABCMeta, abstractmethod from datetime import datetime -import caosdb as db -from caosdb.common.models import Entity -from caosdb.exceptions import (BadQueryError, EmptyUniqueQueryError, - QueryNotUniqueError, TransactionError) +import linkahead as db +from linkahead.common.models import Entity +from linkahead.exceptions import (BadQueryError, EmptyUniqueQueryError, + QueryNotUniqueError, TransactionError) from .datamodel_problems import DataModelProblems from .guard import global_guard as guard @@ -65,7 +65,7 @@ logger = logging.getLogger(__name__) def get_entity(name): """ Returns the entity with a given name, preferably from a local cache. - If the local cache does not contain the entity, retrieve it from CaosDB. + If the local cache does not contain the entity, retrieve it from LinkAhead. """ if name not in ENTITIES: @@ -81,7 +81,7 @@ def get_property(name): cache. If the local cache does not contain the record type, try to - retrieve it from CaosDB. If it does not exist, see whether it + retrieve it from LinkAhead. If it does not exist, see whether it could be a record type used as a property. """ @@ -103,7 +103,7 @@ def get_record(name): """Returns the record with a given name, preferably from a local cache. If the local cache does not contain the record, try to retrieve it - from CaosDB. + from LinkAhead. """ @@ -120,7 +120,7 @@ def get_recordtype(name): cache. If the local cache does not contain the record type, try to - retrieve it from CaosDB. If it does not exist, add it to the data + retrieve it from LinkAhead. If it does not exist, add it to the data model problems """ @@ -140,7 +140,7 @@ def get_recordtype(name): class FileGuide(object): def access(self, path): """ should be replaced by a function that adds - a prefix to paths to allow to access caosdb files locally + a prefix to paths to allow to access LinkAhead files locally This default just returns the unchanged path. """ diff --git a/src/caosadvancedtools/cfoods/__init__.py b/src/caosadvancedtools/cfoods/__init__.py index 30ce05ad..6936568a 100644 --- a/src/caosadvancedtools/cfoods/__init__.py +++ b/src/caosadvancedtools/cfoods/__init__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 IndiScale GmbH <www.indiscale.com> # Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> diff --git a/src/caosadvancedtools/cfoods/h5.py b/src/caosadvancedtools/cfoods/h5.py index dfd6f290..3b3b5688 100644 --- a/src/caosadvancedtools/cfoods/h5.py +++ b/src/caosadvancedtools/cfoods/h5.py @@ -34,7 +34,7 @@ Properties. from copy import deepcopy -import caosdb as db +import linkahead as db import h5py import numpy as np from caosadvancedtools.cfood import fileguide @@ -45,7 +45,7 @@ from ..structure_mapping import (EntityMapping, collect_existing_structure, def h5_attr_to_property(val): - """ returns the value and datatype of a CaosDB Property for the given value + """ returns the value and datatype of a LinkAhead Property for the given value 1d arrays are converted to lists @@ -168,7 +168,7 @@ class H5CFood(AbstractFileCFood): self.to_be_inserted = db.Container() self.insert_missing_structure(self.structure) - # TODO this is a workaround due to the fact that the caosdb library + # TODO this is a workaround due to the fact that the linkahead library # changes the objects in the Container if it is inserted. The graph # structure is flattened. I.e. references to other entity objects are # replaced with their IDs. However this code depends on this graph. diff --git a/src/caosadvancedtools/collect_datamodel.py b/src/caosadvancedtools/collect_datamodel.py index 806d1533..1c37bab0 100644 --- a/src/caosadvancedtools/collect_datamodel.py +++ b/src/caosadvancedtools/collect_datamodel.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -25,8 +25,8 @@ import argparse import os -import caosdb as db -from caosdb.apiutils import retrieve_entities_with_ids +import linkahead as db +from linkahead.apiutils import retrieve_entities_with_ids from export_related import export diff --git a/src/caosadvancedtools/converter/labfolder_api.py b/src/caosadvancedtools/converter/labfolder_api.py index cf57c015..fe77282a 100644 --- a/src/caosadvancedtools/converter/labfolder_api.py +++ b/src/caosadvancedtools/converter/labfolder_api.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (c) 2020 IndiScale GmbH # Copyright (c) 2020 Daniel Hornung <d.hornung@indiscale.com> @@ -27,7 +27,7 @@ import time import html2text -import caosdb as db +import linkahead as db from labfolder.connection import configure_connection # pylint: disable=import-error diff --git a/src/caosadvancedtools/converter/labfolder_export.py b/src/caosadvancedtools/converter/labfolder_export.py index 6e282218..ae38cb10 100644 --- a/src/caosadvancedtools/converter/labfolder_export.py +++ b/src/caosadvancedtools/converter/labfolder_export.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (c) 2020 IndiScale GmbH # Copyright (c) 2020 Daniel Hornung <d.hornung@indiscale.com> @@ -25,7 +25,7 @@ import os from bs4 import BeautifulSoup -import caosdb as db +import linkahead as db RERUN = False # crawler = Crawler() diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index fc3b260b..7a840624 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -25,16 +25,16 @@ # # ** end header # -""" Crawls a file structure and inserts Records into CaosDB based on what is +""" Crawls a file structure and inserts Records into LinkAhead based on what is found. -CaosDB can automatically be filled with Records based on some file structure. +LinkAhead can automatically be filled with Records based on some file structure. The Crawler will iterate over the files and test for each file whether a CFood exists that matches the file path. If one does, it is instanciated to treat the match. This occurs in basically three steps: -1. create a list of identifiables, i.e. unique representation of CaosDB Records +1. create a list of identifiables, i.e. unique representation of LinkAhead Records (such as an experiment belonging to a project and a date/time) -2. the identifiables are either found in CaosDB or they are created. +2. the identifiables are either found in LinkAhead or they are created. 3. the identifiables are update based on the date in the file structure """ @@ -47,8 +47,8 @@ import uuid from datetime import datetime from sqlite3 import IntegrityError -import caosdb as db -from caosdb.exceptions import BadQueryError +import linkahead as db +from linkahead.exceptions import BadQueryError from .cache import IdentifiableCache, UpdateCache, get_pretty_xml from .cfood import RowCFood, add_files, get_ids_for_entities_with_names @@ -69,7 +69,7 @@ def separated(text): def apply_list_of_updates(to_be_updated, update_flags={}, update_cache=None, run_id=None): - """Updates the `to_be_updated` Container, i.e., pushes the changes to CaosDB + """Updates the `to_be_updated` Container, i.e., pushes the changes to LinkAhead after removing possible duplicates. If a chace is provided, uauthorized updates can be cached for further authorization. @@ -78,7 +78,7 @@ def apply_list_of_updates(to_be_updated, update_flags={}, to_be_updated : db.Container Container with the entities that will be updated. update_flags : dict, optional - Dictionary of CaosDB server flags that will be used for the + Dictionary of LinkAhead server flags that will be used for the update. Default is an empty dict. update_cache : UpdateCache or None, optional Cache in which the intended updates will be stored so they can be @@ -147,7 +147,7 @@ class Crawler(object): The Crawler will use those CFoods when crawling. use_cache : bool, optional Whether to use caching (not re-inserting probably existing - objects into CaosDB), defaults to False. + objects into LinkAhead), defaults to False. abort_on_exception : if true, exceptions are raise. Otherwise the crawler continues if an exception occurs. interactive : boolean, optional @@ -271,7 +271,7 @@ class Crawler(object): """ This is the first phase of the crawl. It collects all cfoods that shall be processed. The second phase is iterating over cfoods and updating - CaosDB. This separate first step is necessary in order to allow a + LinkAhead. This separate first step is necessary in order to allow a single cfood being influenced by multiple crawled items. E.g. the FileCrawler can have a single cfood treat multiple files. @@ -512,16 +512,16 @@ ____________________\n""".format(i+1, len(pending_changes)) + str(el[3])) Parameters: ----------- - changes: The CaosDB entities in the version after the update. + changes: The LinkAhead entities in the version after the update. path: the path defining the subtree that is crawled """ from xml.sax.saxutils import escape - caosdb_config = db.configuration.get_config() - if ("advancedtools" in caosdb_config and "crawler.customcssfile" in - caosdb_config["advancedtools"]): - cssfile = caosdb_config["advancedtools"]["crawler.customcssfile"] + linkahead_config = db.configuration.get_config() + if ("advancedtools" in linkahead_config and "crawler.customcssfile" in + linkahead_config["advancedtools"]): + cssfile = linkahead_config["advancedtools"]["crawler.customcssfile"] else: cssfile = None # TODO move path related stuff to sss_helper @@ -584,11 +584,11 @@ ____________________\n""".format(i+1, len(pending_changes)) + str(el[3])) </script> </body> </html> -""".format(url=caosdb_config["Connection"]["url"], +""".format(url=linkahead_config["Connection"]["url"], rid=run_id, changes=escape("\n".join(changes)), customcssfile='<link rel="stylesheet" href="{url}/webinterface/css/{customcssfile}"/>'.format( - url=caosdb_config["Connection"]["url"], customcssfile=cssfile) if cssfile else "", + url=linkahead_config["Connection"]["url"], customcssfile=cssfile) if cssfile else "", path=path) if "SHARED_DIR" in os.environ: @@ -611,11 +611,11 @@ ____________________\n""".format(i+1, len(pending_changes)) + str(el[3])) Parameters: ----------- - changes: The CaosDB entities in the version after the update. + changes: The LinkAhead entities in the version after the update. filename: path to the html site that allow the authorization """ - caosdb_config = db.configuration.get_config() + linkahead_config = db.configuration.get_config() text = """Dear Curator, there where changes that need your authorization. Please check the following carefully and if the changes are ok, click on the following link: @@ -623,12 +623,12 @@ carefully and if the changes are ok, click on the following link: {url}/Shared/{filename} {changes} - """.format(url=caosdb_config["Connection"]["url"], + """.format(url=linkahead_config["Connection"]["url"], filename=filename, changes="\n".join(changes)) try: - fro = caosdb_config["advancedtools"]["crawler.from_mail"] - to = caosdb_config["advancedtools"]["crawler.to_mail"] + fro = linkahead_config["advancedtools"]["crawler.from_mail"] + to = linkahead_config["advancedtools"]["crawler.to_mail"] except KeyError: logger.error("Server Configuration is missing a setting for " "sending mails. The administrator should check " @@ -646,11 +646,11 @@ carefully and if the changes are ok, click on the following link: @staticmethod def find_or_insert_identifiables(identifiables): """ Sets the ids of identifiables (that do not have already an id from the - cache) based on searching CaosDB and retrieves those entities. + cache) based on searching LinkAhead and retrieves those entities. The remaining entities (those which can not be retrieved) have no - correspondence in CaosDB and are thus inserted. + correspondence in LinkAhead and are thus inserted. """ - # looking for matching entities in CaosDB when there is no valid id + # looking for matching entities in LinkAhead when there is no valid id # i.e. there was none set from a cache existing = [] @@ -699,7 +699,7 @@ carefully and if the changes are ok, click on the following link: else: logger.debug("Did not insert any new entities") - logger.debug("Retrieving entities from CaosDB...") + logger.debug("Retrieving entities from LinkAhead...") identifiables.retrieve(unique=True, raise_exception_on_error=False) @staticmethod @@ -735,7 +735,7 @@ carefully and if the changes are ok, click on the following link: @staticmethod def find_existing(entity): - """searches for an entity that matches the identifiable in CaosDB + """searches for an entity that matches the identifiable in LinkAhead Characteristics of the identifiable like, properties, name or id are used for the match. diff --git a/src/caosadvancedtools/datainconsistency.py b/src/caosadvancedtools/datainconsistency.py index 3af8b5a2..9931dd68 100644 --- a/src/caosadvancedtools/datainconsistency.py +++ b/src/caosadvancedtools/datainconsistency.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com> diff --git a/src/caosadvancedtools/datamodel_problems.py b/src/caosadvancedtools/datamodel_problems.py index df5b7e56..07fef07b 100644 --- a/src/caosadvancedtools/datamodel_problems.py +++ b/src/caosadvancedtools/datamodel_problems.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Florian Sprckelsen <f.spreckelsen@indiscale.com> @@ -27,7 +27,7 @@ be inserted by hand or gueesed from possible exceptions when inserting or updating entities with missing parents and/or properties. """ -from caosdb.exceptions import (EntityDoesNotExistError, +from linkahead.exceptions import (EntityDoesNotExistError, TransactionError, UnqualifiedParentsError, UnqualifiedPropertiesError) diff --git a/src/caosadvancedtools/example_cfood.py b/src/caosadvancedtools/example_cfood.py index 2e395d5c..45984998 100644 --- a/src/caosadvancedtools/example_cfood.py +++ b/src/caosadvancedtools/example_cfood.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -20,7 +20,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db +import linkahead as db from .cfood import AbstractFileCFood, assure_has_property diff --git a/src/caosadvancedtools/export_related.py b/src/caosadvancedtools/export_related.py index 7ae3a4db..1ac6d2cb 100755 --- a/src/caosadvancedtools/export_related.py +++ b/src/caosadvancedtools/export_related.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 IndiScale GmbH, Henrik tom Wörden # @@ -24,7 +24,7 @@ """ This file allows to create an xml representation of a complete dataset. Using the given entity all related entities are collected and saved in a way -that the data can be imported in another CaosDB instance. +that the data can be imported in another LinkAhead instance. Files that are smaller than 1MB are saved in a downloads folder and can be imported along with the entities themselves. @@ -32,9 +32,9 @@ imported along with the entities themselves. import argparse import os -import caosdb as db -from caosdb.apiutils import apply_to_ids, retrieve_entities_with_ids -from caosdb.common.datatype import get_id_of_datatype, is_reference +import linkahead as db +from linkahead.apiutils import apply_to_ids, retrieve_entities_with_ids +from linkahead.common.datatype import get_id_of_datatype, is_reference from lxml import etree @@ -128,7 +128,7 @@ def export(cont, directory="."): xml = etree.tounicode(cont.to_xml( local_serialization=True), pretty_print=True) - with open(os.path.join(directory, "caosdb_data.xml"), "w") as fi: + with open(os.path.join(directory, "linkahead_data.xml"), "w") as fi: fi.write(xml) diff --git a/src/caosadvancedtools/guard.py b/src/caosadvancedtools/guard.py index aa37448d..efda79ed 100644 --- a/src/caosadvancedtools/guard.py +++ b/src/caosadvancedtools/guard.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Henrik tom Wörden # @@ -18,7 +18,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db +import linkahead as db RETRIEVE = 0 INSERT = 1 diff --git a/src/caosadvancedtools/import_from_xml.py b/src/caosadvancedtools/import_from_xml.py index 9d0e03f6..7bc9f018 100755 --- a/src/caosadvancedtools/import_from_xml.py +++ b/src/caosadvancedtools/import_from_xml.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 IndiScale GmbH, Henrik tom Wörden # @@ -31,8 +31,8 @@ import argparse import os from tempfile import NamedTemporaryFile -import caosdb as db -from caosdb.apiutils import apply_to_ids +import linkahead as db +from linkahead.apiutils import apply_to_ids from caosadvancedtools.models.data_model import DataModel diff --git a/src/caosadvancedtools/json_schema_exporter.py b/src/caosadvancedtools/json_schema_exporter.py index c4c6de16..5daa5a4e 100644 --- a/src/caosadvancedtools/json_schema_exporter.py +++ b/src/caosadvancedtools/json_schema_exporter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2023 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2023 Florian Spreckelsen <f.spreckelsen@indiscale.com> diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index cedef367..c9258afa 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -45,7 +45,7 @@ from argparse import ArgumentParser from tempfile import NamedTemporaryFile from typing import Union -import caosdb as db +import linkahead as db logger = logging.getLogger(__name__) timeout_fallback = 20 diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 3be56002..4d4cada2 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -1,7 +1,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -34,7 +34,7 @@ import linkahead.common.models as models from linkahead.apiutils import compare_entities, describe_diff, merge_entities -CAOSDB_INTERNAL_PROPERTIES = [ +LINKAHEAD_INTERNAL_PROPERTIES = [ "description", "name", "unit", @@ -44,19 +44,19 @@ CAOSDB_INTERNAL_PROPERTIES = [ class DataModel(dict): """Provides tools for managing a data model. - When constructing a data model the CaosDB representation can easily be + When constructing a data model the LinkAhead representation can easily be created using the classes RecordType and Propery, storing them in a - Container and inserting it in CaoSDB. However, this has one drawback: You + Container and inserting it in LinkAhead. However, this has one drawback: You cannot simply change someting and update the container. The container will insist on having valid ids for all contained Entities. This class allows you to define your model as easily but also provides you with a method (`sync_data_model`) that will sync with the data model in an - existing CaosDB instance. + existing LinkAhead instance. This is possible because entities, defined in this model, are identified - with entities in CaosDB using names. I.e. a RecordType "Experiment" in this - model will update an existing RecordType with name "Experiment" in CaosDB. + with entities in LinkAhead using names. I.e. a RecordType "Experiment" in this + model will update an existing RecordType with name "Experiment" in LinkAhead. Thus, be carefull not to change existing Entities that were created for a different purpose (e.g. someone else's experiment). @@ -90,9 +90,9 @@ class DataModel(dict): self.append(entity) def sync_data_model(self, noquestion: bool = False, verbose: bool = True): - """Synchronize this DataModel with a CaosDB instance. + """Synchronize this DataModel with a LinkAhead instance. - Updates existing entities from the CaosDB instance and inserts + Updates existing entities from the LinkAhead instance and inserts non-existing entities into the instance. Note: This allows to easily overwrite changes that were made to an existing data model. Use this function with care and double check its effect. @@ -138,7 +138,7 @@ class DataModel(dict): any_change = False for ent in existing_entities: - if ent.name in CAOSDB_INTERNAL_PROPERTIES: + if ent.name in LINKAHEAD_INTERNAL_PROPERTIES: # Workaround for the usage of internal properties like name # in via the extern keyword: ref = db.Property(name=ent.name).retrieve() @@ -171,7 +171,7 @@ class DataModel(dict): @staticmethod def get_existing_entities(entities): """ Return a list with those entities of the supplied iterable that - exist in the CaosDB instance. + exist in the LinkAhead instance. Args ---- diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 175f2f7f..e74de5ac 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -1,4 +1,4 @@ -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -49,7 +49,7 @@ import jsonschema import linkahead as db from linkahead.common.datatype import get_list_datatype -from .data_model import CAOSDB_INTERNAL_PROPERTIES, DataModel +from .data_model import LINKAHEAD_INTERNAL_PROPERTIES, DataModel # Keywords which are allowed in data model descriptions. KEYWORDS = ["importance", @@ -200,7 +200,7 @@ def parse_model_from_json_schema( out : Datamodel The datamodel generated from the input schema which then can be used for - synchronizing with CaosDB. + synchronizing with LinkAhead. Note ---- @@ -301,7 +301,7 @@ debug : bool, optional # Extern keyword: # The extern keyword can be used to include Properties and RecordTypes - # from existing CaosDB datamodels into the current model. + # from existing LinkAhead datamodels into the current model. # Any name included in the list specified by the extern keyword # will be used in queries to retrieve a property or (if no property exists) # a record type with the name of the element. @@ -312,7 +312,7 @@ debug : bool, optional ymlmodel["extern"] = [] for name in ymlmodel["extern"]: - if name in CAOSDB_INTERNAL_PROPERTIES: + if name in LINKAHEAD_INTERNAL_PROPERTIES: self.model[name] = db.Property(name=name).retrieve() continue for role in ("Property", "RecordType", "Record", "File"): @@ -610,7 +610,7 @@ debug : bool, optional iterate over properties and check whether it is a base datatype of a name that was defined in the model (or extern part) - the string representations are replaced with caosdb objects + the string representations are replaced with linkahead objects """ @@ -816,12 +816,12 @@ class JsonSchemaParser(Parser): raise JsonSchemaDefinitionError( f"`type` is missing in element {name}.") if name == "name": - # This is identified with the CaosDB name property as long as the + # This is identified with the LinkAhead name property as long as the # type is correct. if not elt["type"] == "string" and "string" not in elt["type"]: raise JsonSchemaDefinitionError( "The 'name' property must be string-typed, otherwise it cannot " - "be identified with CaosDB's name property." + "be identified with LinkAhead's name property." ) return None, force_list # LinkAhead suports null for all types, so in the very special case of diff --git a/src/caosadvancedtools/pandoc_header_tools.py b/src/caosadvancedtools/pandoc_header_tools.py index e746a26a..e0e62c8c 100644 --- a/src/caosadvancedtools/pandoc_header_tools.py +++ b/src/caosadvancedtools/pandoc_header_tools.py @@ -6,7 +6,7 @@ # A. Schlemmer, 04/2019 # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen diff --git a/src/caosadvancedtools/read_md_header.py b/src/caosadvancedtools/read_md_header.py index ece81c40..cc3e2152 100644 --- a/src/caosadvancedtools/read_md_header.py +++ b/src/caosadvancedtools/read_md_header.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) # A. Schlemmer, 01/2019 @@ -34,7 +34,7 @@ def get_header(fn): # import os # import re -# import caosdb as db +# import linkahead as db # import yaml # from .cfood import AbstractCFood, get_entity diff --git a/src/caosadvancedtools/scifolder/analysis_cfood.py b/src/caosadvancedtools/scifolder/analysis_cfood.py index adce7225..0216f534 100644 --- a/src/caosadvancedtools/scifolder/analysis_cfood.py +++ b/src/caosadvancedtools/scifolder/analysis_cfood.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (AbstractFileCFood, assure_has_property, assure_object_is_in_list, @@ -51,7 +51,7 @@ class AnalysisCFood(AbstractFileCFood, WithREADME): @staticmethod def name_beautifier(name): """ a function that can be used to rename the project. I.e. if - the project in CaosDB shall be named differently than in the folder + the project in LinkAhead shall be named differently than in the folder structure. Use discouraged. """ diff --git a/src/caosadvancedtools/scifolder/experiment_cfood.py b/src/caosadvancedtools/scifolder/experiment_cfood.py index 83329863..b19b2924 100644 --- a/src/caosadvancedtools/scifolder/experiment_cfood.py +++ b/src/caosadvancedtools/scifolder/experiment_cfood.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (AbstractFileCFood, assure_has_property, assure_object_is_in_list, diff --git a/src/caosadvancedtools/scifolder/publication_cfood.py b/src/caosadvancedtools/scifolder/publication_cfood.py index 68e345ac..61e0a0ef 100644 --- a/src/caosadvancedtools/scifolder/publication_cfood.py +++ b/src/caosadvancedtools/scifolder/publication_cfood.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (AbstractFileCFood, assure_object_is_in_list, fileguide, ) diff --git a/src/caosadvancedtools/scifolder/result_table_cfood.py b/src/caosadvancedtools/scifolder/result_table_cfood.py index e32cd0bd..fec29039 100644 --- a/src/caosadvancedtools/scifolder/result_table_cfood.py +++ b/src/caosadvancedtools/scifolder/result_table_cfood.py @@ -18,7 +18,7 @@ import re -import caosdb as db +import linkahead as db import pandas as pd from caosadvancedtools.cfood import (AbstractFileCFood, ) diff --git a/src/caosadvancedtools/scifolder/simulation_cfood.py b/src/caosadvancedtools/scifolder/simulation_cfood.py index f8f3d07e..5127cbfd 100644 --- a/src/caosadvancedtools/scifolder/simulation_cfood.py +++ b/src/caosadvancedtools/scifolder/simulation_cfood.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (AbstractFileCFood, assure_has_property, assure_object_is_in_list, diff --git a/src/caosadvancedtools/scifolder/software_cfood.py b/src/caosadvancedtools/scifolder/software_cfood.py index d91817f1..589112c5 100644 --- a/src/caosadvancedtools/scifolder/software_cfood.py +++ b/src/caosadvancedtools/scifolder/software_cfood.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (AbstractFileCFood, assure_has_property, assure_name_is, assure_object_is_in_list, diff --git a/src/caosadvancedtools/scifolder/utils.py b/src/caosadvancedtools/scifolder/utils.py index cbf87c4b..8e832c10 100644 --- a/src/caosadvancedtools/scifolder/utils.py +++ b/src/caosadvancedtools/scifolder/utils.py @@ -21,7 +21,7 @@ import logging import os from itertools import chain -import caosdb as db +import linkahead as db import pandas as pd from caosadvancedtools.cfood import assure_object_is_in_list, fileguide from caosadvancedtools.utils import (find_records_that_reference_ids, diff --git a/src/caosadvancedtools/scifolder/withreadme.py b/src/caosadvancedtools/scifolder/withreadme.py index d8388e1d..94280b80 100644 --- a/src/caosadvancedtools/scifolder/withreadme.py +++ b/src/caosadvancedtools/scifolder/withreadme.py @@ -22,7 +22,7 @@ import logging import os from dataclasses import dataclass -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (assure_has_description, assure_has_parent, assure_object_is_in_list, fileguide) from caosadvancedtools.read_md_header import get_header as get_md_header diff --git a/src/caosadvancedtools/serverside/examples/example_script.py b/src/caosadvancedtools/serverside/examples/example_script.py index d97d2d0d..fe9bbaa7 100755 --- a/src/caosadvancedtools/serverside/examples/example_script.py +++ b/src/caosadvancedtools/serverside/examples/example_script.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -45,7 +45,7 @@ import sys from argparse import RawTextHelpFormatter from datetime import datetime -import caosdb as db +import linkahead as db import matplotlib.pyplot as plt import numpy as np from caosadvancedtools.cfood import assure_property_is @@ -68,18 +68,18 @@ def send_mail(changes: [db.Entity], receipient: str): Parameters: ----------- - changes: The CaosDB entities in the version after the update. + changes: The LinkAhead entities in the version after the update. receipient: The person who shall receive the mail. """ - caosdb_config = db.configuration.get_config() + linkahead_config = db.configuration.get_config() text = """Dear Curator, The following changes where done automatically. {changes} """.format(changes="\n".join(changes)) try: - fro = caosdb_config["advancedtools"]["automated_updates.from_mail"] + fro = linkahead_config["advancedtools"]["automated_updates.from_mail"] except KeyError: logger.error("Server Configuration is missing a setting for " "sending mails. The administrator should check " diff --git a/src/caosadvancedtools/serverside/generic_analysis.py b/src/caosadvancedtools/serverside/generic_analysis.py index 7c7b26cc..e32e02d0 100644 --- a/src/caosadvancedtools/serverside/generic_analysis.py +++ b/src/caosadvancedtools/serverside/generic_analysis.py @@ -87,8 +87,8 @@ import logging import os import sys -import caosdb as db -from caosdb.utils.server_side_scripting import run_server_side_script +import linkahead as db +from linkahead.utils.server_side_scripting import run_server_side_script logger = logging.getLogger(__name__) diff --git a/src/caosadvancedtools/serverside/helper.py b/src/caosadvancedtools/serverside/helper.py index b7289c7f..ec8083ab 100644 --- a/src/caosadvancedtools/serverside/helper.py +++ b/src/caosadvancedtools/serverside/helper.py @@ -30,7 +30,7 @@ import sys from email import message, policy, utils from tempfile import NamedTemporaryFile -import caosdb as db +import linkahead as db def wrap_bootstrap_alert(text, kind): @@ -165,7 +165,7 @@ def recordtype_is_child_of(rt, parent): Parameters ---------- - rt : caosdb.Entity + rt : linkahead.Entity The child RecordType. parent : str or int The parent's name or id. @@ -193,7 +193,7 @@ def init_data_model(entities): Parameters ---------- - entities : iterable of caosdb.Entity + entities : iterable of linkahead.Entity The data model entities which are to be checked for existence. Raises @@ -339,7 +339,7 @@ def send_mail(from_addr, to, subject, body, cc=None, bcc=None, send_mail_bin=None): """ Send an email via the configured send_mail client. - The relevant options in the pycaosdb.ini are: + The relevant options in the pylinkahead.ini are: [Misc] sendmail = ... @@ -365,8 +365,8 @@ def send_mail(from_addr, to, subject, body, cc=None, bcc=None, ------ subprocess.CalledProcessError If the sendmail client returned with a non-zero code. - caosdb.ConfigurationException - If the caosdb configuration has no `Misc.sendmail` configured while the + linkahead.ConfigurationException + If the linkahead configuration has no `Misc.sendmail` configured while the `send_mail_bin` parameter is None. """ @@ -389,14 +389,14 @@ def send_mail(from_addr, to, subject, body, cc=None, bcc=None, if send_mail_bin is not None: sendmail = send_mail_bin else: - caosdb_config = db.configuration.get_config() + linkahead_config = db.configuration.get_config() - if "Misc" not in caosdb_config or "sendmail" not in caosdb_config["Misc"]: + if "Misc" not in linkahead_config or "sendmail" not in linkahead_config["Misc"]: err_msg = ("No sendmail executable configured. " "Please configure `Misc.sendmail` " - "in your pycaosdb.ini.") + "in your pylinkahead.ini.") raise db.ConfigurationError(err_msg) - sendmail = caosdb_config["Misc"]["sendmail"] + sendmail = linkahead_config["Misc"]["sendmail"] # construct sendmail command # options explained (from `man sendmail`): @@ -438,7 +438,7 @@ def get_file_via_download(ent, logger=logging.getLogger(__name__)): try: # TODO remove the following treatment of size=0 when the # following issue is resolved: - # https://gitlab.com/caosdb/caosdb-server/-/issues/107 + # https://gitlab.com/linkahead/linkahead-server/-/issues/107 if ent.size > 0: val_file = ent.download() @@ -450,7 +450,7 @@ def get_file_via_download(ent, logger=logging.getLogger(__name__)): logger.error("The checksum of the downloaded file with id={} did not " "match.".format(ent.id)) raise e - except db.CaosDBException as e: + except db.LinkAheadException as e: logger.error("Cannot download the file with id={}.".format(ent.id)) raise e diff --git a/src/caosadvancedtools/structure_mapping.py b/src/caosadvancedtools/structure_mapping.py index 50e57ac4..bf446c2a 100644 --- a/src/caosadvancedtools/structure_mapping.py +++ b/src/caosadvancedtools/structure_mapping.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2021 IndiScale GmbH <www.indiscale.com> # Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -18,9 +18,9 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -import caosdb as db -from caosdb.apiutils import resolve_reference -from caosdb.common.utils import uuid +import linkahead as db +from linkahead.apiutils import resolve_reference +from linkahead.common.utils import uuid from .cfood import (assure_has_description, assure_has_parent, assure_property_is) diff --git a/src/caosadvancedtools/table_converter.py b/src/caosadvancedtools/table_converter.py index 7d1097e1..2f0d4cc9 100644 --- a/src/caosadvancedtools/table_converter.py +++ b/src/caosadvancedtools/table_converter.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2019 Henrik tom Wörden # @@ -24,7 +24,7 @@ import argparse import re import sys -import caosdb as db +import linkahead as db import numpy as np import pandas as pd diff --git a/src/caosadvancedtools/table_export.py b/src/caosadvancedtools/table_export.py index eabb1075..00e644e4 100644 --- a/src/caosadvancedtools/table_export.py +++ b/src/caosadvancedtools/table_export.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Florian Sprecklelsen <f.spreckelsen@indiscale.com> @@ -22,7 +22,7 @@ # # ** end header # -"""Collect optional and mandatory data from CaosDB records and prepare +"""Collect optional and mandatory data from LinkAhead records and prepare them for an export as a table, e.g., for the export to metadata repositories. @@ -31,7 +31,7 @@ from inspect import signature import json import logging -import caosdb as db +import linkahead as db FIND_FUNCTION = "find_func" QUERY = "query" @@ -39,7 +39,7 @@ QUERY = "query" logger = logging.getLogger(__name__) -class TableExportError(db.CaosDBException): +class TableExportError(db.LinkAheadException): """Error that is raised in case of failing export, e.g., because of missing mandatory entries. diff --git a/src/caosadvancedtools/utils.py b/src/caosadvancedtools/utils.py index 05000a34..9a0342e9 100644 --- a/src/caosadvancedtools/utils.py +++ b/src/caosadvancedtools/utils.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -27,8 +27,8 @@ import logging import os import pathlib -import caosdb as db -from caosdb.exceptions import TransactionError +import linkahead as db +from linkahead.exceptions import TransactionError logger = logging.getLogger(__name__) diff --git a/src/doc/Makefile b/src/doc/Makefile index 7a1bec10..2df1aff8 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -1,5 +1,5 @@ # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> diff --git a/src/doc/crawler.rst b/src/doc/crawler.rst index d7b351bb..3323631e 100644 --- a/src/doc/crawler.rst +++ b/src/doc/crawler.rst @@ -241,7 +241,7 @@ Let’s look at the following Example: >>> # Example CFood >>> from caosadvancedtools.cfood import AbstractFileCFood, assure_has_property - >>> import caosdb as db + >>> import linkahead as db >>> >>> class ExampleCFood(AbstractFileCFood): ... @staticmethod diff --git a/unittests/create_filetree.py b/unittests/create_filetree.py index f80b9681..bbd7783c 100644 --- a/unittests/create_filetree.py +++ b/unittests/create_filetree.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen diff --git a/unittests/caosdbignore-example b/unittests/linkaheadignore-example similarity index 100% rename from unittests/caosdbignore-example rename to unittests/linkaheadignore-example diff --git a/unittests/test_base_table_exporter.py b/unittests/test_base_table_exporter.py index 8a65b71a..c69a64a0 100644 --- a/unittests/test_base_table_exporter.py +++ b/unittests/test_base_table_exporter.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Florian Sprecklelsen <f.spreckelsen@indiscale.com> @@ -28,7 +28,7 @@ tested without db connection. """ import json import os -import caosdb as db +import linkahead as db from pytest import raises from caosadvancedtools import table_export as te diff --git a/unittests/test_cache.py b/unittests/test_cache.py index de3430bf..1a53f16d 100644 --- a/unittests/test_cache.py +++ b/unittests/test_cache.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2019 Henrik tom Wörden # @@ -26,7 +26,7 @@ from copy import deepcopy from tempfile import NamedTemporaryFile import sqlite3 -import caosdb as db +import linkahead as db from caosadvancedtools.cache import IdentifiableCache, cleanXML from lxml import etree diff --git a/unittests/test_caosdbignore.py b/unittests/test_caosdbignore.py index 9394bf0c..c044a8e8 100644 --- a/unittests/test_caosdbignore.py +++ b/unittests/test_caosdbignore.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2022 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2022 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -34,12 +34,12 @@ from caosadvancedtools.loadFiles import compile_file_list, create_re_for_file_li BASEDIR = os.path.dirname(os.path.realpath(__file__)) -class Caosdbignore(unittest.TestCase): +class Linkaheadignore(unittest.TestCase): def setUp(self): pass def test_compile(self): - files = compile_file_list(os.path.join(BASEDIR, "caosdbignore-example"), + files = compile_file_list(os.path.join(BASEDIR, "linkaheadignore-example"), os.path.join(BASEDIR, "data")) assert len(files) == 3 assert os.path.join(BASEDIR, "data", "datatypes.xlsx") in files diff --git a/unittests/test_cfood.py b/unittests/test_cfood.py index e2f15ffd..77fd654b 100644 --- a/unittests/test_cfood.py +++ b/unittests/test_cfood.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -24,7 +24,7 @@ import re import unittest -import caosdb as db +import linkahead as db from caosadvancedtools.cfood import (AbstractCFood, AbstractFileCFood, CMeal, assure_has_parent, assure_has_property, assure_object_is_in_list, diff --git a/unittests/test_crawler.py b/unittests/test_crawler.py index 64bf291c..15e783a6 100644 --- a/unittests/test_crawler.py +++ b/unittests/test_crawler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -23,7 +23,7 @@ import re import unittest -import caosdb as db +import linkahead as db from caosadvancedtools.crawler import Crawler diff --git a/unittests/test_data_model.py b/unittests/test_data_model.py index cafeb6ca..354e0bf6 100644 --- a/unittests/test_data_model.py +++ b/unittests/test_data_model.py @@ -1,6 +1,6 @@ import unittest -import caosdb as db +import linkahead as db from caosadvancedtools.models.data_model import DataModel from caosadvancedtools.models.parser import parse_model_from_string diff --git a/unittests/test_generic_analysis.py b/unittests/test_generic_analysis.py index a1077b97..3e6f4dbc 100644 --- a/unittests/test_generic_analysis.py +++ b/unittests/test_generic_analysis.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -27,7 +27,7 @@ module description """ -import caosdb as db +import linkahead as db from caosadvancedtools.serverside.generic_analysis import \ check_referenced_script diff --git a/unittests/test_json_schema_exporter.py b/unittests/test_json_schema_exporter.py index 1cea2f58..fd6dbf7c 100644 --- a/unittests/test_json_schema_exporter.py +++ b/unittests/test_json_schema_exporter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2023 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2023 Florian Spreckelsen <f.spreckelsen@indiscale.com> diff --git a/unittests/test_json_schema_model_parser.py b/unittests/test_json_schema_model_parser.py index a991076e..cdd4c074 100644 --- a/unittests/test_json_schema_model_parser.py +++ b/unittests/test_json_schema_model_parser.py @@ -1,5 +1,5 @@ # -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> @@ -24,7 +24,7 @@ import os import pytest -import caosdb as db +import linkahead as db from caosadvancedtools.models.parser import (parse_model_from_json_schema, JsonSchemaDefinitionError) @@ -357,7 +357,7 @@ def test_name_property(): broken = parse_model_from_json_schema(os.path.join( FILEPATH, "datamodel_name_wrong_type.schema.json")) assert str(err.value).startswith( - "The 'name' property must be string-typed, otherwise it cannot be identified with CaosDB's " + "The 'name' property must be string-typed, otherwise it cannot be identified with LinkAhead's " "name property.") diff --git a/unittests/test_read_md_header.py b/unittests/test_read_md_header.py index 994f8f16..71873e05 100644 --- a/unittests/test_read_md_header.py +++ b/unittests/test_read_md_header.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2019 Henrik tom Wörden # @@ -25,7 +25,7 @@ import unittest from copy import deepcopy from tempfile import NamedTemporaryFile -import caosdb as db +import linkahead as db from caosadvancedtools.read_md_header import get_header diff --git a/unittests/test_result_table_cfood.py b/unittests/test_result_table_cfood.py index 3341a239..ad0d6397 100644 --- a/unittests/test_result_table_cfood.py +++ b/unittests/test_result_table_cfood.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen @@ -32,7 +32,7 @@ import os import re import unittest -import caosdb as db +import linkahead as db from caosadvancedtools.scifolder.result_table_cfood import ResultTableCFood diff --git a/unittests/test_sss_helper.py b/unittests/test_sss_helper.py index 71408fa6..c040f503 100644 --- a/unittests/test_sss_helper.py +++ b/unittests/test_sss_helper.py @@ -3,13 +3,13 @@ from email import message_from_file, policy from os import listdir, remove from os.path import abspath, dirname, exists, isfile, join -import caosdb as db +import linkahead as db from caosadvancedtools.serverside.helper import (NameCollector, get_data, get_file_via_download, init_data_model, parse_arguments, send_mail) -from caosdb import RecordType, configure_connection, get_config -from caosdb.connection.mockup import MockUpResponse, MockUpServerConnection +from linkahead import RecordType, configure_connection, get_config +from linkahead.connection.mockup import MockUpResponse, MockUpServerConnection from pytest import mark, raises @@ -110,8 +110,8 @@ def test_get_file_via_download(): # TODO test whether something ends up in the logger class NotThere(DummyFile): def download(*args, **kwargs): - raise db.CaosDBException() - with raises(db.CaosDBException): + raise db.LinkAheadException() + with raises(db.LinkAheadException): get_file_via_download(Inconsistent()) diff --git a/unittests/test_structure_mapping.py b/unittests/test_structure_mapping.py index 5cc4114f..a426cf78 100644 --- a/unittests/test_structure_mapping.py +++ b/unittests/test_structure_mapping.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2021 IndiScale GmbH <www.indiscale.com> # Copyright (C) 2021 Henrik tom Wörden <h.tomwoerden@indiscale.com> @@ -22,10 +22,10 @@ import unittest from os import name -import caosdb as db +import linkahead as db from caosadvancedtools.structure_mapping import (EntityMapping, collect_existing_structure) -from caosdb.common import datatype +from linkahead.common import datatype class structureMappingTest(unittest.TestCase): diff --git a/unittests/test_suppressKnown.py b/unittests/test_suppressKnown.py index 07c2e18e..6f87e842 100644 --- a/unittests/test_suppressKnown.py +++ b/unittests/test_suppressKnown.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 IndiScale GmbH # Copyright (C) 2020 Henrik tom Wörden diff --git a/unittests/test_table_converter.py b/unittests/test_table_converter.py index 9b1ac11b..b4f0c4d3 100644 --- a/unittests/test_table_converter.py +++ b/unittests/test_table_converter.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2019 Henrik tom Wörden # @@ -24,9 +24,9 @@ import os import unittest from tempfile import NamedTemporaryFile -import caosdb as db +import linkahead as db import pandas as pd -from caosdb.apiutils import compare_entities +from linkahead.apiutils import compare_entities from numpy import nan from caosadvancedtools.table_converter import (from_table, from_tsv, to_table, diff --git a/unittests/test_update_cache.py b/unittests/test_update_cache.py index 8376da48..318a35ae 100644 --- a/unittests/test_update_cache.py +++ b/unittests/test_update_cache.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2020 Henrik tom Wörden # @@ -26,7 +26,7 @@ import unittest from copy import deepcopy from tempfile import NamedTemporaryFile -import caosdb as db +import linkahead as db from caosadvancedtools.cache import UpdateCache, get_pretty_xml diff --git a/unittests/test_utils.py b/unittests/test_utils.py index 468e9200..09688f97 100644 --- a/unittests/test_utils.py +++ b/unittests/test_utils.py @@ -2,7 +2,7 @@ # encoding: utf-8 # # ** header v3.0 -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2019 Henrik tom Wörden # @@ -24,12 +24,12 @@ import logging import unittest from tempfile import NamedTemporaryFile -import caosdb as db +import linkahead as db from caosadvancedtools.utils import (check_win_path, get_referenced_files, string_to_person, create_entity_link) -from caosdb import RecordType, configure_connection, get_config -from caosdb.connection.mockup import MockUpResponse, MockUpServerConnection -from caosdb.exceptions import TransactionError +from linkahead import RecordType, configure_connection, get_config +from linkahead.connection.mockup import MockUpResponse, MockUpServerConnection +from linkahead.exceptions import TransactionError class BaseMockUpTest(unittest.TestCase): diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index 9ca92a1d..f8e27507 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -1,4 +1,4 @@ -# This file is a part of the CaosDB Project. +# This file is a part of the LinkAhead project. # # Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2023 Daniel Hornung <d.hornung@indiscale.com> -- GitLab From 612208e7ad2e3ab22cb62f1783b463416244ae49 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Thu, 14 Nov 2024 13:34:35 +0100 Subject: [PATCH 035/106] WIP STY: More renaming CaosDB -> LinkAhead --- src/caosadvancedtools/datamodel_problems.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/caosadvancedtools/datamodel_problems.py b/src/caosadvancedtools/datamodel_problems.py index 07fef07b..d14a384b 100644 --- a/src/caosadvancedtools/datamodel_problems.py +++ b/src/caosadvancedtools/datamodel_problems.py @@ -28,9 +28,9 @@ or updating entities with missing parents and/or properties. """ from linkahead.exceptions import (EntityDoesNotExistError, - TransactionError, - UnqualifiedParentsError, - UnqualifiedPropertiesError) + TransactionError, + UnqualifiedParentsError, + UnqualifiedPropertiesError) class DataModelProblems(object): -- GitLab From 472799d9bf8e68909f02546341a9461975eb7527 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Thu, 14 Nov 2024 13:57:21 +0100 Subject: [PATCH 036/106] DOC: Changelog. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 624c2b29..d97250f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed ### +- Using the official name "LinkAhead" wherever possible without large effort. This includes the + following exposed names / features: + - `models.data_model.LINKAHEAD_INTERNAL_PROPERTIES` + - `export_related.export` exports to `linkahead_data.xml` now. + ### Deprecated ### ### Removed ### -- GitLab From d0f4f3f5ba5c6fc314bafc9bdf66b7f0450a8f16 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 15 Nov 2024 20:39:21 +0100 Subject: [PATCH 037/106] MNT: Implement review feedback, extend test, some more comments --- .../table_json_conversion/convert.py | 108 ++++++++++-------- .../data/simple_data_broken.xlsx | Bin 9175 -> 9133 bytes .../data/simple_data_broken_paths.xlsx | Bin 0 -> 9175 bytes .../table_json_conversion/test_read_xlsx.py | 32 +++++- 4 files changed, 89 insertions(+), 51 deletions(-) create mode 100644 unittests/table_json_conversion/data/simple_data_broken_paths.xlsx diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 37c39aae..3bc25556 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -25,6 +25,7 @@ from __future__ import annotations import datetime import itertools import sys +import textwrap from functools import reduce from operator import getitem from types import SimpleNamespace @@ -95,65 +96,52 @@ def _format_exception_table(exceptions: list[tuple], worksheet_title: str, exceptions.sort(key=lambda tup: tup[1]) for row_i, col_i, excep in exceptions: if column_names is not None: - # Update Names + # Add a line with information about the current column if current_column != col_i: current_column = col_i new_data.append({ "loc": f"\nErrors in column '{column_names[col_i]}':", "type": "", "mess": [""] }) - # Setup - row = {} - new_data.append(row) - # Field + # Setup for current Exception + curr_err_data = {} + new_data.append(curr_err_data) + # Get field if isinstance(row_i, int): - row["loc"] = f"Cell {_column_id_to_chars(col_i)}{row_i + 1}" + curr_err_data["loc"] = f"Cell {_column_id_to_chars(col_i)}{row_i + 1}" else: - row["loc"] = f"Column {_column_id_to_chars(col_i)}" - lengths["loc"] = max(lengths["loc"], len(row["loc"])) - # Code - row["type"] = type(excep).__name__ - lengths["type"] = max(lengths["type"], len(row["type"])) - # Message + curr_err_data["loc"] = f"Column {_column_id_to_chars(col_i)}" + lengths["loc"] = max(lengths["loc"], len(curr_err_data["loc"])) + # Add error code + curr_err_data["type"] = type(excep).__name__ + lengths["type"] = max(lengths["type"], len(curr_err_data["type"])) + # Format message - split into lines lines = str(excep).split('\n') new_lines = [] for line in lines: - if len(line) > max_line_length: - words = line.split(' ') - current = "" - for word, next_word in zip(words, words[1:] + [""]): - if current != "": - current += " " - current += word - if len(current + next_word) > max_line_length: - lengths["mess"] = max(lengths["mess"], len(current)) - new_lines.append(current) - current = "" - if current != "": - lengths["mess"] = max(lengths["mess"], len(current)) - new_lines.append(current) - elif len(line) > 0: - lengths["mess"] = max(lengths["mess"], len(line)) - new_lines.append(line) + new_lines += textwrap.wrap(line, max_line_length, break_long_words=False) + for line in new_lines: + lengths["mess"] = max(lengths["mess"], len(line)) if new_lines == []: new_lines = [""] - row["mess"] = new_lines + curr_err_data["mess"] = new_lines + # Generate underline for each header dividers = {key: '–' * l for key, l in lengths.items()} dividers["mess"] = [dividers["mess"]] - - # Fill for the messages is set to 0, if we want another column or align - # right we need to use lengths["mess"] + # Fill with spaces for alignment string_rep = f"There were errors during the validation of worksheet '{worksheet_title}':\n\n" - for row in [headers, dividers] + new_data: - string_rep += ' {loc: <{fill}} '.format(loc=row["loc"], + for curr_err_data in [headers, dividers] + new_data: + string_rep += ' {loc: <{fill}} '.format(loc=curr_err_data["loc"], fill=lengths["loc"]) - string_rep += ' {typ: <{fill}} '.format(typ=row["type"], + string_rep += ' {typ: <{fill}} '.format(typ=curr_err_data["type"], fill=lengths["type"]) - string_rep += ' {mes: <{fill}}\n'.format(mes=row["mess"][0], fill=0) - for line in row["mess"][1:]: - # Front padding - string_rep += ' ' * (lengths["loc"] + lengths["type"] + 7) + # Fill for the messages is set to 0, if we want another column or align + # right we need to use lengths["mess"] + string_rep += ' {mes: <{fill}}\n'.format(mes=curr_err_data["mess"][0], fill=0) + for line in curr_err_data["mess"][1:]: + # Front padding for lines without location and error type + string_rep += ' ' * (lengths["loc"] + lengths["type"] + 6) string_rep += ' {mes: <{fill}}\n'.format(mes=line, fill=0) return string_rep @@ -194,7 +182,11 @@ class XLSXConverter: self._workbook = load_workbook(xlsx) self._schema = read_or_dict(schema) self._defining_path_index = xlsx_utils.get_defining_paths(self._workbook) - self._check_columns(fail_fast=strict) + try: + self._check_columns(fail_fast=strict) + except KeyError as e: + raise jsonschema.ValidationError(f"Malformed metadata: Cannot parse paths. " + f"Unknown path: {e}") from e self._handled_sheets: set[str] = set() self._result: dict = {} self._errors: dict = {} @@ -220,9 +212,29 @@ class XLSXConverter: self._handled_sheets = set() self._result = {} self._errors = {} - for sheetname in self._workbook.sheetnames: - if sheetname not in self._handled_sheets: - self._handle_sheet(self._workbook[sheetname], fail_later=collect_errors) + if not collect_errors: + for sheetname in self._workbook.sheetnames: + if sheetname not in self._handled_sheets: + self._handle_sheet(self._workbook[sheetname], fail_later=collect_errors) + else: + # Collect errors from converting + exceptions = [] + for sheetname in self._workbook.sheetnames: + if sheetname not in self._handled_sheets: + try: + self._handle_sheet(self._workbook[sheetname], fail_later=collect_errors) + except jsonschema.ValidationError as e: + exceptions.append(e) + # do not collect errors from sheet again + self._handled_sheets.add(sheetname) + if len(exceptions) == 1: + raise exceptions[0] + elif len(exceptions) > 1: + mess = "There were errors during the validation of several worksheets:\n\n" + mess += '\n\n'.join([str(e).replace("There were errors during the validation of worksheet", + "In worksheet") + for e in exceptions]) + raise jsonschema.ValidationError(mess) if validate: jsonschema.validate(self._result, self._schema) if self._errors: @@ -323,6 +335,7 @@ class XLSXConverter: # entries: dict[str, list[SimpleNamespace]] = {} exceptions = [] + warns = [] col_names = {} for row_idx, row in enumerate(sheet.iter_rows(values_only=True)): # Skip non-data rows @@ -359,7 +372,12 @@ class XLSXConverter: _set_in_nested(mydict=data, path=path, value=value, prefix=parent, skip=1) continue elif sheet.cell(col_type_row+1, col_idx+1).value is None: - warn(f"No metadata configured for column {_column_id_to_chars(col_idx)}.") + mess = (f"\nNo metadata configured for column " + f"'{_column_id_to_chars(col_idx)}' in worksheet " + f"'{sheet.title}'.\n") + if mess not in warns: + print(mess, file=sys.stderr) + warns.append(mess) # Prevent multiple instances of same warning except (ValueError, KeyError, jsonschema.ValidationError) as e: # Append error for entire column only once if isinstance(e, KeyError) and 'column' in str(e): diff --git a/unittests/table_json_conversion/data/simple_data_broken.xlsx b/unittests/table_json_conversion/data/simple_data_broken.xlsx index 0221570c942fc28f2b59a282f751781ff4a504fa..a65d464a53459de73e41fd20d807899c44728cda 100644 GIT binary patch delta 6686 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 delta 6811 zcmZWu1yohtwx+vFIu3{K?oR0r0qK%%5O8x4kvw!a5>g^9NJt4BO1gwYBOoFmT@StQ z-RFPr+GDM~_ZoBVF~^E;efyg=Dsw8hI_k(MBnTK77znx+?sd3eMC6BigCL?l((i|q z7-SB>3>y;@*Cm<V7A9ViUAbabGueoajw2@|ETEP1Yi=AJ8PeCeKUt|+<>~h-R2tX` zk(Ne#cX)HzSvVF9s?2RbrIb2KR4^Gy$+gG+wf*8YFfv!oCfy1~VOoe>@#SPo`$UbF zwRMRIM6(4k#BNNhzgh6B3RK53ms(@8#(E62vc5O4NNP1?!_Z=<C!MAVe!5B~>gXiq z_|e8<5Egw29YUoHU{-;@&`xc(3a38cUXM;brm|MFiZS0<-SzzW2JknRzV<m?Z*rGv zAfK(u2$;ZLMjLl$bQ9ASlVH!KcQYBQN*D{)FjTB13&$?L=16jJW8?OI{^c_t`8pRs zmIliyn~`g*!lr(1tWfKbSe84<ttmYjxz*mMN7OxAxgmIPtx!Q0Sy4afzUOt%Cr*69 zOQ|iBr{k5)QV5C_-RdD+aDdF7Her1l-KLHzUIfM+AJueLn7V&Zoi20U5tFYOdhDI+ z6}g+^4bju!2p6BKy+L+~9~NV(Ft7#`^WE0CgD{_cNNv}NPe+z-+<8~jGY~N;F%R*W z+9*3poeF*4X=}2qOGVWvqIpoUyINoJS_qv*@4Kq)MJX*mZ;exaU3e}|2-62}T{Rtj zQ;^uefvn@O(w%N=r1wxZF7`N8)_~RIi4qhXe3`9Y-NC9!hr)fBR;O+=mMjju@2RXA zT=*E=IVNFJTJhaZG<D!mbu#Abc69NXa@+MUu>K04_8aw+>2H#n2Jo-r24-mRgv=w& zIHi&P;C<%p|GS9zi0`vkQd1@jE3(YfvX6u+FuUr=TkbF4$!rJ1kEYaRHqLijk2~|n zQ|~%Lr-0JNTN3~y6wsQK4$Zi663bb^I#4HFyfAXQ&21eWE(+M3>R?5hZV>l0Xpsdz zC9xcox-|?}jAZ?2-HC{Lgz7$!P=*}t!6XU<0RbgevRH8?c?1#tuc0TtpRy$TDEhK- z1GP2VjTQTz;fkw?7JhrvYs*hc2fd%BNq5&ye!CmvDj-V!3)sV+FOTXRiHhF{`st#K z(9mDU_TKB0yRyUVW#Gz441&X%!^TK8_4}Np!IyMq)B-F989`;%->&7XhTlqmm(nL# zI3`2McRX>JLc=kmj{0@)?Plo~{7TXsy;&&qt-Py1lX0<I*_k=A&Dhe>&0R>7o0p&i z)V7KyK8xTjn}FrOxwWC&qN~I_G@=L>@<edXi6GPPHR4U?+(5H>hz!mshUW-Y2t4wW zdn2PTYGHTe#c421D(J<>1D|E7yDINX9vyXbj1@(%u|Z@6ghOfsgnw-M6jdBBz{efv z=GtMR>9a0M&~aGndC6N&<BF3Bw#|geS~Ux&lq8R6&8$Rl*&4bIGY%zg&UvWceM-t@ zk}yl7Mrg{n4CqQPl<3|W;B4~G^pZcxlA`|5{OTl884Mr$et2G$z|!203S&&2q#pmy zGIB6}0uPt6$CvCjF_BF?$;!h3baTb<@QHI7qzh5UtXax96_C<h_kV_4lT^H}pFT35 z3*cAu{%9j=>#<hor6J#5Vx6^SZUDw9SCzexWI*+pr+p)Gq=a+8FvFa$6*c^<e2WT- z+Zh)T=S>+ar`jMcC@`$Q^Ghi|VdPq<Yz;+knb4H2mSMQ3#V(8COoxmPfP6$K6$Ue{ zKW1_rNA3rDt20ZG8axEUK?AH?<Y!oo{Q)K+Jky;Y%0;Z4n)8BIr}4*MM#)Oq*^%`g zjY!kw*Mvsvgmq!8oQyffviNp|U%*I?BDE;y;uJH$16HKf)$uL9U4^^GUyz{A0UI7T z#X@Mx&6tXT(Y6zMSdFbfFB={z^y!CIZY8XzKl1BwHO(S12HtACibK57ot+OLI35`* z&1dtRl)o}r6-*0SG-9m-!jJ)1v+-1i00uR=(xQF;S>rvgW%ko{MeRm|w&{<@&)ir; z6PbthVeA!xC7r0rbMK)&%>*U^A7Zx0C*Hce&2PHUHY93YNY~H<0%SyHOe++SXWlg- z(7Z@g1rscIt`=yp)TrsC)|#l{nXMpng7b^W<4e=Cjrc9sX|xb)i+2~pI$&c#Yaz5@ zCFUJ!Uit<<wQhTov9o7%4N=upN!Hp;{iIkkD4s{qujOs-<;AiX(&@B~y78y2-#8{n zMbnyJHK}*`?b4b9SIGAUGjCu`S1>uGQDo(FGW|6}D2M42OZ5IGdUjv^aN|ba`j;i8 zB0-6*-dN+_?|*E&uYR`+5n7LpCht__go4sl2p_2sR$;AmLQU?edJu!m;ycb~<^{Y@ z1miXPRHrUjZGuR=yh!SfaZrW&78T>Jg=jl!KfifHnG+Qal+{K56nd~Tn3`A2b)rnb zLDl~K`sLtJ&`l>OVN|_xxtoVs(Re}e8+#6hg*|amm87uHG+tjDI{#iq&~YcfHgxza zGKCAJ5J7p8oy~UDjKebW(KXZ2eF3=kHmtL3sK+=dXnC+vq3%1xseHW{z1X5N%|mr{ zH)DMF26*-;Zgag&$0sUHwic_Qx2R>A_Ug$p(yiZ;p^kFCGq+A#*cw`c7CsVjHhod+ znt|q(NMADwb$R8rAG-cbWu4lF1E$oQ?4QgljkhnaT;GO;|2hCyZb=jLrN)dcI-^I_ zhc!2T`VN&;$ne2}`8}}`5*4(t>u@zwSxP3E(*Q1`ze#s#d%nP3=*hA|Nj6Mb9^qys z#vybH6k)@n8$0=?BCjYBYr;F=cXdb521gy;j2g7x$+z9j@M5?=sN!E*t?XtOd%Ek; zK{6cvDIrs%q@uf<Xfk|t+uQJ2O{%hy;yU?WDt14B(ZFY^GSUCTlVck(zW7;B79eYS z<ZM>-ROW`W;=&idfwbkFm3vz$1q|rwHzUtAX{zv47}q=8f%vQ@r5Xx$sj?YX1bUEo zXp)I8YgjMbaai5q|Hd~>l)$6+C<q8z1pke14;;p4QIuo=ey$&Q^JO7#!N%3c4Wfm` z!0@U}fAV0YldYLru#U@^EOB${T(#56j%mz4XOqEdcgN?lfYG||TdxHPrNoGy{6?K~ z%VHVCHsK1~Ns$A8x9x#mmgG%x&04}on{zHIB%^Uhe!%uoQ-s_H8K-Y|{;Owxdqef~ z60nL<%9XuJ?tlaX^{pi@n>hFI9&c&tI*A?lkH-*1kB;<6oKaH=Vnn@moL*8E-OeJ6 zROn;4@l{A}eDA*_Gn_yEg;tMiy&^(%*g-AWzubWbMEiyfH*olkF6|Sk;UXbP*a=ju z%VFq;e5C}4eT(EX=upg5IcnKGrNv4D5h#84SoNYqV?H;o<d$ayLv@hPOqVW(x{$Y@ zH=~fM{qv0(Xy=mj774k(QHa9yax^7LyO0*d|8mXBHGlrl2w6^bl`j0;d8;GI{o4z? zBR7RqvhB@P3dXzSK5}KTrR|rNyD!vweZC+qHi{qdpiRUeD!U64tP!EN3l2@3QUb5% zH|A?s0$R5iL`~r;bAp_>7oxIDiLnHqXzcqh@IbUVb%_EfDT0LDWuiC(+atob+V8R7 z!}l{kBbQDrDlkOZwJfFWk01N{84R{6p8Imx4>|V3+RA<z;b4Ar(*<X}N)(Z^A>G!^ zL<^sw87nr$tDIY?QNB_jvlA1YRtL!6b@HeQWY8d&j-?@xb`lqO&~tyB**|^VA=hQL zhhiu;An%ju|77(Fu~Ii~^J+@t8`H`fK_G>WAC9EmrKt*{hBEy#_IvCgh18PbuvT4< z9B<04BzvYs0{DQJm*FYBh4MGN@Caj~;ki`!FcxIi{>1^5;G0bFH2Asa?k2!Z6R$q! zys!*EoE)`iqs-9yI0Ha9C0d7}TJtYleqKxY`y^Q8sgw(aK)~0n!}(gqCNw;WTl4{9 zUq1R?cfq%K1H`6VzqfpSL@?|AXurP3OFS@1@W7iV&`!YfDQLn*<h|b#<e=HLRl!lh z@(d+hG&_!bnM$KLYsWQ(GY_CSgKuc^zKp%SNQ$pZrvY>2=3!WrXnzoSHL+YGRqqdK z&%H2V`EF~os5(L!Jte-zI@mrjXv*ldqRL4b9jm;q&sgUQHqs^}YgAj{8LK*r)vryN z<e`+8D;piGrVw*e-X0w^74Tk(<IGNqb=cGwsCQL1(gvy2Y;-=`{{Y0-=(Dt`?Kru9 zcxV!#lVX&LUV?M<Ql&oGNhc0=6LIEFiJcF<c7?uBGz#{-6FW|oys4m>v0XvGv34z1 zRH-WBXLWlK#mB{3tf1Pxh^1MM`OxNYl?28vcI%cqui}vPkZQ)gy(;3SnR2=5Kh;>p z{Iuce%eU9f0Ge)(g%bhOS8UA>dwWy#|Ej|T<&^5iaEXq&gS@9chfV}a1I{#FX{4f4 z^fA*XEHpIH)As;K>MZI$Q*G*nRA4El1Er#K_>}mhF74p>UR2Fn-*<AUCS;U~(OdGw zu~#K#O6wzP>ZT*ZabD`oyos;XPPbWxPj?FdAii4mWXsmD<xujNTrzOk8=!RJ5BLhr zz9~$;Y5H+JQ|bQp?1O`0ClhmA-wl7#!0Kl-Mz0ru=#vgH>Z(dc7jy1gT>DMPXX;n_ z)IKBZmd^t+z1C+~s=vntzM98H94L|uacj9cE=;tiB+JNUK1PpxH^p;LKkNdN^IRTL z2J$axaZpl^VNHhl+8)G=a+nS-$6*b<u`t4F$rkQ0zLVkO)k(pKXm#e>3tu`*H_s5v z1^H15h}{-Gwyi)>oPeTe1QqD;41Ct*fx(l|gIiDpt7~}O>#4?ggssG`1>Ioua>Rs8 z#(u#v#Al?{#7Osh{k{HXhu@`_MGgT541{QzJohxjv%I?7{qbcWh4A$D`(Vg1n$pm9 z#m)WpK>G2yF}SDVh~hB5R#5&3Zh15+tjL*@ntMQgd}?P$^Bp6_RItlQk2=87zf1LF zYh9AzC<*s4Je^qv@i+Q6b-y8-LPbC*p!^T?H%0heQnYYr0fB#UTnqgrQIb%&<=T-# zL9>^1F1}MT9vJK!Nrv{#-vLfy1{E4i=U~J9xqq&97sW`WVJ0k@s46bKv*KevV7xJ& zK-koriQTgvz3klNhCM)g^0+;J9)9?UPNkU%922T&8pm=*Om?=jYq>$Qfe-34c_K>? z8%?8@1>}lDf67xcOxR#Tt(mMO<%uFg4x%D#H}_*fd%jBt5Ml<RCAMBR02>_}X?;!X zM3@k2uhzq-MAY+$;j!Y_*|)Cf@f|1hitVFR`P_02RLg;ypGtij8t-MBCCTiI3>zf9 zwD68YHkaYHd%qZFxOCI@w(XM6(>WRY=!Az<fK{ze6{JOq(z_7{yCx@aPY!wmo4d42 zolOK?h&7j-OUUc3bH&=>V1H!d%X$GCiG}{Dx`$JMoj-QN%BH|iD}(XXmoNZhC3-SI zJ;Jpm>_V6%I#)}ZTkNP-HO|`TSW`G?*k3@IryF~|Z0i-kmzl2ZS&zri!$Cb5u2(z* z(3H)m%*!OUuBc+M2WU^kOoVq2ATH`u*dR!KKDp$IkgT)aVnNkPXN{*QGuU!A%kO!C z2!XhmjmIek&=#-il`nJ0ckK?3nr`ioKDVJdP;ahuuOYR?f2MZSY?$Ut34^0lEb+!Z zaNH4hFUnE-a!D<orao;8LK6<GvZ!GIezM5<D;@I0Q7a5vCW=QPs%nZdF7mdAk#&g4 zD6&_t1vMeckyS}Lg<@1MrS>P8{-=E_n9ryD?T3GM?E$N|U+&YINSKNZq&yhGvGs2! zk0bidy>b&^SWo!n69~W|$tD2SWl0sX^rP0(*RWhmqw2@LJPX6%kABH-&gXmp0jU<{ z+BuiJ_AVP4{qJ)Q^Ly=G>-756(`<NV_b;n@HM}ljs<hgyrz~;76TTx0W9yXJdu72N z6Bpsa$~bJ|T?tR;zoc!_JC>H^E6K<9G$A>(Or6ayR9^7+1(B}#<1;ik47OwKQiHfD z31gM}j)fwS(H?OJB<y>)5M`_Z<3YGRzO5Ae9+BpP3S^^+TUCk3<-r4fZFApzaf=;A zEs(u%%c}_HtXiESIkOptjTz9jJ`VUTx_Li;s`LvtwlWH`rbEgnh*JqtKE3;uu&>>9 z#mP@=yu;SVH8(r&*gzR&z244lw`i`EDQrwwHfq?1EsPI!IVoJ&X73XMjthhowuR)~ zJCJ*2d{#>XVly~J>5N{AREktV;^H**kj41?ACpdstdOM(B|dr)uA<`aJpEmdbW(ux z!&_@Ui%R*c?QuukKHnj>4oc?SzGLx;9a19<DX!?bYudn$LtvERTW_q0@#i6dSf*kD zYK5t%&&QW-xTB3NJSQFQ0FHGRq#lESp@Uf+5kE;T1?h+ty#kcekG<>o_2zt-LRDs% zelDFX800CXb^6p`S0X1%;*rBaf%eA*VLqisrgXfUw+_Ob*&0iFBy;Bb7p{-suSGi} zU9Fcqk%sn&3#0RRxy3+V$ZJ`TX~%5tRaEV~9IP*?)5g#xol+b*0X>z+@_rXbkk*rk zPZ9}OTmgPE8+8#@76F6Yqd-wZa|jX2Y6$0}h}aGTzR-i~M@zRgyfgxE?Q!8UI-S&z z?A?317w(xizS<zpYL7t2<$8>M0KR@23CibwW?t^HJKj*&u%nymEZFt90?MSfLN%I` z6rbl^#><I^SbmR4^BX70f)8+y9$2y}$$#KvL**mpKiXf)6gdl^?Xf6J(0_PK!a?^u zRx|2}VKiSctDq{Fp8j=i@#ynUON$?Wj8XQqjEkp6>i^=rT$Sk(k&qC0;V&LiqgKZ_ zu$V39OK}d8Q(iF7IiP=TuFd^IF}y>tm9wTu&X*n<xsZ{%5KAv48HIJYzYn%H)L{~9 z7Rvf*XKTR}`oVVzh;UKi-w7Wywx2va?PN)tW+s9Oe|~M>Wua8ecjck5v61J=sBY@G zd(A#)u1-pZZ=LxSTI?!WAXQsH*5bV0An4q!y*d*pNX5nA%l8CsZN-`;M9{`PNT^6@ zYQ3s#)Fvs}dt-DsxO(x`t#pF31FhxT5*OBJk4bktJAIM^fRS_eJd>wRnZrz&G`+6Q z=}^&3*jfbSs>k`*Gy~hC9~+ajY*8OtqY^y9(9s-aagkO|GrN>NO)lP1Ap4ajt&~Ro zn`_$>+gAbI^x>Ftp0tYyka&*n<E|U#tvbZ5GCY>-n%-nL>N}g6$)FlvF5JwxH?Z*j zM6<Z-c}pA#U@)t!$~f<_#NupLeZ$K<=ZUt)l`mQ=LsU0iN%7XF8{TMjmiBI!W$=AV zi(lNmM_3hS*P+##?@Wi1ZR|Nz{dhvX8d&kFNrk=eXR+BdUcM?o;lYREEw-Y_FtM~m zS+iW!hH*hu+wZ%hY(=yXp~gB<325O3tPtjwD<6a$?%4RTg9{ci?Sc-A#}_OkD-Vhh zItG4{o;yAg0)j5qf2^GpZYnS^q1D4n5_-;&-sxc>B0CkA#7aa5<|BM_RMVWHyWCdB zMGttibjvav9pndVX&>&o317a0Ss{OhJ&7lbwjl{yZ%V8rf0NPA*)9k1)4(*E#ro`o zPNsQW73TtTLDnvtwaP`I3S_iro3m~7*3ysTvXtw0-6Vyj3@;jt1UUg%)fD$OsH<S8 z$_JzY6dxRs$f6%K6DxW@SM+K%7br2HMG;u34Vj84bWL~~_B^ysS;Y2C%UZokyO8fQ zaHF%H1Ai*FDWkm|mJ7GLi?7PKrO)zXkYNqC^r=)<c#5mIP65l1AkD+FSPEE*C`E)9 z5%VsH!B@1z>n49qW(T0^efLgt<-N+P3t~D|MIPK*<?dOaIlp1`?aLjcp50K6U9(Yk zb%*7zJfUoIUw<64=@Y?Li-e!m#NZTgT!qYZo?FVw%k!HgM&J=;<7p$&;w*~cxZ0f% zpX}=fyCmcg_}?C3e)Yo)UUgxyz_hs5$qyaBLH|83A~D<V{7DcI5cVD>=bzHv95o}* z?cT$S6L}aM!@j;)Qq$I>L)qxOi0Lfh>(s)oZZVk3tZS<ibdCBY>?EZA)~w*5pth_V zj86X2znNKVR29jnRcpyjQ#z-`S1vhh(tlDETS!cvp5y3~jPj1PA}&KT3e~fEg<tBQ z!xy{hk>l&*)eb+)*>DbU`GnSzwu?6bbe}*R_0=}K4D)zx)0U7;d2`yIU0=p3rb4Z! zs6#g~S3a%AD-z@`Pkt^EjHi{|T+k<Z#{`_MI5F`(2hCmuN1UG!370eFP1!Wh`pYy~ z##YwAHr)&3wQs`YjT{;>I)p8rc>3c@B#As~P`XoXAm4#>(K?D)_WzMRZOPHCFRmXb zVD7^J{c~^#X=nZ<J9cT`{R{cB>4pC!J*Mcz@g9;NrvERQrcg0((f#iFTV){sLoNTW z2}^NgVEJS7Hy8b<jeknb|JwYG!~e8NNI79(`4a{Whzjv@iWrFP&sYE6eGlOMS2;|9 zfEa<_(fwHo|GN+f|FS?pkflOEu=B9h@%Hfa;j#7bw*SqAb<`1&ND%&={V}!uYp5Pn zl)uX9gJ}G3cWY12|MsSFH(i@W2+MeII(n$Ye>o!{aHq&Jg6MxoC_YUl;QkQdCfa}6 QpwXp-Gcuty(f{`RAI8aq-2eap diff --git a/unittests/table_json_conversion/data/simple_data_broken_paths.xlsx b/unittests/table_json_conversion/data/simple_data_broken_paths.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0221570c942fc28f2b59a282f751781ff4a504fa GIT binary patch literal 9175 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 XiBuJ!pGO237}Cr3>~{@hFIWEqzzhRX literal 0 HcmV?d00001 diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index 8fbf8a2a..f51e114f 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -113,27 +113,47 @@ def test_missing_columns(): assert expected in messages -def test_wrong_datatype(): +def test_error_table(): with pytest.raises(jsonschema.ValidationError) as caught: convert.to_dict(xlsx=rfp("data/simple_data_broken.xlsx"), schema=rfp("data/simple_schema.json")) # Correct Errors + assert "Malformed metadata: Cannot parse paths in worksheet 'Person'." in str(caught.value) assert "'Not a num' is not of type 'number'" in str(caught.value) + assert "'Yes a number?' is not of type 'number'" in str(caught.value) assert "1.5 is not of type 'integer'" in str(caught.value) + assert "1.2345 is not of type 'integer'" in str(caught.value) + assert "'There is no entry in the schema" in str(caught.value) + assert "'Not an enum' is not one of [" in str(caught.value) # Correct Locations for line in str(caught.value).split('\n'): if "'Not a num' is not of type 'number'" in line: assert "J7" in line + if "'Yes a number?' is not of type 'number'" in line: + assert "J8" in line if "1.5 is not of type 'integer'" in line: assert "K7" in line if "1.2345 is not of type 'integer'" in line: assert "K8" in line - # No additional type errors - if "is not of type 'boolean'" in str(caught.value): # ToDo: Remove when boolean is fixed - assert str(caught.value).count("is not of type") == 3 + if "'There is no entry in the schema" in line: + assert "Column M" in line + if "'Not an enum' is not one of [" in line: + assert "G8" in line + # No additional errors + assert str(caught.value).count("Malformed metadata: Cannot parse paths in worksheet") == 1 + assert str(caught.value).count("There is no entry in the schema") == 1 + assert str(caught.value).count("is not one of") == 1 + # FIXME ToDo: Remove when boolean is fixed / when everything works as + # expected, set correct number. + if "is not of type 'boolean'" in str(caught.value): + assert str(caught.value).count("is not of type") == 6 else: - assert str(caught.value).count("is not of type") == 2 # FIXME when everything works as - # # expected, set correct number. + assert str(caught.value).count("is not of type") == 4 + # Check correct error message for completely unknown path + with pytest.raises(jsonschema.ValidationError) as caught: + convert.to_dict(xlsx=rfp("data/simple_data_broken_paths.xlsx"), + schema=rfp("data/simple_schema.json")) + assert "Malformed metadata: Cannot parse paths" in str(caught.value) def test_additional_column(): -- GitLab From dc5554d06b1b1141a34e38c14de8dbf4171ffb2b Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 11:06:27 +0100 Subject: [PATCH 038/106] STY(yaml-model-parser): formatting of test --- unittests/test_yaml_model_parser.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index 79a7c6a3..5df3b8ea 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -742,10 +742,11 @@ RT: datatype: TEXT """) - existing_entities = [db.RecordType(name="RT", id=25).add_property(name="identifier", - datatype="INTEGER", - importance="OBLIGATORY", - id=24), + existing_entities = [db.RecordType( + name="RT", id=25).add_property(name="identifier", + datatype="INTEGER", + importance="OBLIGATORY", + id=24), db.Property(name="identifier", datatype="INTEGER", id=24)] def get_existing_entities(ent_cont): -- GitLab From d753df87fc6d345f87a7354cdfd2d94b8ef3d966 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 11:46:38 +0100 Subject: [PATCH 039/106] TST(yaml-model-parser): unit test for data model comparison --- unittests/test_yaml_model_parser.py | 53 ++++++++++++++++++----------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index 5df3b8ea..e645dcd6 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -30,8 +30,6 @@ from caosadvancedtools.models.parser import (TwiceDefinedException, from linkahead.apiutils import compare_entities from pytest import mark, raises -from unittests.mock import Mock - def to_file(string): f = NamedTemporaryFile(mode="w", delete=False) @@ -676,12 +674,14 @@ test_reference: # comparison with a version taken from a LinkAhead instance will have these attributes. # Furthermore, RT2 will be set as the datatype **in object version** in the yaml definition, while # it is an ID in case of the version from the LinkAhead instance. + # p_foo = db.Property(name="foo", datatype="INTEGER", description="bla bla", unit="m") + # rt2 = db.RecordType(name="RT2") + # rt1 = db.RecordType(name="RT1") + # rt1.add_property(p_foo) + # rt1.add_property(rt2) - p_foo = db.Property(name="foo", datatype="INTEGER", description="bla bla", unit="m") - rt2 = db.RecordType(name="RT2") - rt1 = db.RecordType(name="RT1") - rt1.add_property(p_foo) - rt1.add_property(rt2) + # existing_entities = [ + # p_foo, rt2, rt1] server_response = """ <Entities> @@ -710,26 +710,39 @@ test_reference: c2 = compare_entities(model["RT1"], entities[1]) c3 = compare_entities(model["RT2"], entities[2]) c4 = compare_entities(model["test_reference"], entities[3]) + for cs in (c1, c2, c3, c4): - assert "id" not in cs[0] + assert "id" in cs[0] + assert cs[0]["id"] is None assert "id" in cs[1] + assert cs[1]["id"] is not None - mq = Mock() - - def mq_init(self, query): - self.query = query + # The server response would be the same as the xml above: + def get_existing_entities(ent_cont): + return entities - def mq_execute(self, unique=True): - pass + class MockQuery: + def __init__(self, q): + self.q = q - mq.__init__ = mq_init - mq.execute.side_effect = mq_execute + def execute(self, unique=True): + id = int(self.q.split("=")[1]) + for existing_ent in entities: + if existing_ent.id == id: + return existing_ent + return None - caosadvancedtools.models.parser.db.Query = mq + model.get_existing_entities = get_existing_entities + caosadvancedtools.models.parser.db.Query = MockQuery + caosadvancedtools.models.parser.db.Container.update = Mock() + caosadvancedtools.models.parser.db.Container.insert = Mock() model.sync_data_model(True, True) - - stdout, stderr = capfd.readouterr() + assert caosadvancedtools.models.parser.db.Container.update.called + assert not caosadvancedtools.models.parser.db.Container.insert.called + output, err = capfd.readouterr() + print(output) + assert False # TODO: test that there were no changes required @@ -766,9 +779,11 @@ RT: model.get_existing_entities = get_existing_entities caosadvancedtools.models.parser.db.Query = MockQuery caosadvancedtools.models.parser.db.Container.update = Mock() + caosadvancedtools.models.parser.db.Container.insert = Mock() model.sync_data_model(True, True) assert caosadvancedtools.models.parser.db.Container.update.called + assert not caosadvancedtools.models.parser.db.Container.insert.called output, err = capfd.readouterr() print(output) assert "version from the yaml file: TEXT" in output -- GitLab From dd637a408f32ae4ba2dae6bd6799c1fca368b7e8 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 11:51:39 +0100 Subject: [PATCH 040/106] FIX(yaml-model-parser): add datatype and other missing attributes to properties belonging to record types in data model --- src/caosadvancedtools/models/parser.py | 70 +++++++++++++------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index b3c5c7e2..27505329 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -37,18 +37,17 @@ to be a list with the names. Here, NO NEW entities can be defined. """ import argparse import json -import jsonref import re import sys -import yaml - from typing import List, Optional from warnings import warn +import jsonref import jsonschema import linkahead as db - +import yaml from linkahead.common.datatype import get_list_datatype + from .data_model import LINKAHEAD_INTERNAL_PROPERTIES, DataModel # Keywords which are allowed in data model descriptions. @@ -341,38 +340,37 @@ debug : bool, optional f"invalid keyword in line {entity['__line__']}:", 1) raise ValueError(err_str, *err.args[1:]) from err - # TODO: functionality commented out, to be able to test failing test first. - # Update properties that are part of record types: - # e.g. add their datatypes, units etc.. - # Otherwise comparison of existing models and the parsed model become difficult. - # for name, ent in self.model.items(): - # if not isinstance(ent, db.RecordType): - # continue - # props = ent.get_properties() - # for prop in props: - # if prop.name in self.model: - # model_prop = self.model[prop.name] - # # The information must be missing, we don't want to overwrite it accidentally: - # if prop.datatype is not None and prop.datatype != model_prop.datatype: - # # breakpoint() - # raise RuntimeError("datatype must not be set, here. This is probably a bug.") - # if prop.unit is not None and prop.unit != model_prop.unit: - # # continue - # raise RuntimeError("unit must not be set, here. This is probably a bug.") - # if prop.description is not None and prop.description != model_prop.description: - # # continue - # raise RuntimeError("description must not be set, here. This is probably a bug.") - # - # # If this property has a more detailed definition in the model, - # # copy over the information: - # - # if isinstance(model_prop, db.RecordType): - # # in this case the datatype equals the name of the record type: - # prop.datatype = prop.name - # else: - # prop.datatype = model_prop.datatype - # prop.unit = model_prop.unit - # prop.description = model_prop.description +# Update properties that are part of record types: +# e.g. add their datatypes, units etc.. +# Otherwise comparison of existing models and the parsed model become difficult. + for name, ent in self.model.items(): + if not isinstance(ent, db.RecordType): + continue + props = ent.get_properties() + for prop in props: + if prop.name in self.model: + model_prop = self.model[prop.name] + # The information must be missing, we don't want to overwrite it accidentally: + if prop.datatype is not None and prop.datatype != model_prop.datatype: + # breakpoint() + raise RuntimeError("datatype must not be set, here. This is probably a bug.") + if prop.unit is not None and prop.unit != model_prop.unit: + # continue + raise RuntimeError("unit must not be set, here. This is probably a bug.") + if prop.description is not None and prop.description != model_prop.description: + # continue + raise RuntimeError("description must not be set, here. This is probably a bug.") + + # If this property has a more detailed definition in the model, + # copy over the information: + + if isinstance(model_prop, db.RecordType): + # in this case the datatype equals the name of the record type: + prop.datatype = prop.name + else: + prop.datatype = model_prop.datatype + prop.unit = model_prop.unit + prop.description = model_prop.description return DataModel(self.model.values()) -- GitLab From d75f64686d3ebc943f9b753c8d8b623e27d44471 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 11:52:04 +0100 Subject: [PATCH 041/106] TST(yaml-model-parser): test for correct comparison of yaml models --- unittests/test_yaml_model_parser.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index e645dcd6..e3e9a0af 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -674,14 +674,6 @@ test_reference: # comparison with a version taken from a LinkAhead instance will have these attributes. # Furthermore, RT2 will be set as the datatype **in object version** in the yaml definition, while # it is an ID in case of the version from the LinkAhead instance. - # p_foo = db.Property(name="foo", datatype="INTEGER", description="bla bla", unit="m") - # rt2 = db.RecordType(name="RT2") - # rt1 = db.RecordType(name="RT1") - # rt1.add_property(p_foo) - # rt1.add_property(rt2) - - # existing_entities = [ - # p_foo, rt2, rt1] server_response = """ <Entities> @@ -738,13 +730,11 @@ test_reference: caosadvancedtools.models.parser.db.Container.insert = Mock() model.sync_data_model(True, True) - assert caosadvancedtools.models.parser.db.Container.update.called + assert not caosadvancedtools.models.parser.db.Container.update.called assert not caosadvancedtools.models.parser.db.Container.insert.called output, err = capfd.readouterr() - print(output) - assert False - - # TODO: test that there were no changes required + assert "No new entities." in output + assert "No differences found. No update" in output def test_sync_output(capfd): -- GitLab From 0c25885d62026b47e2c6f7f6fd49d333b72d3e28 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 13:00:48 +0100 Subject: [PATCH 042/106] FIX(yaml-model-parser): removed data type check --- src/caosadvancedtools/models/parser.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 27505329..fb8f75ab 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -352,14 +352,14 @@ debug : bool, optional model_prop = self.model[prop.name] # The information must be missing, we don't want to overwrite it accidentally: if prop.datatype is not None and prop.datatype != model_prop.datatype: - # breakpoint() - raise RuntimeError("datatype must not be set, here. This is probably a bug.") + continue + # TODO: Data type overwrite is allowed here (because + # of lists), but this might change in the future. + # raise RuntimeError("datatype must not be set, here. This is probably a bug.") if prop.unit is not None and prop.unit != model_prop.unit: - # continue - raise RuntimeError("unit must not be set, here. This is probably a bug.") + continue if prop.description is not None and prop.description != model_prop.description: - # continue - raise RuntimeError("description must not be set, here. This is probably a bug.") + continue # If this property has a more detailed definition in the model, # copy over the information: -- GitLab From 18ccd72dcfbeea1e62affa9d1fa1e3e32650fbe1 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 13:01:21 +0100 Subject: [PATCH 043/106] TST(data-model-parser): replaced static xml tests by more specific ones --- unittests/test_yaml_model_parser.py | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index e3e9a0af..cf999789 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -612,14 +612,13 @@ RT2: obligatory_properties: *RT1_oblig """ model = parse_model_from_string(model_string) - assert str(model) == """{'foo': <Property name="foo" datatype="INTEGER"/> -, 'RT1': <RecordType name="RT1"> - <Property name="foo" importance="OBLIGATORY" flag="inheritance:FIX"/> -</RecordType> -, 'RT2': <RecordType name="RT2"> - <Property name="foo" importance="OBLIGATORY" flag="inheritance:FIX"/> -</RecordType> -}""" + + assert len(model) == 3 + assert isinstance(model["foo"], db.Property) + assert model["foo"].datatype == db.INTEGER + for st in ("RT1", "RT2"): + assert isinstance(model[st], db.RecordType) + assert model[st].get_property("foo").datatype == db.INTEGER # Aliasing with override model_string = """ @@ -634,16 +633,13 @@ RT2: bar: """ model = parse_model_from_string(model_string) - assert str(model) == """{'foo': <Property name="foo" datatype="INTEGER"/> -, 'RT1': <RecordType name="RT1"> - <Property name="foo" importance="OBLIGATORY" flag="inheritance:FIX"/> -</RecordType> -, 'RT2': <RecordType name="RT2"> - <Property name="foo" importance="OBLIGATORY" flag="inheritance:FIX"/> - <Property name="bar" importance="OBLIGATORY" flag="inheritance:FIX"/> -</RecordType> -, 'bar': <RecordType name="bar"/> -}""" + + assert len(model) == 4 + assert isinstance(model["bar"], db.RecordType) + for st in ("RT1", "RT2"): + assert isinstance(model[st], db.RecordType) + assert model[st].get_property("foo").datatype == db.INTEGER + assert model["RT2"].get_property("bar").datatype == "bar" def test_comparison_yaml_model(capfd): -- GitLab From f2bfc455bf5f3770fc4543057f722c0ec5421886 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 13:26:00 +0100 Subject: [PATCH 044/106] MAINT(json-schema-export): added error detection when datatype is given as string --- src/caosadvancedtools/json_schema_exporter.py | 8 ++++++- unittests/test_json_schema_exporter.py | 24 +++++++++---------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/caosadvancedtools/json_schema_exporter.py b/src/caosadvancedtools/json_schema_exporter.py index 5daa5a4e..7a92eaad 100644 --- a/src/caosadvancedtools/json_schema_exporter.py +++ b/src/caosadvancedtools/json_schema_exporter.py @@ -58,8 +58,9 @@ from collections import OrderedDict from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union import linkahead as db -from linkahead.cached import cached_query, cache_clear +from linkahead.cached import cache_clear, cached_query from linkahead.common.datatype import get_list_datatype, is_list_datatype + from .models.data_model import DataModel @@ -322,6 +323,10 @@ ui_schema : dict rt = results[0] else: rt = db.Entity() + + if isinstance(rt, str): + raise NotImplementedError("Behavior is not implemented when _no_remote == True and datatype is given as a string.") + subschema, ui_schema = self._make_segment_from_recordtype(rt) if prop.is_reference(): if prop.name: @@ -431,6 +436,7 @@ ui_schema : dict } } """ + schema: OrderedDict[str, Any] = OrderedDict({ "type": "object" }) diff --git a/unittests/test_json_schema_exporter.py b/unittests/test_json_schema_exporter.py index fd6dbf7c..3b37f638 100644 --- a/unittests/test_json_schema_exporter.py +++ b/unittests/test_json_schema_exporter.py @@ -23,18 +23,16 @@ """Tests the Json schema exporter.""" import json - -import linkahead as db -import caosadvancedtools.json_schema_exporter as jsex - from collections import OrderedDict - -from jsonschema import FormatChecker, validate, ValidationError -from pytest import raises from unittest.mock import Mock, patch -from caosadvancedtools.json_schema_exporter import recordtype_to_json_schema as rtjs +import caosadvancedtools.json_schema_exporter as jsex +import linkahead as db +from caosadvancedtools.json_schema_exporter import \ + recordtype_to_json_schema as rtjs from caosadvancedtools.models.parser import parse_model_from_string +from jsonschema import FormatChecker, ValidationError, validate +from pytest import raises GLOBAL_MODEL = parse_model_from_string(""" RT1: @@ -920,10 +918,12 @@ RT3: schema_noexist = rtjs(model.get_deep("RT3")) assert schema_noexist["properties"]["NoRecords"].get("type") == "object" - schema_noexist_noremote = rtjs(model.get_deep("RT3"), no_remote=True) - assert schema_noexist_noremote["properties"]["NoRecords"].get("type") == "object" - assert (schema_noexist_noremote["properties"]["NoRecords"].get("properties") - == OrderedDict([('some_text', {'type': 'string'})])) + with raises(NotImplementedError, + match="Behavior is not implemented when _no_remote == True and datatype is given as a string."): + schema_noexist_noremote = rtjs(model.get_deep("RT3"), no_remote=True) + assert schema_noexist_noremote["properties"]["NoRecords"].get("type") == "object" + assert (schema_noexist_noremote["properties"]["NoRecords"].get("properties") + == OrderedDict([('some_text', {'type': 'string'})])) uischema = {} schema_noexist_noretrieve = rtjs(model.get_deep("RT2"), do_not_retrieve=["RT1"], -- GitLab From e613db9a5420747b173734ff10c63874cc3aecfe Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 13:26:30 +0100 Subject: [PATCH 045/106] TST(yaml-model-parser): updated test to new behavior --- unittests/test_data_model.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unittests/test_data_model.py b/unittests/test_data_model.py index 354e0bf6..174f15fc 100644 --- a/unittests/test_data_model.py +++ b/unittests/test_data_model.py @@ -44,7 +44,10 @@ RT1: """ model_recursive = parse_model_from_string(model_recursive_str) prop1 = model_recursive["RT1"].get_property("RT1") - assert prop1.datatype is None + + assert prop1.datatype is not None + assert prop1.datatype == "RT1" + # TODO The next line actually changes model_recursive in place, is this OK? RT1 = model_recursive.get_deep("RT1") assert model_recursive["RT1"] == RT1 -- GitLab From dd6cf0846f4e4f8182fe9458a56b01e65998577c Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <a.schlemmer@indiscale.com> Date: Mon, 18 Nov 2024 13:32:13 +0100 Subject: [PATCH 046/106] DOC(yaml-model-parser): updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d97250f2..3b7e7185 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### +- Yaml data model parser adds data types of properties of record types and other attributes which fixes https://gitlab.indiscale.com/caosdb/customers/f-fit/management/-/issues/58 + ### Security ### ### Documentation ### -- GitLab From 1a6a00ab40d773b70b41a43ee768c8f54975b54f Mon Sep 17 00:00:00 2001 From: Daniel Hornung <d.hornung@indiscale.com> Date: Tue, 19 Nov 2024 09:22:05 +0100 Subject: [PATCH 047/106] ENH: Even better error message. --- .../table_json_conversion/convert.py | 13 +++++++------ unittests/table_json_conversion/test_read_xlsx.py | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 3bc25556..bffab78e 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -186,7 +186,8 @@ class XLSXConverter: self._check_columns(fail_fast=strict) except KeyError as e: raise jsonschema.ValidationError(f"Malformed metadata: Cannot parse paths. " - f"Unknown path: {e}") from e + f"Unknown path: '{e.args[1]}' in sheet '{e.args[0]}'." + ) from e self._handled_sheets: set[str] = set() self._result: dict = {} self._errors: dict = {} @@ -270,8 +271,11 @@ class XLSXConverter: parents[xlsx_utils.p2s(col.path[:-1])] = col.path[:-1] col_paths.append(col.path) for path in parents.values(): - subschema = xlsx_utils.get_subschema(path, self._schema) - + try: + subschema = xlsx_utils.get_subschema(path, self._schema) + except KeyError as kerr: + kerr.args = (sheetname, *kerr.args) + raise # Unfortunately, there are a lot of special cases to handle here. if subschema.get("type") == "array": subschema = subschema["items"] @@ -544,9 +548,6 @@ def _group_foreign_paths(foreign: list[list], common: list[str]) -> list[SimpleN last_level = len(elem.path) resultlist.append(elem) - # from IPython import embed - # embed() - if last_level != len(common): raise ValueError("Foreign keys must cover the complete `common` depth.") return resultlist diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index f51e114f..ac0a42b5 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -153,7 +153,8 @@ def test_error_table(): with pytest.raises(jsonschema.ValidationError) as caught: convert.to_dict(xlsx=rfp("data/simple_data_broken_paths.xlsx"), schema=rfp("data/simple_schema.json")) - assert "Malformed metadata: Cannot parse paths" in str(caught.value) + assert ("Malformed metadata: Cannot parse paths. Unknown path: 'There' in sheet 'Person'." + == str(caught.value)) def test_additional_column(): -- GitLab From 008b1bcf9caee57ea69ab907e5d0c23f0dc96364 Mon Sep 17 00:00:00 2001 From: Daniel Hornung <d.hornung@indiscale.com> Date: Tue, 19 Nov 2024 09:35:41 +0100 Subject: [PATCH 048/106] DOC: if and only if --- src/caosadvancedtools/table_json_conversion/xlsx_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/caosadvancedtools/table_json_conversion/xlsx_utils.py b/src/caosadvancedtools/table_json_conversion/xlsx_utils.py index 7efe15c8..7770e3ec 100644 --- a/src/caosadvancedtools/table_json_conversion/xlsx_utils.py +++ b/src/caosadvancedtools/table_json_conversion/xlsx_utils.py @@ -295,7 +295,7 @@ def is_exploded_sheet(sheet: Worksheet) -> bool: """Return True if this is a an "exploded" sheet. An exploded sheet is a sheet whose data entries are LIST valued properties of entries in another - sheet. A sheet is detected as exploded if it has FOREIGN columns. + sheet. A sheet is detected as exploded if and only if it has FOREIGN columns. """ column_types = _get_column_types(sheet) return ColumnType.FOREIGN.name in column_types.values() -- GitLab From 5f8ef3fe9ae284e9c7ed9d0c973e104c420204b2 Mon Sep 17 00:00:00 2001 From: Daniel Hornung <d.hornung@indiscale.com> Date: Tue, 19 Nov 2024 09:59:27 +0100 Subject: [PATCH 049/106] MAINT: Explicit dependencies for testing and documentation. --- .gitlab-ci.yml | 4 ++-- setup.py | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f9702235..cc0a1f73 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -139,9 +139,9 @@ unittest_py38: stage: unittest image: python:3.8 script: &python_test_script - - pip install pynose pandas pytest pytest-cov gitignore-parser openpyxl>=3.0.7 xlrd==1.2 h5py + - pip install pynose pandas - pip install git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev - - pip install . + - pip install .[test,h5-crawler,gitignore-parser] - pytest --cov=caosadvancedtools unittests unittest_py310: diff --git a/setup.py b/setup.py index a7146ead..08908baa 100755 --- a/setup.py +++ b/setup.py @@ -165,13 +165,21 @@ def setup_package(): ], extras_require={"h5-crawler": ["h5py>=3.3.0", ], "gitignore-parser": ["gitignore-parser >=0.1.0", ], + "doc": [ + "sphinx", + "sphinx-autoapi", + "sphinx-rtd-theme", + "recommonmark >= 0.6.0", + ], + "test": [ + "gitignore-parser", + "pytest", + "pytest-pythonpath", + "pytest-cov", + "coverage>=4.4.2", + ], }, setup_requires=["pytest-runner>=2.0,<3dev"], - tests_require=["pytest", - "pytest-pythonpath", - "pytest-cov", - "coverage>=4.4.2", - ], packages=find_packages('src'), package_dir={'': 'src'}, entry_points={"console_scripts": [ -- GitLab From 3cb23ce97ea61ef3ee9890c07ecb53551790c17c Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 19 Nov 2024 11:55:21 +0100 Subject: [PATCH 050/106] STY: Added type definition. --- src/caosadvancedtools/table_json_conversion/convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index bffab78e..3c5b78fa 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -104,7 +104,7 @@ def _format_exception_table(exceptions: list[tuple], worksheet_title: str, "type": "", "mess": [""] }) # Setup for current Exception - curr_err_data = {} + curr_err_data: Any = {} new_data.append(curr_err_data) # Get field if isinstance(row_i, int): -- GitLab From ed483239a7eade92fa2fb656a3ecc66448c443b6 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Tue, 19 Nov 2024 14:36:26 +0100 Subject: [PATCH 051/106] STY: autopep8'd --- src/caosadvancedtools/models/data_model.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 1067a09c..92afb7eb 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -114,8 +114,6 @@ class DataModel(dict): self.sync_ids_by_name(tmp_exist) - - if len(non_existing_entities) > 0: if verbose: print("New entities:") -- GitLab From bc112cf6f2ac96950b3a0c3b98c23c938c694de7 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Tue, 19 Nov 2024 15:18:08 +0100 Subject: [PATCH 052/106] FIX: Don't ignore top-level description or unit if datatype is given --- src/caosadvancedtools/models/parser.py | 33 +++++++++++--------------- unittests/test_yaml_model_parser.py | 25 +++++++++++++++++-- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index fb8f75ab..b1e3aa95 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -351,25 +351,20 @@ debug : bool, optional if prop.name in self.model: model_prop = self.model[prop.name] # The information must be missing, we don't want to overwrite it accidentally: - if prop.datatype is not None and prop.datatype != model_prop.datatype: - continue - # TODO: Data type overwrite is allowed here (because - # of lists), but this might change in the future. - # raise RuntimeError("datatype must not be set, here. This is probably a bug.") - if prop.unit is not None and prop.unit != model_prop.unit: - continue - if prop.description is not None and prop.description != model_prop.description: - continue - - # If this property has a more detailed definition in the model, - # copy over the information: - - if isinstance(model_prop, db.RecordType): - # in this case the datatype equals the name of the record type: - prop.datatype = prop.name - else: - prop.datatype = model_prop.datatype - prop.unit = model_prop.unit + if prop.datatype is None: + if isinstance(model_prop, db.RecordType): + prop.datatype = model_prop.name + else: + prop.datatype = model_prop.datatype + # TODO: Data type overwrite is allowed here (because + # of lists), but this might change in the future. + # elif prop.datatype != model_prop.datatype: + # raise RuntimeError("datatype must not be set, here. This is probably a bug.") + if prop.unit is None: + # No unit for plain reference properties + if not isinstance(model_prop, db.RecordType): + prop.unit = model_prop.unit + if prop.description is None: prop.description = model_prop.description return DataModel(self.model.values()) diff --git a/unittests/test_yaml_model_parser.py b/unittests/test_yaml_model_parser.py index cf999789..8728e128 100644 --- a/unittests/test_yaml_model_parser.py +++ b/unittests/test_yaml_model_parser.py @@ -657,9 +657,11 @@ RT1: obligatory_properties: foo: RT2: + datatype: LIST<RT2> test_reference: RT2: + description: Describe RT2 test_reference: datatype: RT2 @@ -681,10 +683,10 @@ test_reference: <RecordType id="2273" name="RT1"> <Version id="0c1b9df6677ee40d1e1429b2123e078ee6c863e0" head="true"/> <Property id="2272" name="foo" description="bla bla" datatype="INTEGER" unit="m" importance="OBLIGATORY" flag="inheritance:FIX"/> - <Property id="2274" name="RT2" datatype="RT2" importance="OBLIGATORY" flag="inheritance:FIX"/> + <Property id="2274" name="RT2" description="Describe RT2" datatype="LIST<RT2>" importance="OBLIGATORY" flag="inheritance:FIX"/> <Property id="2275" name="test_reference" datatype="RT2" importance="OBLIGATORY" flag="inheritance:FIX"/> </RecordType> - <RecordType id="2274" name="RT2"> + <RecordType id="2274" name="RT2" description="Describe RT2"> <Version id="185940642680a7eba7f71914dd8dd7758dd13faa" head="true"/> </RecordType> <Property id="2275" name="test_reference" datatype="RT2"> @@ -699,13 +701,32 @@ test_reference: c3 = compare_entities(model["RT2"], entities[2]) c4 = compare_entities(model["test_reference"], entities[3]) + # Make sure the mock response matches the datamodel definiton + # exactly, i.e., they only differ in ids which are None for all + # entities from the datamodel and not None for the mocked + # response. for cs in (c1, c2, c3, c4): assert "id" in cs[0] assert cs[0]["id"] is None + assert cs[0]["parents"] == [] + for name, val in cs[0]["properties"].items(): + # Also properties differ in ids: The one from the + # datamodel have None + assert len(val) == 1 + assert "id" in val + assert val["id"] is None assert "id" in cs[1] assert cs[1]["id"] is not None + assert cs[1]["parents"] == [] + for name, val in cs[1]["properties"].items(): + # Also properties differ in ids: The one from the + # mock response have not None + assert len(val) == 1 + assert "id" in val + assert val["id"] is not None # The server response would be the same as the xml above: + def get_existing_entities(ent_cont): return entities -- GitLab From 92644ba4f92edf900967511e3962be213917d6a3 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Sat, 23 Nov 2024 15:39:53 +0100 Subject: [PATCH 053/106] BUG: convert.XLSXConverter._validate_and_convert now parses booleans that were retrieved as integer or a formula --- src/caosadvancedtools/table_json_conversion/convert.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 3c5b78fa..f775709a 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -478,6 +478,12 @@ class XLSXConverter: if isinstance(value, datetime.date) and ( {'type': 'string', 'format': 'date'} in subschema["anyOf"]): return value + # booleans might be retrieved as an integer or formula + if subschema.get('type') == 'boolean': + if value == 0 or isinstance(value, str) and 'false' in value.lower(): + value = False + if value == 1 or isinstance(value, str) and 'true' in value.lower(): + value = True jsonschema.validate(value, subschema) # Finally: convert to target type -- GitLab From 1056109870169a2d4e029a1c07d40bdc358082d7 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Sat, 23 Nov 2024 15:41:10 +0100 Subject: [PATCH 054/106] TST: test_read_xlsx..test_error_table now fails if boolean is not parsed correctly --- unittests/table_json_conversion/test_read_xlsx.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index ac0a42b5..cd5d53dd 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -143,12 +143,7 @@ def test_error_table(): assert str(caught.value).count("Malformed metadata: Cannot parse paths in worksheet") == 1 assert str(caught.value).count("There is no entry in the schema") == 1 assert str(caught.value).count("is not one of") == 1 - # FIXME ToDo: Remove when boolean is fixed / when everything works as - # expected, set correct number. - if "is not of type 'boolean'" in str(caught.value): - assert str(caught.value).count("is not of type") == 6 - else: - assert str(caught.value).count("is not of type") == 4 + assert str(caught.value).count("is not of type") == 4 # Check correct error message for completely unknown path with pytest.raises(jsonschema.ValidationError) as caught: convert.to_dict(xlsx=rfp("data/simple_data_broken_paths.xlsx"), -- GitLab From dce79e16be5be0b087405858933ccae02d97e300 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Mon, 25 Nov 2024 13:26:52 +0100 Subject: [PATCH 055/106] DOC: Changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d97250f2..aa1511c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### * Official support for Python 3.13 +* New setup extras `test` and `doc` which install the dependencies for testing and documentation. ### Changed ### -- GitLab From 2f34d766793a160c7a356417e79942eed9f267fe Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 09:30:15 +0100 Subject: [PATCH 056/106] MAINT: Pipeline cleanup. --- .gitlab-ci.yml | 3 +-- CHANGELOG.md | 5 ++++- setup.py | 9 ++++++--- tox.ini | 14 ++++---------- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cc0a1f73..0e953065 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -139,9 +139,8 @@ unittest_py38: stage: unittest image: python:3.8 script: &python_test_script - - pip install pynose pandas - pip install git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev - - pip install .[test,h5-crawler,gitignore-parser] + - pip install .[all] - pytest --cov=caosadvancedtools unittests unittest_py310: diff --git a/CHANGELOG.md b/CHANGELOG.md index aa1511c8..18647b88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### * Official support for Python 3.13 -* New setup extras `test` and `doc` which install the dependencies for testing and documentation. ### Changed ### @@ -17,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 following exposed names / features: - `models.data_model.LINKAHEAD_INTERNAL_PROPERTIES` - `export_related.export` exports to `linkahead_data.xml` now. +- Renamed (and added) installation "extra" options: + - `h5` instead of `h5-crawler` + - `doc`, `test` and `all` are new, they install the dependencies for testing, documentation and + everything. ### Deprecated ### diff --git a/setup.py b/setup.py index 08908baa..747324fb 100755 --- a/setup.py +++ b/setup.py @@ -163,7 +163,7 @@ def setup_package(): "pandas>=1.2.0", "xlrd>=2.0", ], - extras_require={"h5-crawler": ["h5py>=3.3.0", ], + extras_require={"h5": ["h5py>=3.3.0", ], "gitignore-parser": ["gitignore-parser >=0.1.0", ], "doc": [ "sphinx", @@ -171,13 +171,16 @@ def setup_package(): "sphinx-rtd-theme", "recommonmark >= 0.6.0", ], - "test": [ - "gitignore-parser", + "test": [ # include: h5, gitignore-parser "pytest", "pytest-pythonpath", "pytest-cov", "coverage>=4.4.2", + "caosadvancedtools[h5, gitignore-parser]", ], + "all": [ # include: doc, test + "caosadvancedtools[doc, test]", + ] }, setup_requires=["pytest-runner>=2.0,<3dev"], packages=find_packages('src'), diff --git a/tox.ini b/tox.ini index a7e06bf5..12c7ad50 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,12 @@ [tox] -envlist=py38, py39, py310, py311, py312, py313 +envlist = py38, py39, py310, py311, py312, py313 skip_missing_interpreters = true [testenv] -deps=nose - pandas +deps = git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev - pytest - pytest-cov - gitignore-parser - openpyxl >= 3.0.7 - xlrd == 1.2 - h5py -commands=py.test --cov=caosadvancedtools --cov-report=html:.tox/cov_html -vv {posargs} +extras = test +commands = py.test --cov=caosadvancedtools --cov-report=html:.tox/cov_html -vv {posargs} [flake8] max-line-length=100 -- GitLab From 8773ccbecbc61d34ea6890573d01f474a3cf82a4 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 12:36:36 +0100 Subject: [PATCH 057/106] FIX: Dockerfile --- .docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 5b26c03c..f028bbb1 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -29,6 +29,6 @@ RUN pip3 install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme g COPY . /git RUN rm -r /git/.git \ && mv /git/.docker/pycaosdb.ini /git/integrationtests -RUN cd /git && pip3 install .[h5-crawler] +RUN cd /git && pip3 install .[all] WORKDIR /git/integrationtests CMD /wait-for-it.sh caosdb-server:10443 -t 500 -- ./test.sh --force -- GitLab From 4b6826d00d991bc3eb00a7ef99bc15106f14837c Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 13:03:50 +0100 Subject: [PATCH 058/106] FIX: Use current pip in pipeline. --- .docker/Dockerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.docker/Dockerfile b/.docker/Dockerfile index f028bbb1..5e412efc 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -21,14 +21,15 @@ RUN apt-get update && \ COPY .docker/wait-for-it.sh /wait-for-it.sh ADD https://gitlab.com/api/v4/projects/13656973/repository/branches/dev \ - pylib_version.json + pylib_version.json +RUN pip install -U pip RUN git clone https://gitlab.com/caosdb/caosdb-pylib.git && \ - cd caosdb-pylib && git checkout dev && pip3 install . + cd caosdb-pylib && git checkout dev && pip install . # At least recommonmark 0.6 required. -RUN pip3 install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme gitignore-parser +RUN pip install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme gitignore-parser COPY . /git RUN rm -r /git/.git \ && mv /git/.docker/pycaosdb.ini /git/integrationtests -RUN cd /git && pip3 install .[all] +RUN cd /git && pip install .[all] WORKDIR /git/integrationtests CMD /wait-for-it.sh caosdb-server:10443 -t 500 -- ./test.sh --force -- GitLab From 0506e93eb8ac7916872c04a566db4174e7aa81a9 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 13:07:14 +0100 Subject: [PATCH 059/106] MAINT: Pipeline optimization --- .docker/Dockerfile | 16 ++++------------ setup.py | 7 ++++++- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 5e412efc..03b8278d 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -2,20 +2,12 @@ FROM debian:11 RUN apt-get update && \ apt-get install \ curl \ - libhdf5-dev \ pkgconf \ python3 \ python3-pip \ - python3-requests \ - python3-pandas \ - python3-html2text \ - python3-sphinx \ tox \ git \ openjdk-11-jdk-headless \ - python3-autopep8 \ - python3-pytest \ - libxml2 \ -y @@ -23,13 +15,13 @@ COPY .docker/wait-for-it.sh /wait-for-it.sh ADD https://gitlab.com/api/v4/projects/13656973/repository/branches/dev \ pylib_version.json RUN pip install -U pip -RUN git clone https://gitlab.com/caosdb/caosdb-pylib.git && \ - cd caosdb-pylib && git checkout dev && pip install . +RUN git clone --depth 1 --branch dev https://gitlab.com/caosdb/caosdb-pylib.git && \ + cd caosdb-pylib && pip install -U . # At least recommonmark 0.6 required. -RUN pip install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme gitignore-parser +# RUN pip install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme gitignore-parser COPY . /git RUN rm -r /git/.git \ && mv /git/.docker/pycaosdb.ini /git/integrationtests -RUN cd /git && pip install .[all] +RUN cd /git && pip install -U .[all] WORKDIR /git/integrationtests CMD /wait-for-it.sh caosdb-server:10443 -t 500 -- ./test.sh --force diff --git a/setup.py b/setup.py index 747324fb..732bbf61 100755 --- a/setup.py +++ b/setup.py @@ -165,6 +165,11 @@ def setup_package(): ], extras_require={"h5": ["h5py>=3.3.0", ], "gitignore-parser": ["gitignore-parser >=0.1.0", ], + "dev": [ + "autopep8", + "pycodestyle", + "pylint", + ], "doc": [ "sphinx", "sphinx-autoapi", @@ -179,7 +184,7 @@ def setup_package(): "caosadvancedtools[h5, gitignore-parser]", ], "all": [ # include: doc, test - "caosadvancedtools[doc, test]", + "caosadvancedtools[dev, doc, test]", ] }, setup_requires=["pytest-runner>=2.0,<3dev"], -- GitLab From a47f95adc9ab823ac6ebf622a235058d5a84be6f Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 13:16:15 +0100 Subject: [PATCH 060/106] MAINT: Debian 12 in pipeline --- .docker/Dockerfile | 12 ++++-------- .gitlab-ci.yml | 18 +++++++++--------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 03b8278d..0ce75f43 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -1,27 +1,23 @@ -FROM debian:11 +FROM debian:12 RUN apt-get update && \ apt-get install \ - curl \ - pkgconf \ python3 \ python3-pip \ tox \ git \ - openjdk-11-jdk-headless \ -y COPY .docker/wait-for-it.sh /wait-for-it.sh ADD https://gitlab.com/api/v4/projects/13656973/repository/branches/dev \ pylib_version.json -RUN pip install -U pip -RUN git clone --depth 1 --branch dev https://gitlab.com/caosdb/caosdb-pylib.git && \ - cd caosdb-pylib && pip install -U . +RUN pip install --break-system-packages -U pip +RUN pip install --break-system-packages -U git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev # At least recommonmark 0.6 required. # RUN pip install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme gitignore-parser COPY . /git RUN rm -r /git/.git \ && mv /git/.docker/pycaosdb.ini /git/integrationtests -RUN cd /git && pip install -U .[all] +RUN cd /git && pip install --break-system-packages -U .[all] WORKDIR /git/integrationtests CMD /wait-for-it.sh caosdb-server:10443 -t 500 -- ./test.sh --force diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e953065..aeb28eca 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -123,14 +123,14 @@ linting: - make lint allow_failure: true -unittest_py39: +unittest_py311: tags: [docker] stage: unittest image: $CI_REGISTRY_IMAGE needs: [build-testenv] script: - # First verify that system Python actually is 3.9 - - python3 -c "import sys; assert sys.version.startswith('3.9')" + # First verify that system Python actually is 3.11 + - python3 -c "import sys; assert sys.version.startswith('3.11')" - python3 -c "import linkahead; print('LinkAhead Version:', linkahead.__version__)" - tox @@ -139,20 +139,20 @@ unittest_py38: stage: unittest image: python:3.8 script: &python_test_script - - pip install git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev - - pip install .[all] + - pip install --break-system-packages git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev + - pip install --break-system-packages .[all] - pytest --cov=caosadvancedtools unittests -unittest_py310: +unittest_py39: tags: [docker] stage: unittest - image: python:3.10 + image: python:3.9 script: *python_test_script -unittest_py311: +unittest_py310: tags: [docker] stage: unittest - image: python:3.11 + image: python:3.10 script: *python_test_script unittest_py312: -- GitLab From 8ab1417f0d793e3dec344c3b4a90192e4f977230 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 13:30:41 +0100 Subject: [PATCH 061/106] DOC: CHANGELOG --- .gitlab-ci.yml | 1 + CHANGELOG.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aeb28eca..d2c7f75b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -123,6 +123,7 @@ linting: - make lint allow_failure: true +# The Python version provided by the OS. unittest_py311: tags: [docker] stage: unittest diff --git a/CHANGELOG.md b/CHANGELOG.md index 18647b88..d156dced 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `export_related.export` exports to `linkahead_data.xml` now. - Renamed (and added) installation "extra" options: - `h5` instead of `h5-crawler` - - `doc`, `test` and `all` are new, they install the dependencies for testing, documentation and - everything. + - `dev`, `doc`, `test` and `all` are new, they install the dependencies for developing, testing, + documentation and everything. ### Deprecated ### -- GitLab From 74510469da1c0a7efd25ad30e2faccbaf2525a0d Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 15:41:27 +0100 Subject: [PATCH 062/106] FIX: Pipeline (also some LinkAhead renaming) --- .docker/Dockerfile | 5 +++-- .docker/docker-compose.yml | 4 ++-- .docker/local_testing.sh | 2 +- .docker/{pycaosdb.ini => pylinkahead.ini} | 2 +- .gitlab-ci.yml | 2 +- integrationtests/test.sh | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) rename .docker/{pycaosdb.ini => pylinkahead.ini} (88%) diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 0ce75f43..905cf5e3 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -5,6 +5,7 @@ RUN apt-get update && \ python3-pip \ tox \ git \ + openjdk-17-jdk-headless \ -y @@ -17,7 +18,7 @@ RUN pip install --break-system-packages -U git+https://gitlab.indiscale.com/caos # RUN pip install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme gitignore-parser COPY . /git RUN rm -r /git/.git \ - && mv /git/.docker/pycaosdb.ini /git/integrationtests + && mv /git/.docker/pylinkahead.ini /git/integrationtests RUN cd /git && pip install --break-system-packages -U .[all] WORKDIR /git/integrationtests -CMD /wait-for-it.sh caosdb-server:10443 -t 500 -- ./test.sh --force +CMD /wait-for-it.sh docker-linkahead-server-1:10443 -t 300 --strict -- ./test.sh --force diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 36964ee6..61d455f4 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -1,12 +1,12 @@ version: '3.7' services: sqldb: - image: mariadb:10.4 + image: mariadb:10.11 environment: MYSQL_ROOT_PASSWORD: caosdb1234 networks: - caosnet - caosdb-server: + linkahead-server: image: "$CI_REGISTRY/caosdb/src/caosdb-deploy:$CAOSDB_TAG" user: 999:999 depends_on: diff --git a/.docker/local_testing.sh b/.docker/local_testing.sh index bdecf73b..bbe7d8af 100755 --- a/.docker/local_testing.sh +++ b/.docker/local_testing.sh @@ -10,7 +10,7 @@ CI_REGISTRY_IMAGE=registry.indiscale.com/caosdb-advanced-testenv \ CI_REGISTRY=registry.indiscale.com EXEPATH=`pwd` CAOSDB_TAG=dev-latest \ docker-compose -f .docker/docker-compose.yml up -d cd .docker -CAOSHOSTNAME=caosdb-server ./cert.sh +CAOSHOSTNAME=linkahead-server ./cert.sh CI_REGISTRY_IMAGE=registry.indiscale.com/caosdb-advanced-testenv ./run.sh docker-compose down diff --git a/.docker/pycaosdb.ini b/.docker/pylinkahead.ini similarity index 88% rename from .docker/pycaosdb.ini rename to .docker/pylinkahead.ini index 652d5369..bfa5705b 100644 --- a/.docker/pycaosdb.ini +++ b/.docker/pylinkahead.ini @@ -2,7 +2,7 @@ test_server_side_scripting.bin_dir=../caosdb-server/test_scripting/bin/ [Connection] -url=https://caosdb-server:10443 +url=https://linkahead-server:10443 username=admin cacert=/opt/caosdb/cert/caosdb.cert.pem debug=0 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d2c7f75b..5f9d7fe4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,7 +58,7 @@ test: - cd .docker - /bin/sh ./run.sh - cd .. - - docker logs docker-caosdb-server-1 &> caosdb_log.txt + - docker logs docker-linkahead-server-1 &> caosdb_log.txt - docker logs docker-sqldb-1 &> mariadb_log.txt - docker-compose -f .docker/docker-compose.yml down - rc=`cat .docker/result` diff --git a/integrationtests/test.sh b/integrationtests/test.sh index a31afcfd..952a4dd2 100755 --- a/integrationtests/test.sh +++ b/integrationtests/test.sh @@ -15,7 +15,7 @@ then fi OUT=/tmp/crawler.output ls -cat pycaosdb.ini +cat pylinkahead.ini python3 -c "import linkahead; print('LinkAhead Version:', linkahead.__version__)" rm -rf /tmp/caosdb_identifiable_cache.db set -e -- GitLab From 85745c50611d29a38573c3bdc1bd476628caf315 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 26 Nov 2024 15:53:35 +0100 Subject: [PATCH 063/106] MAINT: Cleanup pipeline --- .docker/Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 905cf5e3..7ab3e655 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -12,10 +12,7 @@ RUN apt-get update && \ COPY .docker/wait-for-it.sh /wait-for-it.sh ADD https://gitlab.com/api/v4/projects/13656973/repository/branches/dev \ pylib_version.json -RUN pip install --break-system-packages -U pip RUN pip install --break-system-packages -U git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev -# At least recommonmark 0.6 required. -# RUN pip install -U html2text pycodestyle pylint recommonmark sphinx-rtd-theme gitignore-parser COPY . /git RUN rm -r /git/.git \ && mv /git/.docker/pylinkahead.ini /git/integrationtests -- GitLab From fcbffa468f967b306002ea10cc1aa74f7926fbd2 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Wed, 27 Nov 2024 14:24:15 +0100 Subject: [PATCH 064/106] !MAINT: Removed labfolder converter. For the time being, it lives on in the `f-labfolder-converter` branch. --- CHANGELOG.md | 2 + manual_tests/test_labfolder_import.py | 46 - manual_tests/test_labfolder_retrieve.py | 46 - pylintrc | 2 +- src/caosadvancedtools/converter/__init__.py | 0 .../converter/labfolder_api.py | 164 - .../converter/labfolder_export.py | 228 - src/doc/conf.py | 1 - .../example_labfolder_data/projects.html | 138 - .../click_on_extract_4624688_10.xlsx | Bin 21312 -> 0 bytes .../click_on_preview_4624688_9.docx | Bin 68424 -> 0 bytes .../click_on_view_4624688_8.pdf | Bin 69318 -> 0 bytes .../image_945829_4624688_image_element.png | Bin 65912 -> 0 bytes .../image_946047_4625717_blank.png | Bin 8356 -> 0 bytes .../118217_Example project/index.html | 1788 -- .../labfolder_table_4624688_11.xlsx | Bin 12036 -> 0 bytes .../labfolder_table_4625212_3.xlsx | Bin 5564 -> 0 bytes .../original_image_946047_4625717_blank.png | Bin 2399 -> 0 bytes .../118224_subproj 1/index.html | 0 .../static/css/combined.css | 10061 ----------- .../static/css/data-elements.css | 104 - .../static/css/eln_layout.css | 3101 ---- .../static/css/export-entry-footer.css | 43 - .../static/css/export-table-element.css | 35 - .../static/css/jquery-ui.css | 474 - .../static/css/notebook.css | 2194 --- .../static/css/pixel_icon.css | 570 - .../static/css/redactor.css | 1112 -- .../static/css/tree.css | 454 - .../static/font/icons11.eot | Bin 37880 -> 0 bytes .../static/font/icons11.svg | 114 - .../static/font/icons11.ttf | Bin 37716 -> 0 bytes .../static/font/icons11.woff | Bin 26056 -> 0 bytes .../static/font/redactor-font.eot | Bin 6224 -> 0 bytes .../static/img/favicon2.ico | Bin 1150 -> 0 bytes .../static/img/labfolder_icons.png | Bin 17304 -> 0 bytes .../static/img/squares.png | Bin 228 -> 0 bytes .../static/js/jquery-1.8.2.min.js | 2 - .../static/js/jquery-ui.js | 14912 ---------------- .../static/js/labfolder-global.js | 81 - .../example_labfolder_data/static/js/tree.js | 505 - .../example_labfolder_data/templates.html | 135 - .../118218_test_template/index.html | 437 - .../118219_template2/index.html | 653 - .../labfolder_table_4625184_3.xlsx | Bin 5564 -> 0 bytes 45 files changed, 3 insertions(+), 37399 deletions(-) delete mode 100644 manual_tests/test_labfolder_import.py delete mode 100644 manual_tests/test_labfolder_retrieve.py delete mode 100644 src/caosadvancedtools/converter/__init__.py delete mode 100644 src/caosadvancedtools/converter/labfolder_api.py delete mode 100644 src/caosadvancedtools/converter/labfolder_export.py delete mode 100644 unittests/example_labfolder_data/projects.html delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_extract_4624688_10.xlsx delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_preview_4624688_9.docx delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_view_4624688_8.pdf delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/image_945829_4624688_image_element.png delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/image_946047_4625717_blank.png delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/index.html delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/labfolder_table_4624688_11.xlsx delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/labfolder_table_4625212_3.xlsx delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/original_image_946047_4625717_blank.png delete mode 100644 unittests/example_labfolder_data/projects/My private projects_0/118224_subproj 1/index.html delete mode 100644 unittests/example_labfolder_data/static/css/combined.css delete mode 100644 unittests/example_labfolder_data/static/css/data-elements.css delete mode 100644 unittests/example_labfolder_data/static/css/eln_layout.css delete mode 100644 unittests/example_labfolder_data/static/css/export-entry-footer.css delete mode 100644 unittests/example_labfolder_data/static/css/export-table-element.css delete mode 100644 unittests/example_labfolder_data/static/css/jquery-ui.css delete mode 100644 unittests/example_labfolder_data/static/css/notebook.css delete mode 100644 unittests/example_labfolder_data/static/css/pixel_icon.css delete mode 100644 unittests/example_labfolder_data/static/css/redactor.css delete mode 100644 unittests/example_labfolder_data/static/css/tree.css delete mode 100644 unittests/example_labfolder_data/static/font/icons11.eot delete mode 100644 unittests/example_labfolder_data/static/font/icons11.svg delete mode 100644 unittests/example_labfolder_data/static/font/icons11.ttf delete mode 100644 unittests/example_labfolder_data/static/font/icons11.woff delete mode 100644 unittests/example_labfolder_data/static/font/redactor-font.eot delete mode 100644 unittests/example_labfolder_data/static/img/favicon2.ico delete mode 100644 unittests/example_labfolder_data/static/img/labfolder_icons.png delete mode 100644 unittests/example_labfolder_data/static/img/squares.png delete mode 100644 unittests/example_labfolder_data/static/js/jquery-1.8.2.min.js delete mode 100644 unittests/example_labfolder_data/static/js/jquery-ui.js delete mode 100644 unittests/example_labfolder_data/static/js/labfolder-global.js delete mode 100644 unittests/example_labfolder_data/static/js/tree.js delete mode 100644 unittests/example_labfolder_data/templates.html delete mode 100644 unittests/example_labfolder_data/templates/My private templates_0/118218_test_template/index.html delete mode 100644 unittests/example_labfolder_data/templates/My private templates_0/118219_template2/index.html delete mode 100644 unittests/example_labfolder_data/templates/My private templates_0/118219_template2/labfolder_table_4625184_3.xlsx diff --git a/CHANGELOG.md b/CHANGELOG.md index d156dced..d070d8da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed ### - Bloxberg code snippets. These were just a proof of concept, untested and never used in production. +- Labfolder converter. It was broken anyway, not used by anyone we know and there were no automated + tests. For the time being, it lives on in the `f-labfolder-converter` branch. ### Fixed ### diff --git a/manual_tests/test_labfolder_import.py b/manual_tests/test_labfolder_import.py deleted file mode 100644 index abc5eb11..00000000 --- a/manual_tests/test_labfolder_import.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# -# This file is a part of the LinkAhead project. -# -# Copyright (c) 2020 IndiScale GmbH -# Copyright (c) 2020 Daniel Hornung <d.hornung@indiscale.com> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. -# - -""" Imports labfolder exports """ - -import argparse -import sys - -import caosmodels -from caosmodels.parser import parse_model_from_yaml - -from caosadvancedtools.converter import labfolder_export as labfolder - - -def main(args): - """The main function.""" - model = parse_model_from_yaml("./models/model.yml") - - model.sync_data_model() - labfolder.import_data(args.folder) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("folder", default="./example_labfolder_data", - nargs="?", help='folder that contains the data') - args = parser.parse_args() - sys.exit(main(args)) diff --git a/manual_tests/test_labfolder_retrieve.py b/manual_tests/test_labfolder_retrieve.py deleted file mode 100644 index a7f56e80..00000000 --- a/manual_tests/test_labfolder_retrieve.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 -# -# This file is a part of the LinkAhead project. -# -# Copyright (c) 2020 IndiScale GmbH -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. -# - -""" Retrieve Labfolder data from API """ - -import argparse -import sys - -import caosmodels -from caosmodels.parser import parse_model_from_yaml - -from caosadvancedtools.converter.labfolder_api import Importer - - -def main(args): - """The main function.""" - model = parse_model_from_yaml("./models/model.yml") - - # model.sync_data_model() - importer = Importer() - importer.import_data() - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("folder", default="./example_labfolder_data", - nargs="?", help='folder that contains the data') - args = parser.parse_args() - sys.exit(main(args)) diff --git a/pylintrc b/pylintrc index d3a2e89a..1be7cd8d 100644 --- a/pylintrc +++ b/pylintrc @@ -6,7 +6,7 @@ good-names=ii,rt,df # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis -ignored-modules=etree,h5py,labfolder +ignored-modules=etree,h5py [MASTER] # TODO: The max_inferred size is necessary for https://github.com/PyCQA/pylint/issues/4577, diff --git a/src/caosadvancedtools/converter/__init__.py b/src/caosadvancedtools/converter/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/caosadvancedtools/converter/labfolder_api.py b/src/caosadvancedtools/converter/labfolder_api.py deleted file mode 100644 index fe77282a..00000000 --- a/src/caosadvancedtools/converter/labfolder_api.py +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env python3 -# -# This file is a part of the LinkAhead project. -# -# Copyright (c) 2020 IndiScale GmbH -# Copyright (c) 2020 Daniel Hornung <d.hornung@indiscale.com> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. -# - -""" Imports data from labfolder via api """ - -import json -import os -import time - -import html2text - -import linkahead as db -from labfolder.connection import configure_connection # pylint: disable=import-error - - -class Importer(object): - def __init__(self): - self.connection = configure_connection() - self.projects = self.connection.retrieve_projects() - self.entries = self.connection.retrieve_entries() - - def create_project(self, project): - dbproject = db.Record(name=project['title']) - dbproject.add_parent(name="Project") - dbproject.add_property(name="projectId", value=project['id']) - # crawler.cached_find_identifiables([dbproject]) - - return dbproject - - def get_entries(self, project_id): - return [ent for ent in self.entries if ent["project_id"] == project_id] - - def treat_project(self, project): - cont = db.Container() - dbproject = self.create_project(project) - cont.append(dbproject) - - for entry in self.get_entries(project["id"]): - recs = self.create_entry(entry, dbproject) - cont.extend(recs) - - print(cont) - cont.insert(unique=False) - # import IPython - # IPython.embed() - - def import_data(self): - for project in self.projects: - self.treat_project(project) - - def add_property_from_data_element(self, dbrecord, element): - - if element['type'] == "DATA_ELEMENT_GROUP": - for c in element["children"]: - self.add_property_from_data_element(dbrecord, c) - elif element['type'] == "SINGLE_DATA_ELEMENT": - - # if quant is not None: - # quant = quant.strip(": ") - # title = title+" - "+quant - res = db.execute_query("FIND PROPERTY '{}'".format(element['title'])) - - if len(res) == 0: - p = db.Property(name=element['title'], unit=element['unit'], datatype=db.DOUBLE) - try: - p.insert() - except db.exceptions.TransactionError as e: - print(e) - - return - val = element['value'] - try: - val = float(val) - except (ValueError, TypeError): - print("Value is no float!!!", val) - - return - dbrecord.add_property(name=element['title'], value=val, unit=element['unit']) - elif element['type'] == "DESCRIPTIVE_DATA_ELEMENT": - res = db.execute_query("FIND PROPERTY '{}'".format(element['title'])) - - if len(res) == 0: - p = db.Property(name=element['title'], datatype=db.TEXT) - p.insert() - dbrecord.add_property(name=element['title'], - value=element['description']) - - def create_element(self, element_id, el_type, dbrecord): - print(element_id, el_type) - - if el_type == "IMAGE": - el_type = "FILE" - elif el_type == "DATA_ELEMENT": - el_type = "DATA" - - try: - element = self.connection.retrieve_element(element_id, el_type=el_type) - except BaseException: - print("Could not retrieve: ", element_id) - - return - - if el_type == "TEXT": - dbrecord.add_property( - name="textElement", - value=html2text.html2text(element["content"])) - elif el_type == "FILE": - local_file = self.connection.download_file(element_id) - f = db.File(name=element["file_name"], - path=os.path.join("labfolder", str(time.time()), - element["file_name"]), - file=local_file) - f.insert(unique=False) - dbrecord.add_property(name="associatedFile", value=f) - - elif el_type == "DATA": - for subel in element["data_elements"]: - self.add_property_from_data_element(dbrecord=dbrecord, - element=subel) - elif el_type == "TABLE": - print(element) - - def create_entry(self, entry, dbproject): - cont = db.Container() - dbrecord = db.Record(name=entry["title"]) - dbrecord.add_parent(name="LabbookEntry") - dbrecord.add_property(name="Project", value=dbproject) - dbrecord.add_property(name="entryId", value=entry['id']) - # crawler.cached_find_identifiables([dbrecord]) - - # TODO resolve id - # person = get_author_from_entry(entry) - # dbrecord.add_property(name="responsible", value=person) - - for element in entry["elements"]: - - print(json.dumps(element, sort_keys=True, indent=4)) - self.create_element(element["id"], element["type"], dbrecord) - # If all text field would have the class dd_text_entry the - # following would be sufficient: - # if 'dd_text_entry' in block['class']: - # instead we check whether an editor field exists. - - cont.extend([dbrecord]) - - return cont diff --git a/src/caosadvancedtools/converter/labfolder_export.py b/src/caosadvancedtools/converter/labfolder_export.py deleted file mode 100644 index ae38cb10..00000000 --- a/src/caosadvancedtools/converter/labfolder_export.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env python3 -# -# This file is a part of the LinkAhead project. -# -# Copyright (c) 2020 IndiScale GmbH -# Copyright (c) 2020 Daniel Hornung <d.hornung@indiscale.com> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. -# - -""" Imports labfolder exports """ - -import os - -from bs4 import BeautifulSoup - -import linkahead as db - -RERUN = False -# crawler = Crawler() - -print(""" -WARNING: This is an ALPHA version. Parsing of the by labfolder exported data -might not work correctly! There might be missing elements! Check the result -carefully before inserting it. -""") - - -def create_project(project): - dbproject = db.Record(name=project.attrs['data-name']) - dbproject.add_parent(name="Project") - dbproject.add_property(name="projectId", value=project.attrs['data-id']) - # crawler.cached_find_identifiables([dbproject]) - - return dbproject - - -def get_author_from_entry(entry): - person = db.Record() - person.add_parent(name="Person") - resp = entry.find_all(attrs={'class': 'author_name'}) - - for name in ["firstname", "lastname"]: - person.add_property( - name=name, - value=resp[0].find_all(attrs={'class': 'author_'+name})[0].getText()) - # crawler.cached_find_identifiables([person]) - - return person - - -def val_or_none(stuff): - if len(stuff) == 0: - return None - - return stuff[0].getText() - - -def add_property_from_data_element(dbrecord, element): - unit = val_or_none(element.find_all(attrs={'class': 'element-unit'})) - title = val_or_none(element.find_all(attrs={'class': 'element-title'})) - quant = val_or_none(element.find_all(attrs={'class': 'element-quantity'})) - val = val_or_none(element.find_all(attrs={'class': 'element-value'})) - - print("tit", title) - print("qu", quant) - if quant is not None: - quant = quant.strip(": ") - title = title+" - "+quant - res = db.execute_query("FIND PROPERTY '{}'".format(title)) - if len(res) == 0: - p = db.Property(name=title, unit=unit, datatype=db.DOUBLE) - p.insert() - try: - val = float(val) - except TypeError: - print("Value is no float!!!", val) - return - dbrecord.add_property(name=title, value=val, unit=unit) - - -def create_file(name, filename, root): - local_path = os.path.join(root, filename) - local_path = os.path.normpath(local_path) - if not os.path.exists(local_path): - raise ValueError("FILE DOES NOT EXIST: ", local_path) - f = db.File(path=local_path, file=local_path, name=name) - return f - - -def create_entry(entry, dbproject, root): - cont = db.Container() - dbrecord = db.Record() - dbrecord.add_parent(name="LabbookEntry") - dbrecord.add_property(name="Project", value=dbproject) - dbrecord.add_property(name="entryId", value=entry.attrs['data-id']) - # crawler.cached_find_identifiables([dbrecord]) - - person = get_author_from_entry(entry) - dbrecord.add_property(name="responsible", value=person) - - for block in entry.find_all(attrs={'class': 'dd_entry_cell'}): - # If all text field would have the class dd_text_entry the - # following would be sufficient: - # if 'dd_text_entry' in block['class']: - # instead we check whether an editor field exists. - editor = block.find_all(attrs={'class': 'redactor_editor'}) - - if len(editor) > 0: - dbrecord.add_property(name="textElement", value=editor[0].getText()) - - continue - - download = block.find_all( - attrs={'class': 'dd_entry_cell_file_download'}) - - if len(download) > 0: - name = ((download[0].parent).attrs['data-filename']).strip('"') - if name == "blank.png": - continue - if len(download[0].find_all("img")) > 0: - filename = download[0].find_all("img")[0].attrs['src'] - elif len(download[0].find_all("a")) > 0: - filename = download[0].find_all("a")[0].attrs['href'] - else: - raise ValueError("could not get filename") - print(name) - print(filename) - f = create_file(name, filename, root) - if RERUN: - f.retrieve() - else: - f.insert() - dbrecord.add_property(name="associatedFile", value=f) - cont.append(f) - - continue - - elements = block.find_all( - attrs={'class': 'data-element-display'}) - - if len(elements) > 0: - for el in elements: - add_property_from_data_element(dbrecord=dbrecord, element=el) - - continue - - tables = block.find_all( - attrs={'class': 'table-el-container'}) - - if len(tables) > 0: - name = (tables[0]).find_all( - attrs={'class': 'table-el-filename'} - )[0].getText().strip() - f = create_file(name, name, root) - if RERUN: - f.retrieve() - else: - f.insert() - dbrecord.add_property(name="table", value=f) - cont.append(f) - - continue - - empty = block.find_all( - attrs={'class': 'dd_entry_empty_element'}) - - if len(tables) > 0: - print("\n\nempty") - - continue - - cont.extend([dbrecord, person]) - - return cont - - -def treat_project(path): - with open(os.path.join(path, "index.html")) as fp: - tree = BeautifulSoup(fp, features="lxml") - - cont = db.Container() - project = tree.find_all(id="eln_project_content") - - if len(project) == 0: - return - else: - project = project[0] - dbproject = create_project(project) - cont.append(dbproject) - - for entry in project.find_all(lambda x: x.has_attr('data-id')): - recs = create_entry(entry, dbproject, path) - cont.extend(recs) - - print(cont) - cont.insert() - # import IPython - # IPython.embed() - - -def import_data(folder): - """imports the data of a labfolder export""" - - if not os.path.exists(folder): - raise ValueError("folder does not exist") - - projects_folder = os.path.join(folder, "projects") - - if not os.path.exists(projects_folder): - raise ValueError("folder does not contain a projects folder") - - for root, dirs, files in os.walk(projects_folder): - print(root, dirs, files) - - if "index.html" in files: - treat_project(root) diff --git a/src/doc/conf.py b/src/doc/conf.py index b769fd1e..e8975650 100644 --- a/src/doc/conf.py +++ b/src/doc/conf.py @@ -201,5 +201,4 @@ autodoc_default_options = { 'undoc-members': None, } autodoc_mock_imports = [ - "labfolder", ] diff --git a/unittests/example_labfolder_data/projects.html b/unittests/example_labfolder_data/projects.html deleted file mode 100644 index 6aafb8e2..00000000 --- a/unittests/example_labfolder_data/projects.html +++ /dev/null @@ -1,138 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> - <meta name="apple-mobile-web-app-capable" content="yes"> - <meta name="apple-mobile-web-app-status-bar-style" - content="black-translucent"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - - <title>Projects</title> - - <link rel="shortcut icon" type="image/x-icon" - href="static/img/favicon2.ico"/> - - <script - src="static/js/jquery-1.8.2.min.js" - type="text/javascript"></script> - - <script src="static/js/tree.js" - type="text/javascript"></script> - - - <!-- This must be the first labfolder JS file included --> - <script - src="static/js/labfolder-global.js?13fcc6eeb30608bb104f4b234c2fa3fd86699ffe" - type="text/javascript"></script> - - <link rel="stylesheet" type="text/css" - href="static/css/eln_layout.css"/> - - - <link rel="stylesheet" type="text/css" - href="static/css/pixel_icon.css"/> - - <link rel="stylesheet" type="text/css" - href="static/css/tree.css"/> - - <link rel="stylesheet" type="text/css" - href="static/css/notebook.css"/> - -</head> -<body> -<div class="body_bg"></div> -<div class="eln_header eln_row"> - <div class="headerbar_top"> - <a href="/eln/"><span class="logo-img"></span></a> - <header> - <span aria-hidden="true" class="manage_s-img"></span> Projects - </header> - <nav> - <div class="nav_top"> - <ul> - <li><a href="templates.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Templates</p> - </button> - </a></li> - </ul> - </div> - </nav> - </div> -</div> -<div class="action_bar clearfix"></div> -<div id="data_element" data-viewname="WORKSPACE_INDEX"></div> -<div id="eln_main_content" - class="eln_main_content eln_row eln_scroll-y"> - <div class="eln_main_content_box projects-list"> - <div class="headers"> - <div class="owner">Owner</div> - <div class="update">Last Modified</div> - <div class="created">Created</div> - </div> - <div class="tree_my_eln_projects tree_top_level" data-treeid="eln_projects"> - <a id="treeline_eln_projects_0_0" - data-groupid="0" - data-objectid="0" - data-ownerid="{{ownerId}}" - class="treeline is_folder ui-droppable is_closed_folder"> - <span class="updateTS"></span> - <span class="folder_up-img"></span> - <span class="name">My private projects</span> - <span class="details"> - <span class="box-owner"> - <label>Owner:</label> - - -</span> -<span class="box-last-update"> - <label>Last update:</label> - -</span> - - </span> - </a> - <div class="treeline_children"style="overflow: hidden; display: none;"><a id="treeline_eln_projects" data-id="118217" data-parentId="0" data-userId="30003" data-groupId="0" data-name="Example project" data-folder="false" data-template="false" data-createTS="22.10.2019 15:49" data-hidden="false" data-shareable="false" data-owner-profilePictureHash="null" data-owner-tutorial="1" data-owner-zoneId="Europe/Berlin" data-owner-id="30003" data-owner-firstname="max" data-owner-lastname="muster" data-owner-email="max.muster@posteo.de" data-numberOfBlocks="4" data-lastEditedTS="28.01.2020 10:12" data-adminUserIds="[]" data-adminOrOwner="true" class="treeline is_item ui-draggable" href="./projects/My private projects_0/118217_Example%20project/index.html"> - <span class="updateTS">22.10.2019 15:49</span> - <span class="project_s-img"></span> - <span class="name">Example project</span> - <span class="details"> - <span class="box-owner"> - <label>Owner:</label> - max - muster -</span> -<span class="box-last-update"> - <label>Last update:</label> - 28.01.2020 10:12 -</span> - - </span> -</a> -<div class="treeline_children"style="overflow: hidden; display: none;"></div> -<a id="treeline_eln_projects" data-id="118224" data-parentId="0" data-userId="30003" data-groupId="0" data-name="subproj 1" data-folder="false" data-template="false" data-createTS="22.10.2019 16:49" data-hidden="false" data-shareable="false" data-owner-profilePictureHash="null" data-owner-tutorial="1" data-owner-zoneId="Europe/Berlin" data-owner-id="30003" data-owner-firstname="max" data-owner-lastname="muster" data-owner-email="max.muster@posteo.de" data-numberOfBlocks="0" data-lastEditedTS="22.10.2019 16:49" data-adminUserIds="[]" data-adminOrOwner="true" class="treeline is_item ui-draggable" href="./projects/My private projects_0/118224_subproj%201/index.html"> - <span class="updateTS">22.10.2019 16:49</span> - <span class="project_s-img"></span> - <span class="name">subproj 1</span> - <span class="details"> - <span class="box-owner"> - <label>Owner:</label> - max - muster -</span> -<span class="box-last-update"> - <label>Last update:</label> - 22.10.2019 16:49 -</span> - - </span> -</a> -<div class="treeline_children"style="overflow: hidden; display: none;"></div> -</div> -</div> - - </div> -</div> -</body> -</html> diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_extract_4624688_10.xlsx b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_extract_4624688_10.xlsx deleted file mode 100644 index 81ad1fa3196ba4235ce116dc408ba5ad0379cc5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21312 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 V-mJixZP0A21Vb~BwcH290{|zfg2Mm+ diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_preview_4624688_9.docx b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_preview_4624688_9.docx deleted file mode 100644 index 5b07c13c7997239ff51c78839e90bf34a98482d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68424 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%0An@5 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	}4)GW!RE4EgQz-CTQ9xB(pvRLosvXz14U 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 diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_view_4624688_8.pdf b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/click_on_view_4624688_8.pdf deleted file mode 100644 index 211d0f4b9c8b61ee87b4d276d2da0460f187935e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69318 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 diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/image_945829_4624688_image_element.png b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/image_945829_4624688_image_element.png deleted file mode 100644 index 7a57e0e322072c8d8914dd0453761e3f0e519b24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65912 zcmeEtWmg<s)FlK68lWKr0t9z=cXtaKEI@D%!5awf?jGFTJ$P_;cc*ceDV}%c2h4n) zwYnDFKv&&5viCmco(fh{ko<sziv$G)^+8%nOa%%Gh6oDk9Rk98;5P|(A%Rd(L{QRV z!m2K5$LX$VI%>%snYYV_Lhp#vgM`FB?Em%=^&u7P@%K}PRrUrUhQ`3M3nviCN+Fbx zhT#xd8R!R+5e57n?(z4K{FP+D2J%NF#`%FP)jYNE)p6|cackNAQQh%6=9jahe=Axh z#Y)}s<7`n&8pM@TS*@1|rTf2E&ilr8j=%r=Q`iVRCQ*O^&VR3Il>h(!%@qG{c9>2( zvTX@nkq9?wP|itqe$DZ)9;N8c)OX{?YXJUIQZcfSE7gDU57G3hjvBCcDnEtLn@hGl z24m({*GHQ!9~ObnVJt`<*1v&eOt1@F59qp_4>WmL2UG>0&42CK%DrUROMUceuaIX( z>89%D`_Faf0$VG$3HFn&iMMs1ffK7SqXhw{haKY=%zV8YF<QR;SF>Ow+F-pseJ*ML zPgsAH;PFzH(cunl^!@r~QGZRh)6xY*@KrIx<x~+0-+dk$3`w%BQhR+_zC8-OZ?H6h zVFJ$?$nkihxO<t1B_3;CEaE-wMi(S8Ut$|aX7bvjz=ID$!Dld{znMVzuJdTs9y+Wi zR;Tx4@HMv|R_dc26z>W2aqpWHZj)cF1o545D8UdjsL}Sb5G$RG4lnhEy+Pa8roFwy z@Lsh3FMW+UFaFRl4~ZuQB}VC99y?BGf>(c!9bovbL-A^uy(@XVwvOGkD($2>IM%q2 z{}eCTMmn!)t8*kAw0G3MN(FfQ>SwSmD5<}?;&PsOnU0MX5WKi_x8GaVH?BW!xFwK# zdYJ$p#<oB)L0%-e9Tq<<JVM;JwN8Pfz3FwYX}@)<nU4XmWSf6s@l72lz`#mR$7@M< zA@>L{mov{nX_}JS&tn64yIpF`-xtykXS#vLv4ecw&R^auT{k5sW-b*Wycr4XI9zlh zAP5-m=}`@v<-5=;3pC5GB?+k22X}|mTOId}gY=N7a)hWGflJQYS8(zlsRdgIf8)#K zWlaa?kJ2pg&$NQch*qekyW-TQXKXaJ70*2WlZgdqrF;HU4vSwVb7`psrjfQm^!(hT zc!pk{VM|MlwGsC2Ygvfs-AspY$ek=GIptbyZXYyOFC2*EHUV>gVie#`+=FDs%kSI1 z_KKG3wdIevW7Fw$HDUIjZN@sd9%6HvROnaQAwn3mNBKGRdO{UPcb0>Vs&DyTh8@xu ze{Bu7coR_(Bzcg(oeDcMEwy)%QM1txTTf?x*TeR?E!pE{ng0<5aJA;m^0L0b@(l4o z+;slaUNa=xl>4R<W-+W6bL=^oyrK=->Q1u)Sb`i_hwu8%>QNN8p~zy%Nb#8=^{n7# z+uCEZNzk!~Wibx90;<b7$}<vexSa(v@hf9<{vq>3Y`xVnmvjHi6Z7-abIm+pyy`sy zx8u)HsNDNQ|HVsx2jEgyAd4sjP`V58<bLA>D9@qbjA!<rwj~2gAG%J=7%Qo08*P0g z+*xC2$r_HWw2)sKSRA*;yC2;bg}PgZ52zf=XfYj2=Xoil`>_+6`7C#HcaabeSYpDp z;QY;G$E&HIE7iPqS6->+)|@mJ25$$|N=n*qm!<nnv$*t^ynfu=RqrM!+%93YJIo7f z-Hm3rA1Ck&0KuS;VTXd=xA`~Py<xGLXTCYh==oo4S>|ov7U~e67U9!h^!$vc=i-|k ze{~DAzs?ebG4iutLDK|4dJA5@1HTsf)<Ep%C7ri<1HZt+RwXu66j&dOz8U5DW|fpT zA0B0YOj!Rx<VI&GMD2^G9sn_Joj(ESDRf`;u>IVyVsG1$#c~pjjSoe*U>|sV`=x$~ z<I&@<dRf(d#kP78?<N3E)pxJuEI=F^yF%SR-+UxoyU$sGEP0&4EI=~v<|PMj+D87C z)vP79U*1|_v=SRV_i00ZbU?U%wN&o``6wA+v!qF(qh6sGyCV(--u+Xh*6=vHmI?%> zd}>;7Tq1Tu0MYXjd(F}_fqJQxm&mHFb~EefN|o20O-tN!+qF7Oar+z-N=^ndv>}d! zZjIYDE`>r{p}fyokfKKnHMZV_4IkLlY9>5b+jvzd<@n|4siRg}rULuDEo<e}+%MD8 z5_vyCt{+MTdc`-Ib@?99lQZ!z5qfi9>s2S??N1ROKXfy382?Xn@Lg=zEc7(6KsPgL z0$H4V_m46ahEMR7(Zl>(!@;Pg1~Rw1^TI`SN5i4MK=9gp2E`J}GR<QftvE{Y#MgQ& z6n=va1DwA6upJ=Sss<{T$_a-&_1oM=B-{m?MREJl&dwuGHS1a0*LxE!Z4_-M;;Tjj zb=w;4>=zuoJP&p_X4>DQ?CU46r7I5V0Sh?huwZKm#~ne8W!xXH*A?I>U3u06&x|ZM zWw?8Kwk+*aYjXr-RIV|h7=7)7eZzhf=a)@Sz}nr1GnRJ^LyL@9OQ}};f7qw@+a)tb zD9W8j(=`&lRu)agSFL(Y?+q0j@!w2CelvM@tXJcev{PoX@t+)OyWX}L3t1X7|DJ&N z$`f6Bv2V~Fx=B?pegN1b(Y1hwwqP0a?QV^|B)9qbDz=N$@*btdN3R=J>LwlmfibU1 z2Rp<R)@<^soN0Q;cxu|&MNX&Lm`kU{mAU<NsQ;=yyI<abb2IVf4HBw@4cik%S2G$C z+Lw;%uh{T-W?|l6?E#!+%ujhi?s~iA9$9^xi@7O^`oPlhnhE#DYkcR+nS&`<A_&ii zrG$gOp`V)`D8E)`P?;*UWXZ3E$~G(gtf#bEz;PRV8NG?VK>=6;5isRSK75D)j)cAe z!5d1Z0A%AZQd{%iD*A7h+|kP0&VJ>m^E11bCfsA2X0T+H-gX0c(ByJ>{$z0zc3kC( z#;?Ze?iLdM`RHvqtc-%3NBYoNcwl4JPH^F(_+ENn@7G91cSW86-4WjVX-ek}?*)y7 zYZY%ITmUzX6M3_4{pj&T6&Kb(dx{UjT1gB2?%z`Z&f)iV6yXGPfSZ5q;~j9#H)wgB z#|4B!jvmt+u?JKsZ#y8;#O7aq>A4)a`%l&VCj|N=9J;oVdF0z6MNuSg!s6NcjRa7P za^CPilJB0*nPT9`bu^tTfYI}Y^$iaJwec46|D*quS?S<={*Nw9F?jd?-vjpfzqZ4~ z-a9d9Hi@aV^MwvTIBc3N2rfXroz(HSS(f$cp%_hdjv@jv=P!Uw<O8p)Bn~y5g;cB( zD-FbBThLv|<vgh#XzkIoA?WHs;J<thHo)=lHzU;dzTm}%6ORoRJ%m1R2>*f8*O&d< zFE}Eo_63jN^nRr%0Wos0<3l%9|0t-N>A?p$zpz<j_1cM#84iT-V$b1@zioTk$-c9k z_RZhQgwx(oh_zb8YL!hs23Cu(ih+`9LS%?Fav8OkOK(xYA$v&LJ`kujfkBiVjF82V zTpVC<g)3~g%|`^a*{#T^WX(_RQK~Te4JF5>(xHnftUY^-pGdD0v4>!n?~JX*<G9-e zt7}@^I(nLk!@!V)#E^)8j-S-&5vM${JL`gAMy+Jd1d|?6C>*9V-RN-h79}qprcnTT z(fhY^5V`Oef{&>ml%8p@2xU;jJS_hh;NXRmDzv7=$b-eCFNE9_QGUdhiuuLyo8Y8U zZ{Q<%qZQk)^l~%mS2b721F-XB{4cbJwMgXD9<ipdg<p?@J{<+~)_`Bu(57fLVf2$& z!AWo3PYe>QNZWlf@{W$yFUkCO%aHg-TCY+oWR-h4=l#VysRhfT%CZ!GJRWsaW$7F3 z`+M5{O8R1%Bw2M$at8PI<0hIlFYQ#Cj+$kM6n8nS#4n@_3k_o;VT(3XQs-LI*5dYD z-m5KFcRv(2yv*BMoZ+S&Pmk5qz@zOrCv|pJH#hqCwryV&;}tIL^kzq+^{l<FKgp1B zZ)gvp3qiN~`SUTBJzi}F)f}ZtvP-1XpMDOQaK37SCsPza^ypTajEk<eY&DA+W*DgV zSg<gg!4qMbP@Q4O`?K9Z{BG4f&7q9*3yG>nQf&wfJ&48wE-QYK&U`Wy;p*-~+w=K= z7wVqQymLIg)K69i5*G-oJ8z9jjCH6(VPs9!!12IB(gKaj?B8+~vR%TjLLOm3=-h#f zsf~_?_+@MQGjXI7awu+pDf{!s1SG{C()0Su$hKky--mtMgo<2OI+vos_aGt3W!=aj z=A$zY!Ucg!FhHZyj%{@B#k%Zw$#@0X?kfoVf+*_mx7{|{(CVGe!ABrGsnG!>JU{_g z43yi(aN*FjPpy(&ppy3mi-N?!|2ijeC<m?w0XRh6cYu!3{~|+aa{vn#wV}9Yikuzr zIy69CdT%#C#;iawad5?|tEIt~n&(W8CQ!q~$*lM)U*ZZ9U&m65jHPN4-tm`>Z-?XO zbG5bw`)K5X*UH}cZd1%Y5M;(t9vvd=7@f0wc)^p8PL8cQl@MGrXmi<O5trSVIyF!- z@Cu2YXUrnXUwlrds+#LL$_f^ehcmRStAE0g{&rF{HNotLs~9$gAm55ZLymekf|Q1& zSBvb4o#`S(B$D(ppvFb!7r=vPK+B%12WP#?P}l}f(k3wTIDh4@tJf92LJQtB;>Cbw zICq=Y{ud8q1)~RpkeDCm8aP&^XxgoFmFOHq(Wy6ur_!Egdo<|jiIIlQDblDMxA}{m zUaJg}ji7R#<?e1Xxr&Pc`$rm9Qd8|(uNo1o;1p+DBWe5XOC*|E@~m`!$?#BgE77&5 z)wukydCXjF<j|NRO!rI9uU<~%&j=OaQvDOe(V{b^P9#44AZ0Q8WL;P2I^r$NPlLYm zQvH-S>pIiBywcBt_bc1|^s7X8VHsT@@7%ovN$Rt|!oGF~u8Ue+YClK&-zjXgbyS$_ z-w=wB$`@bHFj$fELSl|4v~AmZ$FoE&>t8K$V~_G=6RW#XdEa?pQY5VHE!lRA+$`DZ zV~dbIM@-uLEC&1t@d*)S-&I7`?>7gTN%5IStloD1iiFvtgG`*r<4x2ov4(xSI8gMg zt&rbWd(im}h4O_b&af)zkmProsbRM{7WBayL+bZLe_iS7!4p!$OaaLS`BGX=RK(8D zSezZ(&$uQcG|UkQ5IFmY7;Ky7gHIH4cLH#8hq6*@3#pt}99zDUu{wD2qIIfEVZLsP zrQeu8L!PuTNLnAN2V7}T#C3K*m}7BtRt6WyiI9m%_r$<l*S@5J6BYR8bnWfy8_>IU zE;94Aw=j<*L^TP1bIIVU_h<3xFkYsa?VNv~{s@-~`w<-uA_SJh_eYP9K&OoR#UIV# z*Fi2q+Ijz8Ri@3>ef5+1wZQC9RotyvejI1=@ydXcz;qR9>O+johUS!q=`BCvoS@@? zNHFq-rsJruB<kVBN!#U(Ouz@c*_@?i%>+6v!+O<DtD@1GOYGY^#5RRY$}CaW)Bg8? zdTKoq$Vj*`zUfjId`(Yiog3(cSpua9d4h#wBALw=l1YLMyX*)Al)>2j<Wu^NTKkg^ zF+WE>aMpllaBWf@Df2>7O*xn$S+G~5ef{K_ZNs!=otSa2QLc<C&0h-A*T!4XvdKS4 zqw|@iA$(CxVM|jNAKV*tk<Y$Q@9sC?lkWNlCZXdKF)}h5oqpQe5BY871)hYxq~ey{ zoWFc}!ft%YUuwG9UAkL?^UC`8NGC_%vG(hFs*qn8wb?E#cNN{7=mI^W;l_*YhHEa8 zO&PmFx>z-sVVZ59Bfj58zckyHuCCJlD{kN*q}-{Vvj1m&kdJO8Pz>=NcEQA86XMla z<RVoCAXay8=^PbrxS6kC3^7Xj)4}`bly+d-Ap~I*nNFG)Y$DLE>W+4w-7Dc^Q;aH{ z9ir2d>-pNjG@jffm+CeUh`HEmVREkU#BR0U>f&Z!Ffr_ZLzQvvFQ9r(^1MfhdbgTr z_BB5mX$;hf%zR%<7;xgqB4M1ZB8o)@LQE%~29Y!0Dr1!I>Kq-hMn{K-O3rvwMZ62@ zhhYFIDSzBB>JX;QE}{ybA-|Vo9<4(Psymvk+DUkJHQyk~csZ$|v($?wZxOiK$K-o` zx&)tx>i?MYx^qEym~=e1xO%6xnYgK>)Ok-L1*504m%TuZktl>zNSjU5dAWfr!k2N? z^Lar)xU$8nlZ^2FXEC=nIWlc*w1<p`D)Q~cUT#I(LZ75h75mReA}M5ZZfSk(QXj3o z=dORXRp$b#8lr;zj!f}TdjI0cThpJmJjJ`1<=~2Nm!Vxmke=nbHrCu~nIg5vB$vTl z{)_O&T7Eu7S8cuJr?`qRq$;FDeNT2~rt7O<zwJvUMB}GBi2aBoXO+{68*H9&uZ78I zyDx;mT~2+sj=k0t=6$yA5f1@j=hjD=6j{ECO>rtrjCMcF-utA{DYv@K2BrnUooUuH z5*_DW@tulMkJl`HzdzYr_zi2Gc>NKnzbS3x-;ess^xDg9Pm0|V$@7p8kTz`=mkjnx zs(7jQ9JieAhBvH<lXaB@SZGWCn|B|fO}Z^vJIne~zoi}crRz6+edSq6yBJ1zRDfPc z!8ShJb&v*_GEXx7flN>qMCcs~qTl`m@8<k&q4|_J8OPS6)zSVBqq%ObopI#MVUleN zBeuxS;d&Z!s7_hG=8+*9`yk;@;X(^BDb6qiI1awU?A6&ZK(OiNpTbJ@=LT<?C!zjf zhVwQ&GpamUho;l6=W$gJhGS^jTs&(pB^0is4>TR+J0WA!{cww?!k)|CkVPbu=7;>@ zb1S?2NQqL#Iv<?>R|T9gat%GnG(X$6soFG4+eZK3eh)O|PH~?(rstJP#QuQD$SEcE zok`^UfW~{xsDB{ZG{+akraK?jnz9m_#vs<QXT<D0hM-9G5|#l{baT02bQ)HdGol3c zGNMnCi}}Q`{;p|UJ^gWMXEn)lB+VH|3>`^`u@qm4M5z50Q(eD^j0OLCZYkNqG~U{} z`}?QN%t9|dd~C8oZ|^d5EwCWNH6c%S?Zbw7vJfJ<e#4RtZ~NW-*!hh%<m^0MK!j!} zt(M{ykDV;k7vAn;OmIt(WHUNP5`$_k#MYw}k3vl@g;w0Nt_yJ`S?Sh<Jl|r;5>hod zR$C>K$0Aop`)F&M8IN^T9PS~xHW#4euDp%8@g;<+un)n1d%mLTtvmar5)mQl>55&R zD3PpGiVA_qpAJO^3|)|-s;ol7nC3Vr_8x74$4Xf0CwevqCl*#<53@XdN%JwoEeRJK zWyZYdwoa1H9*uq$xoS2Uv69j(>p?AM)6YJ~kD=t_L5?MJ4pS$BMqRfN!gYSJ@3b<5 z_3$%)lqFK{y|P&e$B(~u5hHvZ?ciFH-8}&Xx+VID{PN?$zDXzZFS#wWq;i*EEXb<6 zvb{rDr4<7?ygbXKxdEmZ%KiI6L#HcPFb(5ojdUw^KItQJ6dT(Z_vuUI<AP1g$=#mv zW3`1bvZCOlAf5iIPjP|$8Pv`5vVc{cBdH?)J&J8xO<YldqFAeBnru(t$~7lvv44!Z zg4h)L_?6>M{GQubfCWjxqCg8T^cZERGaITav{K!jIDEE|sMUb2?fGW!a0Y+N@g*Av z2aCyY5?yBLMN4Ir3{XgA7-OOnk&Uc>(}-1z*ZiWP!|qFBaFN83m3oyE+7*swd{{*3 zO@*!R%1?eR7B7w<I?{El*y}KBjtQc&w3q|I>5Jw4*4WtmJeN}ikL?|5hs%23nweex zyZGnL0p)sYw=4{tA1g)1zgpS~ao7;5p_J6d%@jQD6F)>3W!#T4y1^ueeRsL<He--S zdkXw<*~tnN?<d$8n!eKz2v2Xtq-cE|%Z%V!%R^_@2=V<6+PIs_Ux#fC$PZKClk~jZ zj_UCKc^!{UDiH37Mv&KH)AC+Sv!2ec*VRvopHs&XkuuHAB$33B0}S?|;<=2ARbp(t zJavD1I@JdvR<Mh+{YLHOWwhn@9t^KlKg8>iuA=p!fo@yUf%w}>(XNSAb8hVZ4aM}x z$VeEWV8+f+BCE+TPG8vPSpGFkRrS&0T}LVF60qWfJ59tzn*hg;*Zb#M4K=$?A2@u^ zyNzXsF@6+6fmXg@%t5R9@v5RHl!JQHkrZ)RS>(M;FHe)qpz-D9VSjABe@V<ncUJ|1 zE2kVN-TT@J47!7PiF$)Wj2**!0=L`(FXxe$yQ#J;o=-0IixwsA9AooP9Ei}_x#weL zKR9WnL~KRUEI*19qb8F02BKs)75P&aWc-aH)`mm#<MLD4pN#9<rf6esb>M=yR=64` zUNWl2ykN>`-Y1}oo=&x593-kueCBgO9~n~j6SD~Kr2a~g-g7l%0tNc_si&7jL&uA? zK%Or`MZ<c(?~aXLJEGXG?|#Z|Q(0dq4NW(|UhaOPR>?J_GJJeRLs)n7`G5?O|LQwR zhb2PGPpXXXkx<coO5VibFj}jv@5mLbu-l(kFwc<Y^c<O^v7?eO6?pL!&scu#gdVzp z@k#9Otb$#Xu*ON2tXQL@MD7iG&Id~>E)Qc`xR1wup&E}&9i%6(q`y#)FEX#p^GQ># zD1QX?+b{UJ-CykB+x>-J249YZ;V}C=->zlaZ}nZ96)Lb-LGQf#GYJ!$`F)S__{5*e zu@+*{RWccIf4S$-_t}&Qd}k*SNidSe?Jy5`t;EL2NHmkCdmK<@T^Bn;-1pnDHFJ5H z4rl9~a+w0@1F@8>hCM+XUA-60VStkTw-HD<dN@<U{d_gWz5mDeVKG<0U?N*Q>@#aX zGOKCzQF+Vk4`5f(0j=Zt#P)t7(o<Faxw@z**s{DS09axbAg`x;KIJ@4w?RqAvXCPV zNNYg8WJnjhMp?t734y((1)GDYLK*?67eXc??+L7K#@4t0B0Y{3^}d(uLM@|fE2Bn{ z7bLye?r~8b5fr=KkC5cHhzMjn35gsxgc6;b;eKu)3)$@>bl&WMImWw>)M>5{X!i&4 zb3Tk1$YOe*t4D+q81+}pGsGME;X8x(Vh9y`r@ryi#Jr0g>j;v4aikF#2n;5R<KRDP zl@;cTcFHK!zXHKw7kBD-%_x4J<ib(gDKt`qLK;qX{gCxD30?ZGy{9f9u=m>^Zwz4n zAV1F)s}Su%94ROOKguRtacefHnMq)j`J_J<9TzH+F+OMtF$jSst6-pI=v&NK+_7%V z=$`b2-9rgB50+WqV{9#z$ZAa``2Odcp9Uy1hli6{Kl3`#`NE@})&*Nj#@;?ToXA&B z4Lk<OwNC}R*Wrh@(qHb4nVv2;>3Cevq`99q(P>r^VG<oYUTkR0bTu`L==lw&u!mlb z2?{Rh<u!<laUJBwHtwcaasmDxx-sAE{!Jv%em`RS^DRUyrm0W`pUy^9ez)FjhNih} z27g3?>kG%zzywwQ7{GYBNbIod#nPyCwRww@48G)|uLUgDi?tta7I8g9SCFIP>N$s* zYIN$Y*nu4l1T*gr&ayt`;gn-}?rSjtrXNI7xIeZL%OXhsuyZp)prM;ptC=R%m2<dK zQnb5n$gj$wB&RMY;t+`Y5Z7f2v1N{C&mUSK)m!ilJ7Hfv|L(BbcsKen2K4NgQ@A>t zf<=relb&)yV?BwY#K<?$DPE6i$CaXI<DY9E-8otyW?&t}kE)_Ex7GQdq-bo+S<Z%1 z5^_e3eGmxU>iou3$?~D@e!PNwNJFr~n|GlP?7%7N6ePmu1b**dR%<aN@goSK?cu;W zB0BrX6GW)jAt5IIAHWM_1C%7?CGpc?w|Mcf%e%WKZ{E5(nEEUL<|-caL&S91&kA(2 zejVlh#Hcr1;q`2p;j)Q{i-)IG{R0uIJK#f3Q&aNu%~GT-cnj~i^>TE<ed>~|E!b9y z#l3DWe@}chmc{9K{`j8%b~zSADiOD!r{&M+(OQzpOP`bO86d+PyBLGU{8i0q)paiy zi9}7`)~fwusCfHjI;3*V^U;2c|CY&Wp6NX*{`{QDHR4-<%$91sxhp-z3z!J_pIHE8 z#@4944EORmxPOjwy8Uq2I^(C8qudHS2V|#hw|c-$t(4T`@V|MrJ~%3#d4xENCszeq zScWTP;LyPjdnbmrqSta?@5F(#u(nFK*_zUPVY!x2eD5ZH2}Au<)_ezlj)p{}SsLar z&d{E}<7uax&h1*QmFwpDcon>X?9RLsDEP<zpU_#?q6+hpo^1r0^jK^tBNt{5JOrWh zk@fmXw(&~8AR+#<x;N`sdH~ml;D_{JHb-f*STb(*lt?wCJSS-I<ezb@YJ2QprSrnb z;M^$Bf4SUQL;@1L$sd1NgD3Oj$$g0EH`3SHHj&*Sy<X3^mz|iKzLa8Ys*;yTF>*?{ zNFeu<I_$$OGVTm?6AgIdui=Zz*75Cti%285d=91x02D;n9m^a$UZ`=s+Xw_W#4b|N zMlBv&&&8XzqBW+kPogj4%TP}+W=Xr#%hUaE60>hY!lzOGTOFrG^MdM=zX6U{<tS~% za<#U$yfa<hG_ikM3`O$_3n_wV;1u!#^K){+n8c}+MR!Ro#z=3g(a`r`r_696ao8I@ znR#Z=swUGGaycq%p!$e}Lco_43En0x)$hpgdg}MuUiU@Y%^`d?t5{SXP?r1>|J**r z&{7E;Kp$7!kG_6ByL%1=k0XrRVfU(;USdq?_MMojP;FfY&V8yfk1!hI3_zzyt~f4f z0dbe_vGOx`qKSPQh)<xiYxUuV%!7?bN?O3(*V6Ohn2OZWQ4w}>{3l`oC<K0&y+k5C z(9GExf*ofVj6kGEj`64aV2-w(socCy3Y6;BW$f;L`qcJ7fyQ@1)gSrDp`5i<QP{HO z8+k^P=K9iGR+o*@3DwCO!<S@D7_7voYh^($jUj^{1IhEF(edhKdyhtd^OF&S*I#6F zB1)|4o-We(sxcN_o(}^SG#QT{HQGnXWe><kg&$|@edAmzZ0GY-q=FrsuXja?XG^A; zTmIPC8{)yelp<t7xr!baTVYR6t0=hBLFkz7S#_yx_d*<$G?Z)R^J<6pNrGMiv6PCt zr!A2Ds;VjtiaNpj0Y%MvtIt4T$nE?7!ytjJjm>TZ?<v%Jl2JrfRaG>Qnr~n@K0V#@ zrf=3eeYpYps~L-WmD43&d*)^2c?+AT`^zCd!V_krK9rjkXZ;&MF|jDBXcWm6LiXEc z`UD8I^$rG@IRry`NsRg<Mtb@QU(Vn?uS@jpA#JzS*R$HUg97?)2jmRR`y}7KeS3rL z``L!}-nahL4K9Sg<8cMjc(Z7!)#5~tNvTj8jJ{8cls@dQvdML7EE|@QZ38RSF5#L) zN3rs|<RhbPnS$Dj&Q$fzfGujwyRw6<#?m74R?$mZOMYhI>7INgZW=<4x>9r3qmo*& zed39~uY9lgdkWnC^pDoU4i3nfcRiFzP799s4%24pW#4*R^`Apn75M$FA0*l8N)KHi zEBJ(<oiyowO3szpnC5uSlZ(^}0PsGa{Hc%`?fM?eg>SE=A7(61D{|pv!I|ZgG&jyP zWZ6z_z)~d*tN*V_30G5+ZYR)wHGj0P;M&N7;fh31pesr^93MOmeSEE$xtna7A)E^> zb~j&%b~*OwnQ>CT#Lxg4zZ>$C6jEiGpd#sM7vNF9r8vlKPyzo(hlKpekI~r7u@v%# z(}l|T;ImF++6Q@g`8UNIt0<5RsNVk+lE=f<a0HOg3@yhjCL<}mxze$X$JIj|G<zh3 zqjBwm@?0H{r!6ImI!&3;q>?OdS7y7T=|e#v(q?{z`w)HLj6iyFxtCWD&H!#_olvLO z$TgL&Fds-VZm}!;)G0pT0C{!D*OTt;pDz0Pnb{E5>#m!SYcI{gO%0spFv{HuoIcHQ zR_nNa$!1~8a<+71)g1!2uD$l~>G|<?4_W{2o&H@H_FGs2UqTfPL>-}Ny(UA(X4t;% zc=bs9gl+@uSp#vlMu0Z(t;NYYQO^_^E)~_0Sm=V*`T$OF8OJTV#ikk~;faDF8J~i7 zxh{!<hB?}yXLU;~`K%36HKVRQF<pxSLBhYeuBfyavG6<}3e@cI<ll<m2@{4vdTKK^ zhQOamRhAUFiYK~d`lY)1-D21r>Y5$TZrrdyB+Zr!?4#dfJDkJ|8ryBb$5a+Ztm+G~ zE3^X5!!(hf%Xc3JbBfx1xz1n2P*yy(CA^OGV~jrDEILGfZ>c@O`%bnEyZ%_jqbcbM zU7X^ttLt`<mwd;y6~>yx>uj@oZ^rnskd($DS&ZzGMJ|Oc_)S^%6S&t7q$hFO5>RG> zS#l)82MIEP4@P}q)I$?EfPO;$ME89%R~nGDZKW7$8V*b}v`XOw{3)Hj@DAJ2k|q_> zl+Rv|OKZgeZYQ-<3Sq#X{E@K}+B`)gGoLh{&jJOveUKTxKU^JH_b8?mumX;$-fM}4 z(w`x4bTN$i@%Q*j3DG<l4()K3v>NVE7M&UwS!(*AZhT)0Nb9xdQ)kxm^DbmYyHV~v zyW17#+mO4nRaW~=F(8QrBe*t$s`u1OH9LX89sp=W3$V827sro+j|*ef)it64C>sw) z6{e$U+*-u`8O^ipfHcGRxSAMF<*bmcSaV+UsJU3=rxvMSb+cUcd^|xd(P?`)EHS?S zA>r{A`<<AYsH={>*1r!VO-1Gn^{7%ekxGTGk?$q_EE@Ny%1Uxbl=sy`$GwKifU%Qq z=*T~84W(W8I_+YN8&hd;CyOKe^3_fX7@d>+kKnuNSTQ^7pW~Q}k^-M=9a4Q5#Z|KQ zU?F)+*aqZ-sF}aQF6?(^FtnC-;jG(#VCair4&KVrc?h%?UR<)Vvm0+30or7k4+<bQ z`b+Tk8k(+lQ;B*LjmIlcf!uEqzRu?t1l;aq$b$^V{|K{jayB4pV1Ql#2awGbsJnCg zxX4sAyj^8=KGk^>UGkhOJwWyi_RMOuUto<2zCI13s_iIxJz&<Dj+p?W7%v`n^_xvA z*b4pwZqIy`5%+21)?2z&gR#|&ff5$rY8X&fUY@_O?|U^Y_mxk?7%Z^e*EBAihRU9o z`?gKn#i^4^AI(oQrjmTy`9fF~?>(_a^};iVun0{vJphf_&db<(_RcijQN1D<?KdJO zh26S0d_9N|3UD(a0O-cRPk5h#OCXP}x1zZ&{*m4TcQXvQxd{Mm_nvanNWK`Lx&qSo znPZGzuQdtKWtAgayvLO=`mYajuJ=2M?mh1jwj2hj3+(pNoz*||U#zm4j^dB<T@Dj0 z6-=~D`$I_=Sv}3gOZ?U)y{h=v|15js{2>ZlM>WF7D}zp6rC7q^|GSFqiYh2~wXW(S z|6AERd1JWbi?tS0{WupT)jW1-(qsO6FG}gVjgbX5!63hk8b*A^;Qitx%^gbDcq2`N z4HLyYvn5q=shwNhdv2Ane&a;lzO#+)H=q669*A9X5xD3d@4HDV1dq`-EO*_VZ$Yz+ zNm#5A2jX{qHcg9`--WbZDljx{WBhq?X$RD=>%&1o(@ui+;7t|tn%V<*AR6K5auYBF zR#Z?ORSceV-Z3?|uo&#BP-*6oD9(D7F=miyu6UEgvJ6dryr+%6Zz>77AD6=lr(xBN z7HD9AA?|BN1?f(PZ$XwKroPx%<znCYiIA_>hw>fjs@F$l{7c)p<uv+MZpi&$qU6t6 zb3rIZE!4D$7S)i**T;_6t<sv&&GMGhL-up%thi%<?KQ8P*l5V|va+&PPFm0V@Zx0n z_vjz*$Gk?-JkMZknsz<`yBq2^%h8eq1Fn1N8aMNn6>WWEUM~)(%}3<~HPGMtzc~N6 z*dBP}8cYQ)?=jDtngxeYY{t<L^HQyv0BB&?WWSx)X!SYrtYWIX_+hzI|CvQl;AlE! zv8G4~XlZwlP#MQwXGm|BwQkJFxoqF8ts;HHO^DIo7*gl3G&AyKQL>(4)7^j^FssT_ zd~Z^0VWtfyF^?~sHOi-?Xv$)<uWs9}dfE;M2{v=j{&7jppFb3NF0TxRGA2PXBNd>* z94(Mb?gB_dHvuI>P~u|GQzIhzN@v)8^<v9yh`xcz{l<zyE-6Z_4g&;~G06fRJc|6+ zAEAIfK?jr2+l)Cq_wcuB0^mfGO;X#V02KlmJTa-m=ijpqh2P4x1msFDzD>_O?|O|T z?)amZ$Jk0FHRJ#aD&2WCS(dRaZlT7M)nQjIg8ycofHzTGIA*kzrl}>h4}9|XS;^a6 zV=Y8u=Px6q-?c!V=!RS@yYk!4Ny=m@Q1kRf66#Y3<jW;b9&N&`Ps%dxOn+6}DQj5W zJnKedbU&@^M%|h>iZovT>n*0-qwBoVTWdbGXk`R|DUd#_%XZx#_)X>j(KiZwXV4c- z;Gcc}m$`!@uh+*l0OsigE|bTul0Hzssd8+6FtdiPBi7~ah!J3wA8*H+$L$WVQDfR0 zg7q}i@r3MtTm}D@x`32CwZ|(4rd}UmYC*&l0zCN)uu{98x6%;*%9mINNn5@YH$Ivh z4cbXD6XImPT+a1h?_w6Hq+(bgZL%+?&#B>K@(HvW1tn!lyOg~5V>MNUem&d88w8um zCn7-_3mi1C!VRUgi5>AJMOuwSO-3}=dX5eq5NxucNP9@A{eYqk?U+B?7zq}k`Q~*L zvFM`Q_e;#JL8an|f5?%8w*~cYjT_*GlcZxQHqwj$Bn-pnek*2BxwoULt@+M-FqeUV zM#1Nbx*X+Y)ZQ3I_7A`Iti@(fm;bxdUz1YcDC)1Y<8(<77g6q5JP3e6(^drU8{Gon zy9+Rz>2jkz9^d<!GpcA>KaB0{o)n$OnT@ue<Ip)upk1J7_^ObO-WNfYCPkjP9f8v( zOd|mBBfis$qsAxtZ#{9;UmJldyX%65xYR3}4{1EFatP1&b0RNdGoSp3MFXIi?AC<< zKt~1KCjiCJerNb_3(0JA-stkzaovdrpZOAQAC^>{+Ajg8oMYH?P(>y_lCEF#bO*F_ zcJbH;T(%(P90}tl9?oSun0`VpaK&P*3blwF_?Ln%0y@G>Qkuh^N_1U`MvapPV)Uu= zA8Q+}&OgGwK53xHhl}m*Rf)8Km^!r^?Cc1#rq9x|!8)~0dMPrI67I2CPZrj7x7MxD zP12GoxZI0Sj6RB119Kro^@j_(H2iooJz6_PyKsnH8blGH8}k_O$J28Zj;R(NG#TIv z={FI#JCfQDxTx`V)xAc?=SBpNv(G3YvviMg)-@GK!X`lVzRAFjhnWf-K~FxQtza|| zLtYpV;O_N&r2m=wCt0G-PiZab^{1P~A%}w?@T$baiwtD0)%B94iq-1{{B|J)?wz>e z$AzTJ!k?|QqPrKXyD}h7r(?}G@%z?$;<Ul9F&Qxgx(B+&P}85`pdoW4(a19|L0#8` zXdi_e){h>&qHT{~#fd0Hs4bukGe0UZLr-cCr}HM}L<%%3_DE(BzTWk>K3xpy*mc5L zRrP+tciYc8t{D@!f~;lQ0-|f-2<T#b`9!Dr_pJ*7SeNVZxMpq6*rjC<*f{8$QWP8k zN#b_`)X)U52KUXpk!3YR)sOGB9~*F#cQZPXExiYxKGMKAO#Na^P!fH^@f;~J8#yBi zZsUjS-sSp9wd-#QoN~5y@tl)Pj_PWv**|(q60qVgN($Nyhll!$uA44ye>uOFE!liY z{bfAvSnUzny>o2ytbt%H(o6}(SBBZDZZPcxSC_(d5WMC5RZ@(qsDS8M`2%hHM$!Ts z9@}m=h}PW3#^mYl{4IxoCR~C1yqe6;kJggaNWPQcBpK~Ml+Rs21AOqO$i-4&T9QUc z<RFCyo}qT0Df?KZK{pP++b?zUqYU@cqQjzn1q96<Q@PjjUF(4k3AHyT0DM0z_V1t| zbCvX6kEI`1-~$es>WlCAys9HI{?YkWj+mS;m&}4A^SctCnUXhT({Wlb<^#%6xm1pD zts0XV9dIsC$uPVnM(fMN(G$?g+Xm?EkA8>e(}}HD4xoYREaxt=&^+F9;;mX0c-lal zn{Iy-A<2?IfKD&p*<Y9w4&E~Mz%NcX00?fK_Y<04?Z4^J$p7wHQ``0p@JvN|_LBg= zh&HSdt1_5tc5%SGU&njMLTZ;m3;d8*2v<+Y$E2z~Io^eeMIueh^w}f$t6~_ebCfJk z{bS{1q9b?WS(4;m@pYpf@2`)jM;W<-3J?6;{%)TL4McF=np7|UII<D91Bs#RE#<Gt zM)qM#318u(Vpw6xA^%bNh^}k-HylkFcfG(2^zoT`exQq8$}<ZD5YV7=Dd4b1nd!@~ z8H@M4VS}ZWUxj?;OG$&tHjn3mm%;GV5jy)=$T!NNJJDWLX}2LV$_wFhTJvx=8BJR- z-6S0g6nrvJ;M(wO=g9f+R*{X1q8XQz)o%uoMyvz>du$my$h93M+W7kN=z7)(4?w9X z7vKd;3ZbxaK#P-oAP0IlK<E=LkZAeG{_3heFV!gkFqUa4<BsWb$Z)(a_BJKV#$)i% zi#j9-b`sAnOeHG(2=V(B{lTsFSZ(=YqB}K>#@<plagTIvm<-I_wG`PM4oUEtIu^YV zAcpC58Y?SC%&<WQ0HWhN3^O~GEugpnMb5*bpL_tL$ARoye`+gIFe8xAGYKHzrV4qB zZejQ@J#XZvrlG5bZ8&KrtBVi?M)CNFsJyKdPqQI|rywdS2D~f_6~m<b923jX4E+#< z&xncJ(JfX=Xj0gYelDhjtupqgd5gt;BuO2g;VvT%(8E{IjVvp@ec#C;DKINQh%x;+ znF;ke3$%A;kGS_>Y`~eyd*ZJ?vt+NFjBSb|LHh{l5Dfi9e`v|dv;7wa?d>?WWDRpF z<ju6PUH;uQLdwV`2cAYFP&p?S2_xHN?J}nkh(QdMJ$#gPy%fyxRJOi$;VOH*XqiDm z6q=*VVxZ@x3$X~ZK)_R_|ArQbKO-i^{{?U6r<0r?FnxN34|)8ob3HS3``o|!1058{ zg-K{0Q@Ac_Bw<Z|jn_(|%t5?AK%*f68Q0q>koUL9GvXylFH8Va#nK|VAo3ITM9j6G zNnt*4a)3G-PGkot%kY3LTz*mAksf!V&EjY4rI8#45aA#sp9`)wh*HAdWe)cTR+ce0 ztb(;j1GQ3_oPC>0nap&6-+Ip>NP{Q_hYht33&DdRmzLjpbx)N;VK{NW3_jAtc&A+c zV4i*TwY8bV#9r28Z{o9r#=#@4CvVb_yF*qTiY*n&dhE>RdjgkDbB2}&3PW=$cgdaN z=BfiF$eNa?VcN^e4D8ie0K$Z0Rzx%cT3b6od~S2J?&xA%QNZkEBQQfz@lhr~8EDl# zxDj|5dFZDCHzJ}-mZgDVqteEzRpfNZ`hW^T+({s3`!0qR4P5D%y1en>)8_VL@~;c~ z#$1tv#91+uOCKwq9<$LowM@Sw5!c2UV8`e)(|4gckxHtKyx*4@;zJuRb93itO9+HZ z6dyW^m)J8?zAjwm5d3p*y|_h^72|wJnbYWPoz@xjd_7aY_GD)dizw=DF&Imo=CMD+ zid;fmUNVbu#fu%<8drK0AWQ2HQcT4Q2+-+pJ(kYb_i&&PAaJ2O_d_pE4vw@xlm}nI z#*p1p#upo^c+WX>wNkpvTydEDw^|v7<+$$P>ghial+3zsa+Sx(WptQe1+i^|mtP-v z@G~CuwIj#T`-Hw!(MGf1#+`YZ7mSIn@+v8A&1v)V0E6%Ni53}2AI?X&J4)K`+Xo+q zb4Lu@#&h<r^2IJg*xx2V&;A`9mAu&Cq|!JZKr^oj289ai{yRa3ry3Q;PYg<f0U7>l z#RJxD&d_mV5><;|vEFmOzSYr-oMu1iR~f>ftfJz2*;;h-Q4jC0e>?VpvnaldTFE47 zUL_~_MSomzH6Q{oNC6oPRG0kfrPRta38Cl{s#3Ynp?=PxaC*7|=%D@*TE5$kGoB^u zs*FNdTyZIqj45<R2rw2~96vZ%@t0Be#myE?xF9$7IB!TFGBsZG)V^l!nq$NF5mMW_ zV7j4AgBk=aJ-VU#x36*JN~NjPnBB`(Z(!WI!64N0!^dnM9p@9jJWD=CI$C3|j>^)W zr4oK#l=&-xP=nkgC}uaTNYRPh%T~WSJwi-zkp1L!D-l7@`B8tyZuOCk_zZ|UC^kFa zz(Zg+t3R{TTmXNFPjf|F&A!-WPe^E!OPf7jjLAkpwPY5HSgOMlY`27VCd{WGtjl$i z_OQP6Rr1*9cW_YSb>2+pQsBCntAE-3g~GFl=~eC$kC0p%+bk?$uU593=j*kqKXqoB z?m=>qe`5aPOYy>FqH2KE%p}7e76kTu&>O9E+dJLpquKcT)`UN(eFX_t4c!q?rP>;s z;dvvqrFugThHK>Z9TTlCIjgs8NATHJ$<Jkf(*!&EUymBHck8d-n+)v+BckVMC}WY} zi%=s%|LfH(A$nJw0Z-r+a4@%w#2}+5i;?gy2!py%g754O0>$OA2}^RcH))NJ+miv$ zSYE2Qnjcj&F}2-o`VDV_dXrxPmQk6D!2^K?#W)vnb0jckB2=S??i+}*pM`2LJ3d34 zeo$eF>ci-UTF|+0P@yEO4t~61xp}&(q}X*1T-~+4nm^bp@!Nc1*%qnlaf4nT71u{? zf8{bBrDhB`!cWdf1SF1BAaTCU>=6zt$547C@Q;1?hsCgP!v&t5_Ks5P%e$lV1pIaf zQqlVPR<WJkE^mi~%XP}f#gNrr*r16LF~2hcVu?JV33r`OyPH%rd>1{CrsI^<POPqw z>QE6Q5jI+*6xaqRyH}$z^b#iX&D&s(DLf0s4PEH--toH$IPw@QGpUwQTM5<j+)xC2 zd{c5mU7mYKX@Nj4K4y}<+&#&j9NP-ynaZ<utniNoa0KqOyN|vkAxLnBB;gaeqRkS| zQ88m~n|{f)WXQ91`qGe~LxR9X0?Oo7Wqs$>$XO%!u0}sdH3f%-cMR#VA|Fyu^(O=5 z9@@G|VTrNxt4WOZ!Gj%kKIeT&yhQ<XoKz@)srAHzgM-i7|7t|yAO|NYso9AL8_67^ z+jE6?`*R=~oav#*ah17{D_t-v8z2+7J(&}@A0rx?2HH6X1>IjSCmXP@xsw$1&=4P+ zT}~1RT}%ABw@aD5ukS8_A<@BT{zOdo?Q>0I9)fwHnkrNW0cZ?J(TaMuGc=efYI7Le zM3H}T_@jZp2=vQ7>+#E1K32!N*6Gn-lZeoi(CreIz*PxthYnQ5?fz!->-u8AU1(B| zvtlZ)e7|-pb0YBC0g1oc%Yv&n-+#39HL#*e==^a-Lj%$?u(s##EQppH)`=n!M_SL$ z<@uy#`lG`BC#F1w2?lNgcd(K^N*CE7A;suT&4eKHhf;kFxt}PL(oU+Jh;4QK%39J? z;$lI;phSvP+K417hD|Z5=AiyHO|)-N)c#N$;UHY9kWDq0;}J(Q6=(*h1E1RNP!q(n z_-Ez^Hx*s!9lwrQj@?@=d4w65_$?J$`)zR8I2y4?EMK`4|Dj)uCQOTbctK)95HDA) zk-up|J);uv+*Q?%QI3YaKwp1|eg^|JcATFanZS+|Uol3E+f1O{M_5pxS(vkrY>X>= zuz`977xqS-*^%o?A13zPB;z7R?r*L@8nMxh=Ur`Mx^$-efi?4gL{yuxh_+-xh#&)c zxK%5yq3rnIpUx*EgL<ZjGen|R>GZPb^pp+v%1H6aWy+!V_!Zbn^|oSK3)Mj?Xta;i zWm$?LL9{hB3ALwl#`V*f*1Sb?eFD)vN2Su@ydu=*1*nYeo<DztDQM}cyzD{JLqlKh z-GiT<sF?mJ5zZlW@6$Ls&XhN((d9h4e8AG0jTb4K<XDLe4*EELZNSbY@8{$r3EG^! z)2MK<U-z4zlROP9Hi`f0pF7(QBUUpUKZ@>XcJWXv8M5j7y&FUx8E;(yKNfF@lJ|pN z&pw%I86Q#a&uqxoB1wkzV3B%mftV<-TsT$yXR7lvyp1*~k~s2%YiQyhvR%&4`>Et< zeiq_IMDQZn+yV<7yH*p&=Wh1{OS9NF3wOV+Flie6Eu~B5x))9yV>cThahecbuN5~! zJxiQaTt{-D(xv0a*x6lQwG2$f(swbXpipFPk}63stUWa4y0RTE#=IK(o_#xnav<7) zxaq6tFGt_s4;TuM6M4Vkl~wsRu^2%Le0jMlNujalAVd*5UH?R-^kT|UtQqvhgtdfp z-!B`=_}Su6aU@k-dRkhW6|^Dg9lA2DlPcTsSOgH=q%;e;FctW~8Uq~1zl)mp70xXL zEVufQzS0va^&zIisAdpRu}s<(QDJ|Qp3&BT;?E^Ni#sJ{1o|vo-$?VQb@8)^bwp*e z@pW_r=|j{!Z?3~fqn<|`$EaG{KT<)RH`N4l@kU$<e0VXxeEOAzg4-}8mDL>)MW|BN z&w*jxlA~mjCRgZ5je(j}q%2z*#P|Rr9&)f`WV>GOHcv-d0y;h@vR#)<#7+QV&WB4o zivtB_-cGnG%cqy=@W0Zv?fR2!BEyJ`?(Em$nh6KhM};raT{RNK%qzmBSx=S-Vl?Cf zlej$h%~UR;KXi5F=KVyHf*wSU>}i<~ODI_yh%cnqHpx7fc+W(H@y)2?NEO`V3(*D! zqaC=gwGcN2{(?ZHg|_?|uZtL$hcYLVx5`o?je6z`RW9PXWR&^;XBL3k<*S&I;|~v8 z;NdwdYBv`rQjy{ej{>m?2I4*nF`yX85)FKtkFS+BV`KdH=o>+?sV75RzAA1oSuR4y zyork*W8z;9rGkLzn0Y06o24P8kLe~vC4y-0S4mAG#)g=Dh;uD%ix?AA9-Yn5w<Qc~ z|2r|t6eBO|TgsL6fdJ4|zwbX@E{Tv7eF=1FMM53xwhb5%Is5JyR;(ftoclM&wp=_N zgVZJXJk@+P+yJNS>2^)Fl*an*+F4Ed9>PFYh9}VmG)r^8(K`bYlpu&o9B~9Oo$Ap4 zAEE&Rr8Idq#=5AQUgEZIP)Q_)4TFe>H`RcC2&phQ&F}En#tBIfZw7bA{pXI3R|U_< zBkjhG@u<fQRUx=+jJ>sA*c~m8U<pj+Gas2pS9Uy^ygMmo(Bvl&qW$kp5MM><?_Sz1 zrH?{9Xu+2XX6S*p8NIaY74!me(la<^@QE3~gH#gELx%!W(hGXsg_MVes2bEfBKKpp zL3!t%+2NI8$YOBhH$Ji$BNK#nW6!U{k~-8bVr-jrk{u(_iRIk`pIi*jBDfk+9};p^ z%QOPlC!0(B@;5_{dK9z%x^kZMSI%XA&qSOHWNCa6J9Ya`M(BRxeC)7{@;&tITR1hB zB0e_N9Y$5IT5Pjq9SQUX`1mG&%^5*JwL~Q{F{po46UGH!`9l8JlZO}*IS45_d-ePd z?`Xli0a^?fWQiMQiqp6I@3mbcJFoE^do>~ZBJft`xXxNv?gS-A^lf~dQc$=KYyKAg z3ps~nu9P$gQLPNN*MT&r!;>uW+5Us)j_mN=VgvVPHHPwZq^1ail+?=U<3Nh68wY{_ zH6hC0${nlc>*Xa^H7(xw)_s5E-<ZU5wBXxS-{rr~s5~(q5t-gR=-2C_#-%aN=<!tk zH%o1g8(|!A)5LK~SbCP!=NE&HP|^b{qrHF3&|_8;mCgZ%{V6qWSiNrutUYLM+@-RG zuda6bTk|T@VNx>&Q9M>99qiGww<1aKpOc4jGXz->*0g_sZ}xAbXat2XRmjiShG+^h z(g+EXKd~2T10{|;*;*MEg14QL5J`eXA*l92pSs*<VlzG!%jEh+bdm83Oz*8Gifu_@ zV8E@5QYAExhjM+wen^ulw8MJvlQL_kA`0~UEuns~N{f1pN=cx2!KZvjCfyk6LL4(* zI8o%o5ryhg?AHqV){<sR<(h?KL>x6k1y#kB*2DKSi%Sw71ED#%6z&(KkroV4QicX? zOmK!0eek#n2A&~+f0_PRW2Ji=-(BrEn3-Z_KUnBBtY|vT$v~Fwj-_h2ob@`GBY21N zdi#$=py`zWC5prh`sIc!GyRN)bNF+=p!G?YDtIQd>Eg`G2$e`|pL1+u12HrAAewTb z;)#{l|HZSXLa?iSt%KXV9h(oiU*{JxrXW8$xdfZxeWuMG?blQIa34PID=@)hC#BZS zKe`0ZQ=FHzSx}{)AmbfT<|6gG4&DMjrobt_{UgQdTl+as5lqAT^AAFZ!IT#@n77~Y zAom4ZUVRRf2rm_p=S^GsTg~o$7m7m!z!-;(O!0Rtr2-eEAfKtE?6AGlwXh$iBEAw6 zbx-GgM)#dwJ}yd>#v~*A&^=qqdRo-2ix{BLf=r=OX1I8U>x-bEvlJJ(k9xYwhUX#g zoe1`!FMWWh2zaO1zT$wmt=O(>co$WOY6y#x<8e3$V~AsY1}bJ&;EQ;d@oql>>_*tQ zVJZ2)SbGbgD%bCSbR%UTEg=d>svso-BHaj*0@7X5NH+q~AfSY#NJw``cMAg2ozf{? z|FzHe{Nm2sJ9F>Mo$<^Z_TKONKCzy)*5|XH=kxCVC<xQtj=vP@7C&05C+E6XyZ>V2 z;(+>OgVSgq^GZ^te#z-IWk!I>jqQ6B7hU{?vpM1=eIwyU+dfH)W%uh_d}7>CY1n;U zxQ#zaC^h!Js=YMfb8KLBJ2VR){F}vkeiTYi8@NZ#oHTla;<T&c;Uw#aK95a_!^<_o zx)=65^{46~+6Tt@r)&Li$&BvyLVo+4P;3~7@5j9FUNL0P*FNx<j6Wyhw_`tZJCNXW zJb%^ss`&vsu6UL>i<7_rLAl+iGmq_+$4c|eT#5FJAb0F@jx(OgmVgDz<ti(pNOA%P zmm_x31NQHGE$g(tT&rW(YzVU}{G{HV@oT-$q)~c&^WlZl-=9>yE&jUZ(KVy@_It;Z za=xDRs`Ul`Tt;VIBa8n^V*hGGsN-cw^9hM~M5Ox9t7&_bch?CjSBU#cO#BM<E^8B5 zm|ut6UV2Pxk>lY^hkYBO{wu8X(8+0OPV)RW?bkP#7+Yt9cQLlkueip=MQnNeab|)( zdsg`qEIYS6>YeG453j#XaY=9F_ViPG==`sX^D=*W>vPW*!r$qyx`fdgZ~9{DY2bhH zX?xHk<vZ#s0=1IPvyUB2@4pK_LePH1mzNas!KHN29n#o2Uoop@U9pn2?)fWMH~PT( zM7T%0?DkdR5z29ZfspxMn%nb2OF2sG#n!N|{p7ko%@2XiE3Sh%u7@;BH(C}-TL6Kn zD92WJv2cjH44n1HPq2q1wFni4RMG7vy`iSsZNUq8eEV_b=!2r!MEXds*C|c%J3{xo zPw{WXEAJgN;@?HDqLT2YG^Em_cuYK}x1~`PGU#vB%rAlGxq@w;6XrO5`b<9I(-8W3 zs$uT&p8x2f{(JF=hpWkRdbr{tn8_`tIjF-6>Aof=<ln#kc##_PSVZ!jAjOi4&BO1( z-u4f2vHZDSeHr>eDZ`F&bi14)cSZSZw+EFP4>M?<r)6GsNh9X5H7Qw`N;|bxzPKCe zV^&(cQxvTQ5iW<CAkr3gTvwXipwDS20nUGa+PiHKs2^VX!}&)`rysP-p+megf;*u@ zNiphr4r6URIb!a5*IK@t)p)&o5b<J|#0IaZ#R+qs=l0_kUo`8_J1*P2cuee$3s)sa zm%H-HM|InOoash4B?8BF9~UHXmj<ybvP?w%FxR88#xLxgG(TiWWgkljtaU0z-Pkfv zQE1hQdP;WscqQrA?FxF_cT2;I)*n(k_+noud?ZQ1)3T`~`Wi)5W>h*o+G!H{rKrLv z$^Od8=t+{XhpdM*#&MlCvv#C&l5yVl>4D~Y^{`{!9Sj=OH*fBT`P14*RSGJHyJAFr zY^Px{yyu0&*0g4^fbT=~M^MibBX(^74gKRC)U*!2cWfz4{Svw?91O)!z#?NoL}w;- zktv508x^C8%Cp>JYl};(dKa3*sV^0AC$6SrdA|_Lt8;DHVf7YEMt&qo8d=K2?1=r< zljMaLvgi1^qVl)zsVY0R3WxQyl_YRI+E5dUY~RJ1=|WY+@?yunQPPl7C7Tr^Nk<`3 z*r9t1BSS#<Lq}JPOCz1dDSg0t_^L)0*GVH6DWyoS5XSY0K?!_RLiC%8n4^(Yg5FrF z@>ch7q}XC}r|TcEqU%b?RRliu$_i3>e@(Slk+Vp=>Go6fAi)pbtUM=qSBS$OI5BZ3 z1NGsv&9@s=ek$qYVn!OEMO|KV8}yCGdQfxVnlUYdZU4QKMzt1C{bmlP!LIlBp4Y;n zY|z7-p;ddj4VCyG%vrox?e%}4NhadO7=#FW_ZW~g$zfJX4`^Bw8!dcX`gYvhjy?IV zeMaZWiy+iUlt@C1*lU5L?CtvlUJlv1K`!03G^`TlM6qcC5w|~5WhSRr#fn83c1YJY ziz@$Al-Rh{u@}SATZgb9qYYROzOo&OF;YW&AB$&#gY18h3;Vm#6cNjKY-(BgBV87v z55Bt{@0+=Be_+e#M!t2ESbHl#;{5S5GZis<_FU&jT{*;I-;3P}Z5;jYo@Ce(y1qr2 z;?wt<LmjW~k5kAopGKvJaus%Atxk;;?OqR-w$0g}!f^Y#wIqj-R6f$Ix#&;EOLD(O zWKBwYqd1kEEcc-oO?Si@Umb#m=*JZev+bl+nq=2nHil2GRyf1H{)gLgqr{`r?{4Uq z)cbjEons=_RvR!xn|!Xuy)WW#>&U5m2*~p5#0u$@qY>5A^g(gHi7?gRl~H?nsZFlf zK!a+KVJW6UgU%N3$I{k$OnLo1Wj>j$9y-mkgZX@w;Qa)tW1+kLj9Hd4_!HNUn75nV zNKy)~o$q&Fp?V&5Iqn`Yp~kkz5?ovC;JYcwhPYWEjDP&|cXm;uP6Jod0Aq)=Hx<M2 z@=MO%+?zSNtT!%I-tHV(xMBW4JJP>GpUb?IHP4?3FS$Y>Zu0TY_@%3dH8vc@ieLmU zM27H)wmB^}38+Tw1k)$A*Y@#;)Vn+LZ+xVzcf9GTSTFu8#h{MuouQA@o5&OiMm7ob zSbUqgn`D%Nf^YOb#&YlXQn|hvy*ek(Jxz|co?Y>58jI;h6b3ZzVb*ATy=!J`@E{<T z+u%dTeRf*|??-yeMGTH#>3w!tQbaBbwDcY-KF327#2vxIkDps_bN(B`%H!#V_}sna z-9uQ|F>6zN{(vj!N~bIQR4J@SI_K$R%ipgLZ}MGr6CeLAVa+ug&DCnla2M2@|DIEb zWlxKO2qr=G!V*!&i^VEr@wvAfuVRJS=aU*D%poDygdsp4j>Zu7P~pf#;Qi~V_bS7l zWQ{6U<j*W_k`Q)$#1(77)yuZQjcyxyHKThYvgda#$sVzebddQ*bc#u+(Sw}3VNFdc z%4}&JL4hrUY}gXcIwZt7tl34B!n$jnYLWMB{zOo<1rdHoBcZCW5a;+|CR3>pTXlNP z2-g|CGiA$6vbpez!gYe>tebPLz-XyaCl=kSy7*P%TRCQ9b^)WCMl*H`pZwynlSAFH z(~9_gDD!C_^L}$0>pkOhzew&pj1B3R6@L2Un&2YZ%t`A*kCQ0|{gHEKGGn<ftGaEP zg)KJ(BGI0+?WEp`Sier^P5PU3Np)eZ&D2kmbaY?e?9OwnkQ`J8^qU45Tdg`>#2;_t zzlrshT=*D)88`C=8)1Hrt=lI}L?d?ZQwN<bDg04ohN?rN!dqiN6c=jbCFtGsTM1J# zF1-scFqsV7D_5+Q(5AbpYR1P~5Rc(0<2)aor0t^7JJn}*sTe30BDNopzCL2?_!ygd z_i+%nRQ{H-ksPkrXv)?jc^Xuj?_y!ze%>__+^pDiieyx<B(75(#oD0K+_iM-*=fRx zctV2_C@Gg_!@?&QGjs=CQr>tawuO>mEuz%RMU+B+jm{30=ArHlU7xoS4|O7jZqx-) z>fc-VNF(qbi`G_{Ym_VYo>(j?LV|_Gr|NA338mB;FL{Lf{Yb_f@$G9J!IM84(<C$v zb%$_+5(HWk8)!OlRRcRv8-5R!cf1<=P<Wd3wo>BlY3y1MtrVWHm_kY+kJnEH*?K*; zSnn){Fd9MZoGrDr{@S%5|I{E<x*R6c#bIGwFlG^^NCH;@M1ZQEJ%%dpu7rG>DedB2 zalN(8*~nbWFUs5faw;@5orvef+V39~j|Svnmy=>KhS;cT2C%ST#7V9hX^r8kJ~_VS zRTDt0KtB5QDk#XaUQl!OqX7#G36}0d-5~)vtH&x!3ZHBQqN#{)WiyatDYOI%22CD( z{Z9YdkMtAI2c99Eo7xg<tU37IK4|C*Y}UeDxt82wBrH8bv3`wMYgt+tZ4ES%Wz{4; zJ(gZn?kK9)NXWt`7xOh(IY_8t?q(Cuuu5c05&2ZbX};^`5d5cO`4LYUC?_{xR$mip zYcIoTW<0pWMrZNT?rozKv=6^21rF0dvNlatSvHzY;C`$yiV^EU-L0XAov4aUYt;%# zZxbJ83!?f6!s!U*i!YR+PdhMf;MWPn?$V;)aE@?gZ)h9hC5_De@lcLe|K+oXZ4byu z_6P;MT{NtdQj>~Xk4#BOcF><96v(l<ZtDc0#YuK3l3?i|=jcO*mtY%L0|{YZmMd4R z;M9w20t$rRGd>Esi(`u)=8Ft#y&(w_ti9JSKy>||zC4$ZA)#y%Cs)D3v2Co9`PhUY zl$ak?rL_&mtoN0j`t?N6o87~wEw3X*3+tieb#ac690tPdxkf^Pd3ya$In78y(jazh z)LYFBdz9Xymai}g-ELrHh{$}8WMz8vF&2$(2I1%TKzv^B=5Ke(ḩd>!9!*XXj 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	(kd!AAjAbcHAcN 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 Pt|E8j)ldbuO`iP++XD;} diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/image_946047_4625717_blank.png b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/image_946047_4625717_blank.png deleted file mode 100644 index 1939e07a484248d5b92ebae2fd50056a492ccad9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8356 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 diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/index.html b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/index.html deleted file mode 100644 index 2450911f..00000000 --- a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/index.html +++ /dev/null @@ -1,1788 +0,0 @@ -<html> -<head> - <style type="text/css"> - @charset "UTF-8"; - [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak, .ng-hide:not(.ng-hide-animate) { - display: none !important; - } - - ng\:form { - display: block; - } - </style> - - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> - <meta name="apple-mobile-web-app-capable" content="yes"> - <meta name="apple-mobile-web-app-status-bar-style" - content="black-translucent"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - - - <title>Notebook</title> - - - <link rel="shortcut icon" type="image/x-icon" - href="../../../static/img/favicon2.ico"> - - <script src="../../../static/js/jquery-1.8.2.min.js" - type="text/javascript"></script> - <style type="text/css"></style> - - - <!-- This must be the first labfolder JS file included --> - <script - src="../../../static/js/labfolder-global.js?no-build-number" - type="text/javascript"></script> - - <link rel="stylesheet" type="text/css" - href="../../../static/css/export-table-element.css"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/jquery-ui.css"> - - <link rel="stylesheet" type="text/css" - href="../../../static/css/data-elements.css?no-build-number"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/combined.css?no-build-number"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/export-entry-footer.css"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/redactor.css"/> - - <script type="text/javascript"> - function getTemplateText(className) { - return $("#jsTemplate_jsText").find(".jstext_" + className).text(); - } - - $(document).ready(function () { - // expand tags and custom dates container on hover - $(".entry_menu_less").hover( - function () { - if (!$(this).children(":first").hasClass("entry_name_menu")) { - $(this).addClass('entry_menu_more'); - $(this).children(":first").addClass('show_list_more'); - if ($(this).children(":first").hasClass("entry_tags")) { - $(".entry_tags").css("height", "auto"); - } - } - }, - function () { - if (!$(this).children(":first").hasClass("entry_name_menu")) { - $(this).removeClass('entry_menu_more'); - $(this).children(":first").removeClass('show_list_more'); - if ($(this).children(":first").hasClass("entry_tags")) { - $(".entry_tags").css("height", "100%"); - } - } - } - ); - - //selects the table sheet according to click - $(".sheet_tab").click(function () { - if ($(this).hasClass('selected') === false) { - var previous = $(this).siblings(".selected"); - var previousElementId = previous.data("elementid"); - var previousSheetIndex = previous.data("sheetidx"); - previous.removeClass("selected"); - - var targetElementId = $(this).data("elementid"); - var targetSheetIndex = $(this).data("sheetidx"); - $(this).addClass("selected"); - - $("#table_" + targetElementId + "_" + targetSheetIndex).css("display", "block"); - $("#table_" + previousElementId + "_" + previousSheetIndex).css("display", "none"); - } - }); - }); - </script> - - <script src="../../../static/js/jquery-ui.js" - type="text/javascript"></script> -</head> - -<body> -<div class="body_bg"></div> -<div id="global_data"></div> -<div class="eln_header eln_row"> - <div class="headerbar_top"> - <a href="/eln/"><span class="logo-img"></span></a> - <header> - <span class="notebook_s-img"></span> Notebook - </header> - <nav> - <div class="nav_top"> - <ul> - <li><a href="../../../projects.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Projects</p> - </button> - </a></li> - <li><a href="../../../templates.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Templates</p> - </button> - </a></li> - </ul> - </div> - </nav> - </div> - - -</div> -<div class="ng-scope"> - <div class="action_bar clearfix ng-scope"> - <div class="plus_btn_wrap"> - <div class="plus_btn_hover"> - <div class="add_dropdown more_options_menu" style="display: none;"> - <ul> - </ul> - </div> - </div> - </div> - <div class="action_menu_wrap"> - <div class="filter_wrap list_horizontal"></div> - </div> - </div> - <div id="eln_project_content" - class="eln_project_content eln_row eln_scroll-y ng-scope" data-id="118217" data-parentId="0" data-userId="30003" data-groupId="0" data-name="Example project" data-folder="false" data-template="false" data-createTS="22.10.2019 15:49" data-hidden="false" data-shareable="false" data-owner-profilePictureHash="null" data-owner-tutorial="1" data-owner-zoneId="Europe/Berlin" data-owner-id="30003" data-owner-firstname="max" data-owner-lastname="muster" data-owner-email="max.muster@posteo.de" data-numberOfBlocks="4" data-lastEditedTS="28.01.2020 10:12" data-adminUserIds="[]" data-adminOrOwner="true" > - <div id="epb_container"><div data-id="4624688"data-blockId="4624662"data-elnProjectId="118217"data-sourceId="0"data-userAction="8"data-groupId="0"data-hidden="false"data-readOnly="false"data-versionTS="22.10.2019 17:49"data-createTS="22.10.2019 17:49"data-signHash="null"data-signHashDescription=""data-signHashVersion="null"data-signTS="null"data-witnessTS="null"data-title="Example entry"data-blockNumber="1"data-totalBlocksInProject="4"data-projectName="Example project"data-projectReferenceId="null"data-signBiometricsDocId="null"data-witnessBiometricsDocId="null"data-referenced="false"> - <div class="epb_header_container"> - <div class="epb_header clearfix" style="display: block;"> - - <div class="entry_container"> - <header class="entry_header"> - <div class="entry_author"> - <figure> - <span class="avatar-img"></span> - <img ng-src=""> - </figure> - - <div class="author_name"> - <div class="author_firstname ng-binding">max</div> - <div class="author_lastname ng-binding">muster</div> - </div> - </div> - <div class="entry_menu_less entry_title_wrap ng-scope"> - <div class="entry_name_menu has_tooltip"> - <ul> - <li> - <div style="display:block">Entry 1/4:</div> - <div>In Project:</div> - </li> - <li> - <div style="display:block" class="entry_title ng-binding">Example entry</div> - <div>Example project</div> - </li> - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown entry_name"> - <div class="close_entry_menu"> - <span class="cancel_entry_title close_box-img"></span> - </div> - <ul> - <li><label>Entry name</label> <input - class="entry_name_input ng-pristine ng-untouched ng-valid" - type="text" data-title="" value=""></li> - <li><label>located in project</label> <select - class="ng-pristine ng-untouched ng-valid"> - <option - value="0">tableproject - </option> - <option value="1" selected="selected">a project</option> - </select></li> - <li> - <div class="save_entry_menu"> - <span class="cancel_dropdown cancel_entry_title grey_link" - ng-click="cancel()">cancel</span> - <button class="save_entry_title btn_on_grey" ng-click="save()">save</button> - </div> - </li> - </ul> - </div> - </div> - - <div class="entry_menus"> - <ul> - <li class="entry_menu_less ng-scope" - ng-controller="EntryDateController"> - <div class="entry_menu_list has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <ul> - <li><span>created:</span> <span class="ng-binding">22.10.2019 17:49</span> - </li> - <li><span>modified</span> <span class="ng-binding">22.10.2019 17:49</span> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li> - <span>due date</span> - <span class=\"ng-binding\">22.10.2019</span> -</li> -<li> - <span>my date</span> - <span class=\"ng-binding\">22.10.2019</span> -</li> - - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown" - ng-mouseenter="activateElement($event)"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <ul class="entry_dates"> - <li><label>Dates</label></li> - <li> - <div class="date_key"> - <input type="text" value="created" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.createTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <li> - <div class="date_key"> - <input type="text" value="modified" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.versionTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li style="overflow: visible;"> - <div class="date_key"> - - <div class="selectize-control single ng-valid" - ng-keyup="updateInput($select.search)" - reset-search-input="false" ng-model="dateKeyInput.selected" - theme="selectize" style="min-width: 120px;"> - <div class="selectize-input" - ng-class="{'focus': $select.open, 'disabled': $select.disabled, 'selectize-focus' : $select.focus}" - ng-click="$select.activate()"> - <div - ng-hide="$select.searchEnabled && ($select.open || $select.isEmpty())" - class="ui-select-match ng-hide" ng-transclude="" - placeholder="Custom date" - ng-keydown="inputKeydown($event)"> - <span class="ng-binding ng-scope"></span> - </div> - <input type="text" autocomplete="off" tabindex="-1" - class="ui-select-search ui-select-toggle ng-pristine ng-untouched ng-valid" - ng-click="$select.toggle($event)" - placeholder="Custom date" ng-model="$select.search" - ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" - ng-disabled="$select.disabled"> - </div> - <div ng-show="$select.open" - class="ui-select-choices selectize-dropdown single ng-scope ng-hide" - repeat="date in availableDates | filter: $select.search"> - <div - class="ui-select-choices-content selectize-dropdown-content"> - <div class="ui-select-choices-group optgroup"> - <div ng-show="$select.isGrouped" - class="ui-select-choices-group-label optgroup-header ng-binding ng-hide"></div> - <!-- ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">due date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">my date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - </div> - </div> - </div> - <input ng-disabled="$select.disabled" - class="ui-select-focusser ui-select-offscreen ng-scope" - type="text" aria-haspopup="true" role="button"> - </div> - </div> - - <div class="date_value"> - <input type="text" - class="entry_datepicker date_input ng-pristine ng-untouched ng-valid" - ng-model="dateValueInput" ng-keydown="inputKeydown($event)"> - </div> - </li> - </ul> - <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click="save()">save</button> - </div> - </div> - </li> - <li class="entry_menu_less ng-scope" - ng-controller="EntryTagsController"> - <div class="entry_tags has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <span>demo</span><span>example</span><span>entry</span> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <label>Create new tags by using commas</label> - <div class="token_input token_input_width"></div> - <div class="tags_input entry_tags_input" ng-click="focusInput()"> - - <!-- ngRepeat: tag in currentTokens --> - - <textarea class="token_input ng-pristine ng-untouched ng-valid" - ng-model="tagInput" ng-keydown="inputKeydown($event)"></textarea> - </div> - - <!-- <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click='fromViewModel()'>fromViewModel</button> - </div> --> - <h3 class="all_tags">All tags</h3> - <div class="tag_data_wrap"> - <div class="tag_register"> - <ul> - <li> - <ul class="my_tags"> - <!-- ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">demo</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">Entry</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">example</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - </ul> - </li> - </ul> - </div> - </div> - </div> - </li> - <li> - <div class="entry_options"> - <ul> - </ul> - </div> - </li> - </ul> - </div> - </header> - <div class="entry_toolbar"></div> - </div> - <div class="clear"></div> - </div> -</div> - - <div class="epb_content_wrap"> - <div class="epb_content_container"> - <div class="hdrop ui-droppable"></div> - <div class="dd_entry_table"> - <div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p><p style="text-align: center;text-align: center;"><span style="color: rgb(61, 142, 185);"><strong>Use the buttons above to add text, tables, handwritten sketches, files, or data elements.</strong></span></p></p> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p><p style="text-align: center;text-align: center;"><strong><span style="font-size: 24px;">I am a text block</span></strong>.</p><p><br /></p><p style="text-align: justify;text-align: justify;">You can capture all your notes in me immediately after creating an entry. Use all the tools in the editor to style your texts, add numbered and bulleted lists, insert simple tables, and use special characters.</p><p style="text-align: justify;text-align: justify;"><br /></p><p style="text-align: justify;text-align: justify;">Look at this example:</p><p style="text-align: justify;text-align: justify;"><br /></p><h2 style="text-align: justify;text-align: justify;"><strong><span style="color: rgb(51, 51, 51);">Cloning plasmid for inducible mCherry-Wt1</span></strong></h2><table style="width: 100%;"><tbody><tr><td style="background-color: rgb(239, 239, 239);width: 33.3333%;"><strong>Primer</strong></td><td style="background-color: rgb(239, 239, 239);width: 33.3333%;"><strong>Sequence (5' -3')</strong></td><td style="background-color: rgb(239, 239, 239);width: 33.3333%;"><strong>Melting temperature (T<sub>m</sub>)</strong></td></tr><tr><td style="width: 33.3333%;">Fwd pSV40 Kan/Neo</td><td style="width: 33.3333%;">gtc ttc aag aat tcc tca gaa gaa ctc gtc aag<br /></td><td style="width: 33.3333%;">56 °C<br /></td></tr><tr><td style="width: 33.3333%;">Rev pSV40 Kan/Neo</td><td style="width: 33.3333%;">tga tag gga gta aac gag gtg cac tct cag tac<br /></td><td style="width: 33.3333%;">55 °C<br /></td></tr><tr><td style="width: 33.3333%;">Fwd IRES</td><td style="width: 33.3333%;">cct ttc gtc ttc aag gat atc cgg ccc ggt tgt ggc cat a<br /></td><td style="width: 33.3333%;">56 °C<br /></td></tr><tr><td style="width: 33.3333%;">Rev IRES</td><td style="width: 33.3333%;">cga gtt ctt ctg acg gcc ggc ccc tct ccc t<br /></td><td style="width: 33.3333%;">52 °C<br /></td></tr><tr><td style="width: 33.3333%;">Fwd PolyA Tet-ON 3G</td><td style="width: 33.3333%;">cga gtt ctt ctg acg gcc ggc ccc tct ccc t<br /></td><td style="width: 33.3333%;">53 °C<br /></td></tr><tr><td style="width: 33.3333%;">Rev PolyA Tet-ON 3G</td><td style="width: 33.3333%;">a caa ccg ggc cgg ata tgt cta gac tgg aca aga g<br /></td><td style="width: 33.3333%;">58 °C<br /></td></tr></tbody></table><p style="text-align: justify;text-align: justify;"><br /></p></p> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" data-imageOriginalDocId="945829" data-imageLayerDocId="null" data-zoomLevel="50" data-blockVersionId="4624688" data-filename="image_element.png" data-elementNumber="7" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_file_download"> - <i>image_element.png</i> - <br> - <div class="dd_entry_cell_content"> - <img class="imageOriginal" src="image_945829_4624688_image_element.png" width="50%"> - </div> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p><p style="text-align: center;text-align: center;"><span style="font-size: 24px;"><strong>Table Element</strong></span></p><p style="text-align: center;text-align: center;">You can record your data with the Table Element below to later perform operations, do calculations, or create charts.</p></p> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" {{elementMeta1}}> - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content table-el-container"> - <div> - <div class="table-el-info"> - Your labfolder table is available for visualization as the following Excel file: - </div> - <div class="table-el-download"> - <a href="labfolder_table_4624688_11.xlsx"> - <svg class="table-el-icon" viewBox="0 0 475.1 402.5"> - <title>icon-table</title> - <path d="M461.7,14C452.7,5,442,0.5,429.4,0.5H45.7C33.1,0.5,22.4,5,13.4,14C4.5,22.9,0,33.7,0,46.2v310.6 c0,12.6,4.5,23.3,13.4,32.3c8.9,8.9,19.7,13.4,32.3,13.4h383.7c12.6,0,23.3-4.5,32.3-13.4c8.9-9,13.4-19.7,13.4-32.3V46.2 C475.1,33.7,470.6,22.9,461.7,14z M146.2,356.9c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7c-2.7,0-4.9-0.9-6.6-2.6 c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6 L146.2,356.9L146.2,356.9z M146.2,247.2c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7c-2.7,0-4.9-0.9-6.6-2.6 c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L146.2,247.2L146.2,247.2z M146.2,137.6c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7 c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L146.2,137.6L146.2,137.6z M292.4,356.9c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6h-91.4 c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L292.4,356.9L292.4,356.9L292.4,356.9z M292.4,247.2c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6 h-91.4c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6h91.4 c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6L292.4,247.2L292.4,247.2z M292.4,137.6c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6h-91.4c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.9-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6L292.4,137.6L292.4,137.6z M438.5,356.9 c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V356.9z M438.5,247.2c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V247.2z M438.5,137.6c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V137.6z"/> - </svg> - <div class="table-el-filename"> - labfolder_table_4624688_11.xlsx - </div> - </a> - </div> - </div> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell" data-width="50" - style="width: 50%;"> - <div class="dd_entry_cell_wrapper" ><div class="dd_entry_cell_content redactor_editor"> - <p><p><span style="font-size: 24px;"><strong>File Elements</strong></span></p><p><br /></p><p>You can upload and directly view PDF files in labfolder. See the example one on the right side. >></p></p> -</div> -</div> - </div> - <div class="dd_entry_cell"> - <div class="dd_entry_cell_wrapper" data-blockId="4624688" data-elementNumber="8" data-filename="click_on_view.pdf" data-fileSize="67.7 KB" data-fileDocId="945830" data-fileExists="true" ><div class="dd_entry_cell_file_download"> - <div class="file_icon"> - <div class="file_extension">pdf</div> - <span class="icon-file"></span> - </div> - <div class="file_details"> - <div class="file_name">click_on_view.pdf</div> - <div class="file_size_link"> - 67.7 KB <a href="click_on_view_4624688_8.pdf" - target="_blank"> Download </a> - </div> - </div> -</div> -</div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p>Check out the Microsoft Word® and Excel® support. After uploading a file you can do the following: <ul> <li><strong>Preview:</strong> Shows you a preview to see the content of the file.</li> <li><strong>Extract: </strong>All content from a file will be extracted and added to the entry.</li> <li><strong>Download: </strong>You can always download a file, which you uploaded to labfolder.</li> </ul></p> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell" data-width="50" - style="width: 50%;"> - <div class="dd_entry_cell_wrapper" data-blockId="4624688" data-elementNumber="9" data-filename="click_on_preview.docx" data-fileSize="66.8 KB" data-fileDocId="945831" data-fileExists="true" ><div class="dd_entry_cell_file_download"> - <div class="file_icon"> - <div class="file_extension">docx</div> - <span class="icon-file"></span> - </div> - <div class="file_details"> - <div class="file_name">click_on_preview.docx</div> - <div class="file_size_link"> - 66.8 KB <a href="click_on_preview_4624688_9.docx" - target="_blank"> Download </a> - </div> - </div> -</div> -</div> - </div> - <div class="dd_entry_cell"> - <div class="dd_entry_cell_wrapper" data-blockId="4624688" data-elementNumber="10" data-filename="click_on_extract.xlsx" data-fileSize="20.8 KB" data-fileDocId="945832" data-fileExists="true" ><div class="dd_entry_cell_file_download"> - <div class="file_icon"> - <div class="file_extension">xlsx</div> - <span class="icon-file"></span> - </div> - <div class="file_details"> - <div class="file_name">click_on_extract.xlsx</div> - <div class="file_size_link"> - 20.8 KB <a href="click_on_extract_4624688_10.xlsx" - target="_blank"> Download </a> - </div> - </div> -</div> -</div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell" data-width="53" - style="width: 53%;"> - <div class="dd_entry_cell_wrapper" ><div class="dd_entry_cell_content redactor_editor"> - <p><p><span style="font-size: 24px;"><strong>Data Element</strong></span></p><p><br /></p><p>The Data Element (DE) can be found in the entry toolbar next to the <em>Text</em>, <em>Table</em>, <em>Sketch</em> and <em>Upload</em> functions. You have these possibilities when working on the DE:</p><p><br /></p><ul><li>Insert a <em>Numerical Data Element</em> for quantitative experimental parameters.</li><li>Insert a <em>Descriptive Data Element</em> to document parameters with qualitative data.</li><li>Insert a <em>Data Group</em> with several experimental parameters.</li><li>Insert an item from your Material Database, referenced here as a <em>Material Element</em>.</li></ul><p><br /></p><p>Explore the example to the right. >></p></p> -</div> -</div> - </div> - <div class="dd_entry_cell"> - <div class="dd_entry_cell_wrapper" ><div class="notebook-element-content data-elements-container data-elements"> - <html><head></head><body><div class="data-element-wrap data-group-wrap"> - <svg class="data-element-icon data-group-icon" viewbox="0 0 67 64"> - <title>icon-vf-group-filled</title> - <path d="M32.119 39.613c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M0.952 39.019c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.275c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.138z"></path> - <path d="M29.502 36.996c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M49.487 11.063c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M19.39 10.587c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.427-1.071-1.903l-12.372-7.019z"></path> - <path d="M46.87 8.565c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M66.498 40.327c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M35.331 39.851c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0 0 0 0 0 0 0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.019z"></path> - <path d="M64 37.71c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595c0 0 0 0 0 0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - </svg> - - <div class="data-group-content display-mode"> - <div class="data-element-wrap data-group-header"> - <div class="data-element-display data-group-display"> - <span class="element-title">PCR reaction pSV40-Tet3G-TRE3G-mCherry</span> - </div> - </div> - - <div class="data-group-children"> - <div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">5X In-Fusion HD Enzyme Premix</span> - <span class="element-quantity">: Volume: </span> - <span class="element-value ">2 </span> - <span class="element-unit">µL</span> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">Linearized pSV40 vector</span> - <span class="element-quantity">: Volume: </span> - <span class="element-value ">7 </span> - <span class="element-unit">µL</span> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">Purified PCR fragment</span> - <span class="element-quantity">: Volume: </span> - <span class="element-value ">8 </span> - <span class="element-unit">µL</span> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">dH2O (as needed)</span> - <span class="element-quantity">: Volume: </span> - <span class="element-value ">8 </span> - <span class="element-unit">µL</span> - </div> -</div> - - </div> - </div> -</div> -</body></html><html><head></head><body><div class="data-element-wrap descriptive-element-wrap"> - <svg class="data-element-icon descriptive-element-icon" viewbox="0 0 64 64"> - <title>icon-dde</title> - <path d="M62.080 48.96h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.024-0.832-1.92-1.92-1.92z"></path> - <path d="M62.080 24.192h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - <path d="M37.504 0h-35.584c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h35.584c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - </svg> - - <div class="data-element-display descriptive-element-display"> - <span class="element-title">Human Monocytes: </span> - <span class="element-description ">Prepared</span> - </div> -</div> -</body></html> -</div> -</div> - </div> - </div> -</div> - - </div> - </div> -</div> - - -</div><div data-id="4625717"data-blockId="4625197"data-elnProjectId="118217"data-sourceId="0"data-userAction="5"data-groupId="0"data-hidden="false"data-readOnly="false"data-versionTS="22.10.2019 20:01"data-createTS="22.10.2019 18:47"data-signHash="null"data-signHashDescription=""data-signHashVersion="null"data-signTS="null"data-witnessTS="null"data-title="null"data-blockNumber="2"data-totalBlocksInProject="4"data-projectName="Example project"data-projectReferenceId="null"data-signBiometricsDocId="null"data-witnessBiometricsDocId="null"data-referenced="false"> - <div class="epb_header_container"> - <div class="epb_header clearfix" style="display: block;"> - - <div class="entry_container"> - <header class="entry_header"> - <div class="entry_author"> - <figure> - <span class="avatar-img"></span> - <img ng-src=""> - </figure> - - <div class="author_name"> - <div class="author_firstname ng-binding">max</div> - <div class="author_lastname ng-binding">muster</div> - </div> - </div> - <div class="entry_menu_less entry_title_wrap ng-scope"> - <div class="entry_name_menu has_tooltip"> - <ul> - <li> - <div style="display:block">Entry 2/4:</div> - <div>In Project:</div> - </li> - <li> - <div style="display:block" class="entry_title ng-binding"><em>No entry title yet</em></div> - <div>Example project</div> - </li> - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown entry_name"> - <div class="close_entry_menu"> - <span class="cancel_entry_title close_box-img"></span> - </div> - <ul> - <li><label>Entry name</label> <input - class="entry_name_input ng-pristine ng-untouched ng-valid" - type="text" data-title="" value=""></li> - <li><label>located in project</label> <select - class="ng-pristine ng-untouched ng-valid"> - <option - value="0">tableproject - </option> - <option value="1" selected="selected">a project</option> - </select></li> - <li> - <div class="save_entry_menu"> - <span class="cancel_dropdown cancel_entry_title grey_link" - ng-click="cancel()">cancel</span> - <button class="save_entry_title btn_on_grey" ng-click="save()">save</button> - </div> - </li> - </ul> - </div> - </div> - - <div class="entry_menus"> - <ul> - <li class="entry_menu_less ng-scope" - ng-controller="EntryDateController"> - <div class="entry_menu_list has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <ul> - <li><span>created:</span> <span class="ng-binding">22.10.2019 18:47</span> - </li> - <li><span>modified</span> <span class="ng-binding">22.10.2019 20:01</span> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown" - ng-mouseenter="activateElement($event)"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <ul class="entry_dates"> - <li><label>Dates</label></li> - <li> - <div class="date_key"> - <input type="text" value="created" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.createTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <li> - <div class="date_key"> - <input type="text" value="modified" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.versionTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li style="overflow: visible;"> - <div class="date_key"> - - <div class="selectize-control single ng-valid" - ng-keyup="updateInput($select.search)" - reset-search-input="false" ng-model="dateKeyInput.selected" - theme="selectize" style="min-width: 120px;"> - <div class="selectize-input" - ng-class="{'focus': $select.open, 'disabled': $select.disabled, 'selectize-focus' : $select.focus}" - ng-click="$select.activate()"> - <div - ng-hide="$select.searchEnabled && ($select.open || $select.isEmpty())" - class="ui-select-match ng-hide" ng-transclude="" - placeholder="Custom date" - ng-keydown="inputKeydown($event)"> - <span class="ng-binding ng-scope"></span> - </div> - <input type="text" autocomplete="off" tabindex="-1" - class="ui-select-search ui-select-toggle ng-pristine ng-untouched ng-valid" - ng-click="$select.toggle($event)" - placeholder="Custom date" ng-model="$select.search" - ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" - ng-disabled="$select.disabled"> - </div> - <div ng-show="$select.open" - class="ui-select-choices selectize-dropdown single ng-scope ng-hide" - repeat="date in availableDates | filter: $select.search"> - <div - class="ui-select-choices-content selectize-dropdown-content"> - <div class="ui-select-choices-group optgroup"> - <div ng-show="$select.isGrouped" - class="ui-select-choices-group-label optgroup-header ng-binding ng-hide"></div> - <!-- ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">due date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">my date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - </div> - </div> - </div> - <input ng-disabled="$select.disabled" - class="ui-select-focusser ui-select-offscreen ng-scope" - type="text" aria-haspopup="true" role="button"> - </div> - </div> - - <div class="date_value"> - <input type="text" - class="entry_datepicker date_input ng-pristine ng-untouched ng-valid" - ng-model="dateValueInput" ng-keydown="inputKeydown($event)"> - </div> - </li> - </ul> - <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click="save()">save</button> - </div> - </div> - </li> - <li class="entry_menu_less ng-scope" - ng-controller="EntryTagsController"> - <div class="entry_tags has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <i>No tags associated</i> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <label>Create new tags by using commas</label> - <div class="token_input token_input_width"></div> - <div class="tags_input entry_tags_input" ng-click="focusInput()"> - - <!-- ngRepeat: tag in currentTokens --> - - <textarea class="token_input ng-pristine ng-untouched ng-valid" - ng-model="tagInput" ng-keydown="inputKeydown($event)"></textarea> - </div> - - <!-- <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click='fromViewModel()'>fromViewModel</button> - </div> --> - <h3 class="all_tags">All tags</h3> - <div class="tag_data_wrap"> - <div class="tag_register"> - <ul> - <li> - <ul class="my_tags"> - <!-- ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">demo</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">Entry</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">example</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - </ul> - </li> - </ul> - </div> - </div> - </div> - </li> - <li> - <div class="entry_options"> - <ul> - </ul> - </div> - </li> - </ul> - </div> - </header> - <div class="entry_toolbar"></div> - </div> - <div class="clear"></div> - </div> -</div> - - <div class="epb_content_wrap"> - <div class="epb_content_container"> - <div class="hdrop ui-droppable"></div> - <div class="dd_entry_table"> - <div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p><h1>bcvncbvn</h1></p> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_empty_element"><div><i>Empty File Element</i></div></div> - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" data-imageOriginalDocId="946047" data-imageLayerDocId="946048" data-zoomLevel="50" data-blockVersionId="4625717" data-filename="blank.png" data-elementNumber="4" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_file_download"> - <i>blank.png</i> - <br> - <div class="dd_entry_cell_content"> - <img class="imageOriginal" src="image_946047_4625717_blank.png" width="50%"> - </div> -</div> - - </div> - </div> - </div> -</div> - - </div> - </div> -</div> - - -</div><div data-id="4625212"data-blockId="4625203"data-elnProjectId="118217"data-sourceId="4625184"data-userAction="24"data-groupId="0"data-hidden="false"data-readOnly="false"data-versionTS="22.10.2019 18:48"data-createTS="22.10.2019 18:48"data-signHash="null"data-signHashDescription=""data-signHashVersion="null"data-signTS="null"data-witnessTS="null"data-title="null"data-blockNumber="3"data-totalBlocksInProject="4"data-projectName="Example project"data-projectReferenceId="null"data-signBiometricsDocId="null"data-witnessBiometricsDocId="null"data-referenced="false"> - <div class="epb_header_container"> - <div class="epb_header clearfix" style="display: block;"> - - <div class="entry_container"> - <header class="entry_header"> - <div class="entry_author"> - <figure> - <span class="avatar-img"></span> - <img ng-src=""> - </figure> - - <div class="author_name"> - <div class="author_firstname ng-binding">max</div> - <div class="author_lastname ng-binding">muster</div> - </div> - </div> - <div class="entry_menu_less entry_title_wrap ng-scope"> - <div class="entry_name_menu has_tooltip"> - <ul> - <li> - <div style="display:block">Entry 3/4:</div> - <div>In Project:</div> - </li> - <li> - <div style="display:block" class="entry_title ng-binding"><em>No entry title yet</em></div> - <div>Example project</div> - </li> - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown entry_name"> - <div class="close_entry_menu"> - <span class="cancel_entry_title close_box-img"></span> - </div> - <ul> - <li><label>Entry name</label> <input - class="entry_name_input ng-pristine ng-untouched ng-valid" - type="text" data-title="" value=""></li> - <li><label>located in project</label> <select - class="ng-pristine ng-untouched ng-valid"> - <option - value="0">tableproject - </option> - <option value="1" selected="selected">a project</option> - </select></li> - <li> - <div class="save_entry_menu"> - <span class="cancel_dropdown cancel_entry_title grey_link" - ng-click="cancel()">cancel</span> - <button class="save_entry_title btn_on_grey" ng-click="save()">save</button> - </div> - </li> - </ul> - </div> - </div> - - <div class="entry_menus"> - <ul> - <li class="entry_menu_less ng-scope" - ng-controller="EntryDateController"> - <div class="entry_menu_list has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <ul> - <li><span>created:</span> <span class="ng-binding">22.10.2019 18:48</span> - </li> - <li><span>modified</span> <span class="ng-binding">22.10.2019 18:48</span> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li> - <span>todo</span> - <span class=\"ng-binding\">31.10.2019</span> -</li> - - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown" - ng-mouseenter="activateElement($event)"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <ul class="entry_dates"> - <li><label>Dates</label></li> - <li> - <div class="date_key"> - <input type="text" value="created" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.createTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <li> - <div class="date_key"> - <input type="text" value="modified" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.versionTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li style="overflow: visible;"> - <div class="date_key"> - - <div class="selectize-control single ng-valid" - ng-keyup="updateInput($select.search)" - reset-search-input="false" ng-model="dateKeyInput.selected" - theme="selectize" style="min-width: 120px;"> - <div class="selectize-input" - ng-class="{'focus': $select.open, 'disabled': $select.disabled, 'selectize-focus' : $select.focus}" - ng-click="$select.activate()"> - <div - ng-hide="$select.searchEnabled && ($select.open || $select.isEmpty())" - class="ui-select-match ng-hide" ng-transclude="" - placeholder="Custom date" - ng-keydown="inputKeydown($event)"> - <span class="ng-binding ng-scope"></span> - </div> - <input type="text" autocomplete="off" tabindex="-1" - class="ui-select-search ui-select-toggle ng-pristine ng-untouched ng-valid" - ng-click="$select.toggle($event)" - placeholder="Custom date" ng-model="$select.search" - ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" - ng-disabled="$select.disabled"> - </div> - <div ng-show="$select.open" - class="ui-select-choices selectize-dropdown single ng-scope ng-hide" - repeat="date in availableDates | filter: $select.search"> - <div - class="ui-select-choices-content selectize-dropdown-content"> - <div class="ui-select-choices-group optgroup"> - <div ng-show="$select.isGrouped" - class="ui-select-choices-group-label optgroup-header ng-binding ng-hide"></div> - <!-- ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">due date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">my date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - </div> - </div> - </div> - <input ng-disabled="$select.disabled" - class="ui-select-focusser ui-select-offscreen ng-scope" - type="text" aria-haspopup="true" role="button"> - </div> - </div> - - <div class="date_value"> - <input type="text" - class="entry_datepicker date_input ng-pristine ng-untouched ng-valid" - ng-model="dateValueInput" ng-keydown="inputKeydown($event)"> - </div> - </li> - </ul> - <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click="save()">save</button> - </div> - </div> - </li> - <li class="entry_menu_less ng-scope" - ng-controller="EntryTagsController"> - <div class="entry_tags has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <label>Create new tags by using commas</label> - <div class="token_input token_input_width"></div> - <div class="tags_input entry_tags_input" ng-click="focusInput()"> - - <!-- ngRepeat: tag in currentTokens --> - - <textarea class="token_input ng-pristine ng-untouched ng-valid" - ng-model="tagInput" ng-keydown="inputKeydown($event)"></textarea> - </div> - - <!-- <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click='fromViewModel()'>fromViewModel</button> - </div> --> - <h3 class="all_tags">All tags</h3> - <div class="tag_data_wrap"> - <div class="tag_register"> - <ul> - <li> - <ul class="my_tags"> - <!-- ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">demo</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">Entry</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">example</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - </ul> - </li> - </ul> - </div> - </div> - </div> - </li> - <li> - <div class="entry_options"> - <ul> - </ul> - </div> - </li> - </ul> - </div> - </header> - <div class="entry_toolbar"></div> - </div> - <div class="clear"></div> - </div> -</div> - - <div class="epb_content_wrap"> - <div class="epb_content_container"> - <div class="hdrop ui-droppable"></div> - <div class="dd_entry_table"> - <div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p><p>Text ist hier</p></p> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="notebook-element-content data-elements-container data-elements"> - <html><head></head><body><div class="data-element-wrap data-group-wrap"> - <svg class="data-element-icon data-group-icon" viewbox="0 0 67 64"> - <title>icon-vf-group-filled</title> - <path d="M32.119 39.613c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M0.952 39.019c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.275c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.138z"></path> - <path d="M29.502 36.996c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M49.487 11.063c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M19.39 10.587c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.427-1.071-1.903l-12.372-7.019z"></path> - <path d="M46.87 8.565c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M66.498 40.327c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M35.331 39.851c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0 0 0 0 0 0 0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.019z"></path> - <path d="M64 37.71c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595c0 0 0 0 0 0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - </svg> - - <div class="data-group-content display-mode"> - <div class="data-element-wrap data-group-header"> - <div class="data-element-display data-group-display"> - <span class="element-title">gruppe 1</span> - </div> - </div> - - <div class="data-group-children"> - <div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">foo</span> - <span class="element-quantity">: Angular Momentum: </span> - <span class="element-value ">20€ </span> - <span class="element-unit">kg/m<sup>2</sup> s<sup>-1</sup></span> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">barium</span> - <span class="element-quantity">: Fugacity: </span> - <span class="element-value ">12 </span> - <span class="element-unit">Pa</span> - </div> -</div> - - </div> - </div> -</div> -</body></html><html><head></head><body><div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">dsf</span> - <span class="element-quantity">: Electric Displacement: </span> - <span class="element-value ">8765^98x90 </span> - <span class="element-unit">C/m<sup>2</sup></span> - </div> -</div> -</body></html><html><head></head><body><div class="data-element-wrap descriptive-element-wrap"> - <svg class="data-element-icon descriptive-element-icon" viewbox="0 0 64 64"> - <title>icon-dde</title> - <path d="M62.080 48.96h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.024-0.832-1.92-1.92-1.92z"></path> - <path d="M62.080 24.192h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - <path d="M37.504 0h-35.584c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h35.584c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - </svg> - - <div class="data-element-display descriptive-element-display"> - <span class="element-title">DE name: </span> - <span class="element-description ">fdgdfghgfdhgdfhh dfghdfghdfghfgh dfghdfgd</span> - </div> -</div> -</body></html><html><head></head><body><div class="data-element-wrap data-group-wrap"> - <svg class="data-element-icon data-group-icon" viewbox="0 0 67 64"> - <title>icon-vf-group-filled</title> - <path d="M32.119 39.613c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M0.952 39.019c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.275c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.138z"></path> - <path d="M29.502 36.996c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M49.487 11.063c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M19.39 10.587c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.427-1.071-1.903l-12.372-7.019z"></path> - <path d="M46.87 8.565c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M66.498 40.327c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M35.331 39.851c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0 0 0 0 0 0 0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.019z"></path> - <path d="M64 37.71c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595c0 0 0 0 0 0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - </svg> - - <div class="data-group-content display-mode"> - <div class="data-element-wrap data-group-header"> - <div class="data-element-display data-group-display"> - <span class="element-title">gruppe 2</span> - </div> - </div> - - <div class="data-group-children"> - <div class="data-element-wrap data-group-wrap"> - <svg class="data-element-icon data-group-icon" viewbox="0 0 67 64"> - <title>icon-vf-group-filled</title> - <path d="M32.119 39.613c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M0.952 39.019c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.275c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.138z"></path> - <path d="M29.502 36.996c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M49.487 11.063c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M19.39 10.587c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.427-1.071-1.903l-12.372-7.019z"></path> - <path d="M46.87 8.565c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M66.498 40.327c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M35.331 39.851c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0 0 0 0 0 0 0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.019z"></path> - <path d="M64 37.71c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595c0 0 0 0 0 0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - </svg> - - <div class="data-group-content display-mode"> - <div class="data-element-wrap data-group-header"> - <div class="data-element-display data-group-display"> - <span class="element-title">Untergruppe 2.1</span> - </div> - </div> - - <div class="data-group-children"> - <div class="data-element-wrap descriptive-element-wrap"> - <svg class="data-element-icon descriptive-element-icon" viewbox="0 0 64 64"> - <title>icon-dde</title> - <path d="M62.080 48.96h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.024-0.832-1.92-1.92-1.92z"></path> - <path d="M62.080 24.192h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - <path d="M37.504 0h-35.584c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h35.584c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - </svg> - - <div class="data-element-display descriptive-element-display"> - <span class="element-title">DE name 2 (desc): </span> - <span class="element-description empty-value">⎵</span> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">DE 2.1.1</span> - <span class="element-quantity">: Amount of substance: </span> - <span class="element-value ">20 </span> - <span class="element-unit">mol</span> - </div> -</div> - - </div> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">DE 2.2</span> - <span class="element-quantity">: Capacitance: </span> - <span class="element-value ">876x876x87 </span> - <span class="element-unit">µF</span> - </div> -</div> - - </div> - </div> -</div> -</body></html> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" {{elementMeta1}}> - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content table-el-container"> - <div> - <div class="table-el-info"> - Your labfolder table is available for visualization as the following Excel file: - </div> - <div class="table-el-download"> - <a href="labfolder_table_4625212_3.xlsx"> - <svg class="table-el-icon" viewBox="0 0 475.1 402.5"> - <title>icon-table</title> - <path d="M461.7,14C452.7,5,442,0.5,429.4,0.5H45.7C33.1,0.5,22.4,5,13.4,14C4.5,22.9,0,33.7,0,46.2v310.6 c0,12.6,4.5,23.3,13.4,32.3c8.9,8.9,19.7,13.4,32.3,13.4h383.7c12.6,0,23.3-4.5,32.3-13.4c8.9-9,13.4-19.7,13.4-32.3V46.2 C475.1,33.7,470.6,22.9,461.7,14z M146.2,356.9c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7c-2.7,0-4.9-0.9-6.6-2.6 c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6 L146.2,356.9L146.2,356.9z M146.2,247.2c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7c-2.7,0-4.9-0.9-6.6-2.6 c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L146.2,247.2L146.2,247.2z M146.2,137.6c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7 c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L146.2,137.6L146.2,137.6z M292.4,356.9c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6h-91.4 c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L292.4,356.9L292.4,356.9L292.4,356.9z M292.4,247.2c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6 h-91.4c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6h91.4 c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6L292.4,247.2L292.4,247.2z M292.4,137.6c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6h-91.4c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.9-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6L292.4,137.6L292.4,137.6z M438.5,356.9 c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V356.9z M438.5,247.2c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V247.2z M438.5,137.6c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V137.6z"/> - </svg> - <div class="table-el-filename"> - labfolder_table_4625212_3.xlsx - </div> - </a> - </div> - </div> -</div> - - </div> - </div> - </div> -</div> - - </div> - </div> -</div> - - -</div><div data-id="5026191"data-blockId="5026165"data-elnProjectId="118217"data-sourceId="4624688"data-userAction="36"data-groupId="0"data-hidden="false"data-readOnly="false"data-versionTS="28.01.2020 11:12"data-createTS="28.01.2020 11:10"data-signHash="null"data-signHashDescription=""data-signHashVersion="null"data-signTS="null"data-witnessTS="null"data-title="null"data-blockNumber="4"data-totalBlocksInProject="4"data-projectName="Example project"data-projectReferenceId="null"data-signBiometricsDocId="null"data-witnessBiometricsDocId="null"data-referenced="false"> - <div class="epb_header_container"> - <div class="epb_header clearfix" style="display: block;"> - - <div class="entry_container"> - <header class="entry_header"> - <div class="entry_author"> - <figure> - <span class="avatar-img"></span> - <img ng-src=""> - </figure> - - <div class="author_name"> - <div class="author_firstname ng-binding">max</div> - <div class="author_lastname ng-binding">muster</div> - </div> - </div> - <div class="entry_menu_less entry_title_wrap ng-scope"> - <div class="entry_name_menu has_tooltip"> - <ul> - <li> - <div style="display:block">Entry 4/4:</div> - <div>In Project:</div> - </li> - <li> - <div style="display:block" class="entry_title ng-binding"><em>No entry title yet</em></div> - <div>Example project</div> - </li> - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown entry_name"> - <div class="close_entry_menu"> - <span class="cancel_entry_title close_box-img"></span> - </div> - <ul> - <li><label>Entry name</label> <input - class="entry_name_input ng-pristine ng-untouched ng-valid" - type="text" data-title="" value=""></li> - <li><label>located in project</label> <select - class="ng-pristine ng-untouched ng-valid"> - <option - value="0">tableproject - </option> - <option value="1" selected="selected">a project</option> - </select></li> - <li> - <div class="save_entry_menu"> - <span class="cancel_dropdown cancel_entry_title grey_link" - ng-click="cancel()">cancel</span> - <button class="save_entry_title btn_on_grey" ng-click="save()">save</button> - </div> - </li> - </ul> - </div> - </div> - - <div class="entry_menus"> - <ul> - <li class="entry_menu_less ng-scope" - ng-controller="EntryDateController"> - <div class="entry_menu_list has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <ul> - <li><span>created:</span> <span class="ng-binding">28.01.2020 11:10</span> - </li> - <li><span>modified</span> <span class="ng-binding">28.01.2020 11:12</span> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li> - <span>due date</span> - <span class=\"ng-binding\">22.10.2019</span> -</li> -<li> - <span>my date</span> - <span class=\"ng-binding\">22.10.2019</span> -</li> - - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown" - ng-mouseenter="activateElement($event)"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <ul class="entry_dates"> - <li><label>Dates</label></li> - <li> - <div class="date_key"> - <input type="text" value="created" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.createTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <li> - <div class="date_key"> - <input type="text" value="modified" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.versionTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li style="overflow: visible;"> - <div class="date_key"> - - <div class="selectize-control single ng-valid" - ng-keyup="updateInput($select.search)" - reset-search-input="false" ng-model="dateKeyInput.selected" - theme="selectize" style="min-width: 120px;"> - <div class="selectize-input" - ng-class="{'focus': $select.open, 'disabled': $select.disabled, 'selectize-focus' : $select.focus}" - ng-click="$select.activate()"> - <div - ng-hide="$select.searchEnabled && ($select.open || $select.isEmpty())" - class="ui-select-match ng-hide" ng-transclude="" - placeholder="Custom date" - ng-keydown="inputKeydown($event)"> - <span class="ng-binding ng-scope"></span> - </div> - <input type="text" autocomplete="off" tabindex="-1" - class="ui-select-search ui-select-toggle ng-pristine ng-untouched ng-valid" - ng-click="$select.toggle($event)" - placeholder="Custom date" ng-model="$select.search" - ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" - ng-disabled="$select.disabled"> - </div> - <div ng-show="$select.open" - class="ui-select-choices selectize-dropdown single ng-scope ng-hide" - repeat="date in availableDates | filter: $select.search"> - <div - class="ui-select-choices-content selectize-dropdown-content"> - <div class="ui-select-choices-group optgroup"> - <div ng-show="$select.isGrouped" - class="ui-select-choices-group-label optgroup-header ng-binding ng-hide"></div> - <!-- ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">due date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">my date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - </div> - </div> - </div> - <input ng-disabled="$select.disabled" - class="ui-select-focusser ui-select-offscreen ng-scope" - type="text" aria-haspopup="true" role="button"> - </div> - </div> - - <div class="date_value"> - <input type="text" - class="entry_datepicker date_input ng-pristine ng-untouched ng-valid" - ng-model="dateValueInput" ng-keydown="inputKeydown($event)"> - </div> - </li> - </ul> - <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click="save()">save</button> - </div> - </div> - </li> - <li class="entry_menu_less ng-scope" - ng-controller="EntryTagsController"> - <div class="entry_tags has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <span>demo</span><span>example</span><span>entry</span> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <label>Create new tags by using commas</label> - <div class="token_input token_input_width"></div> - <div class="tags_input entry_tags_input" ng-click="focusInput()"> - - <!-- ngRepeat: tag in currentTokens --> - - <textarea class="token_input ng-pristine ng-untouched ng-valid" - ng-model="tagInput" ng-keydown="inputKeydown($event)"></textarea> - </div> - - <!-- <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click='fromViewModel()'>fromViewModel</button> - </div> --> - <h3 class="all_tags">All tags</h3> - <div class="tag_data_wrap"> - <div class="tag_register"> - <ul> - <li> - <ul class="my_tags"> - <!-- ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">demo</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">Entry</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">example</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - </ul> - </li> - </ul> - </div> - </div> - </div> - </li> - <li> - <div class="entry_options"> - <ul> - </ul> - </div> - </li> - </ul> - </div> - </header> - <div class="entry_toolbar"></div> - </div> - <div class="clear"></div> - </div> -</div> - - <div class="epb_content_wrap"> - <div class="epb_content_container"> - <div class="hdrop ui-droppable"></div> - <div class="dd_entry_table"> - - </div> - </div> -</div> - - -</div></div> - <div id="epb_newer_blocks_panel"></div> - </div> -</div> -</body> -</html> diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/labfolder_table_4624688_11.xlsx b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/labfolder_table_4624688_11.xlsx deleted file mode 100644 index 251f84c2f7ef25c567bef65102a16134b5d453e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12036 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 WAPw=OQ<wlufWuSq%8TY1^8WzRRbNj4 diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/labfolder_table_4625212_3.xlsx b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/labfolder_table_4625212_3.xlsx deleted file mode 100644 index 83d3d8119085d311ceb5a54e56c5363351aa1c0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5564 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 JzW?F?{sqL?Yd`=1 diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/original_image_946047_4625717_blank.png b/unittests/example_labfolder_data/projects/My private projects_0/118217_Example project/original_image_946047_4625717_blank.png deleted file mode 100644 index 27d041f3a61aa472e57cb5447c3eb8aa364ca210..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2399 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i0*Z)=h^hlA#^NA%Cx&(BWL^R}oCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#E*BS%5+7gY`RhO-$r9Iy66gHf+|;}h2Ir#G#FEq$ zh4Rdj3<Y;j-+=H&K5+&Hjx(Mvjv*Dd-d-~l1oDm;9N7Q-ILq-V9xtx=0bO!Ol9Pdf zM~tE2AQOW@1OtPF4g*6oD?`Et1~8Y6o8dqLBbZByB9I<}CLt+;*^X%)c118JLfu3i zMGR2ep$<oK6OwhvijYDCsFkoHq!0mW#bFYuia?Qu<ZvW6A(@1v2o$rVC_)Nb+=+rz zMMz-_(u(9JB$JR7A%!hSl%OKy5CNuU>?V<{2r1ZT65mL%1d2N(>##?qgwAN*g(jUr z7ni`uLv|ApaY;mkBjppK%4(#1GMaaZC<U;`5>29VH19$h8EAovx3GS2o{2GqeQjzc SR}`@E!{F)a=d#Wzp$PyhU8Ya~ diff --git a/unittests/example_labfolder_data/projects/My private projects_0/118224_subproj 1/index.html b/unittests/example_labfolder_data/projects/My private projects_0/118224_subproj 1/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/unittests/example_labfolder_data/static/css/combined.css b/unittests/example_labfolder_data/static/css/combined.css deleted file mode 100644 index a2cc2529..00000000 --- a/unittests/example_labfolder_data/static/css/combined.css +++ /dev/null @@ -1,10061 +0,0 @@ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -table.adminTable { - background-color: white; - border-collapse: collapse; -} -table.adminTable th { - font-weight: bold; - border: 1px solid black; - padding: 10px; -} -table.adminTable th .info { - font-size: 10px; - width: 120px; -} -table.adminTable td { - border: 1px solid black; - padding: 10px; -} -#percentage { - border: 1px solid black; - height: 20px; - width: 200px; - background: white; - position: relative; - text-align: center; - color: black; - font-weight: bold; - display: none; -} -#percentage div { - height: 100%; - width: 0%; - background: #33FF33; - position: absolute; - top: 0; - left: 0; -} -#percentage span { - height: 100%; - width: 100%; - position: absolute; - top: 0; - left: 0; -} -#messages { - width: 500px; - height: 300px; - overflow: scroll; -} -#buttonCancel { - margin-top: 20px; - width: 150px; - height: 30px; - display: none; -} - -/*********** -* apps.css * -************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.app_card { - background-color: white; - border: 1px solid #bac7d4; - float: left; - height: 260px; - margin: 10px; - padding: 10px; - overflow: hidden; - text-align: center; - width: 144px; - -webkit-transition: all 0.1s ease; - -moz-transition: all 0.1s ease; - -o-transition: all 0.1s ease; - transition: all 0.1s ease; -} -.app_card:hover { - -webkit-box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); -} -.app_card_icon { - width: 100px; - height: 100px; -} -.app_card_icon:hover, -.app_card_title:hover { - cursor: pointer; -} -.app_card .app_install_button { - width: 100%; -} -.app_installed_info { - line-height: 1.4; - font-size: 13px; -} -.app_card_title { - margin-top: 5px; - margin-bottom: 5px; - font-size: 16px; - height: 44px; -} -.app_card_lastUpdate { - font-size: 12px; - line-height: 1.6; - color: #7b95ad; - margin-bottom: 20px; -} -.app_info_top_left { - float: left; - width: 200px; - padding-top: 25px; - text-align: center; -} -.app_info_top_right { - margin-left: 202px; - padding-top: 25px; -} -.app_info_icon { - border: 1px solid #CCC; - border-radius: 10px; - width: 150px; - height: 150px; -} -.app_info_top_left .app_install_button { - width: 150px; - margin-top: 15px; - margin-left: 25px; -} -.app_info_title { - margin-top: 0; - margin-bottom: 20px; - font-size: 24px; -} -.app_info_description { - line-height: 20px; - max-width: 600px; -} -.app_info_lastUpdate { - font-size: 12px; - color: #aaa; - margin-bottom: 20px; -} -.app_info_preview { - padding-top: 15px; - padding-bottom: 25px; -} -.app_info_preview_left { - float: left; - width: 175px; - padding-left: 25px; -} -.app_info_preview_right { - margin-left: 202px; -} -.app_info_preview_small { - border: 3px solid #CCC; - width: 150px; - margin-bottom: 10px; - cursor: pointer; - transition: all ease 0.3s; -} -.app_info_preview_big { - border: 3px solid #CCC; - width: 600px; - height: 350px; -} -.app_info_preview_small.selected { - border: 3px solid #69bfee; - box-shadow: 0 0 10px #69bfee; -} - -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} - -/****************************** - COMMENTS COLLECTION -*******************************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.eln_main_content_box.comments { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - height: auto; - min-height: 400px; - margin: 0 25px 0 0; -} -#comments_header { - background: #EEE; - border-bottom: 1px solid #D6D4D5; - border-radius: 10px 10px 0 0; - display: block; - font-size: 14px; - height: 35px; - padding: 10px 0px 5px 15px; -} -#comments_content { - max-width: 900px; - padding-left: 10px; - display: block; - line-height: 18px; - position: relative; - overflow: auto; -} -.comment_pagination { - position: relative; - float: left; -} -.comment_pagination, -.comment_total, -.comment_shown { - font-size: 11px; -} -.message_pagination { - position: relative; - float: left; -} -.comment_page_change { - box-sizing: border-box; - cursor: pointer; - display: inline-block; - width: 30px; - text-align: center; - font-size: 22px; - margin: 0; - line-height: 0.6; - height: 17px; - margin-top: 4px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; -} -.comment_page_change.disabled .disabled { - color: #5e7b97; - cursor: default; -} -.comment_empty_folder { - padding: 50px; - text-align: center; - font-size: 12px; -} -.comment_list { - font-size: 14px; -} -.comment_list table { - border-collapse: collapse; - outline: none; - table-layout: fixed; - width: 100%; -} -.comment_list table tr td:last-child { - font-size: 11px; -} -.comment_list_line { - font-size: 12px; - border-bottom: 1px solid #bac7d4; - cursor: pointer; - height: 34px; - line-height: 1.2; - white-space: nowrap; -} -.comment_list_line:hover { - background: #ecf0f3; -} -.comment_list_line:first-child:hover { - background: none; - cursor: default; -} -.comment_line_name { - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: bottom; - overflow: hidden; - padding-left: 4px; -} -.comment_line_text { - overflow: hidden; - text-overflow: ellipsis; -} -.column_comment_name { - min-width: 100px; - width: 25%; -} -.column_comment_project { - min-width: 100px; - width: 25%; -} -.column_comment_content { - min-width: 100px; - width: 50%; -} -.column_comment_date { - width: 89px; -} -.table_header { - color: #7b95ad; - font-size: 12px; -} -.grey_line { - border-bottom: solid 1px #9baec0; -} -/****************************** - COMMENT SIDE VIEW -*******************************/ -.comment_block_container { - /* border-left: 1px solid #DDD; */ - display: none; - font-size: 12px; - min-height: 25px; - overflow-y: auto; - overflow-x: hidden; - position: relative; - vertical-align: top; - min-width: 250px; - width: 15%; -} -.comment_block { - border-radius: 0 0 10px 0; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 15px; - right: 0; -} -.add_comment { - display: block; - margin: 10px; - text-align: center; -} -.epb_entry_removed .comment_block_container { - display: none !important; -} -.epb_entry_removed .epb_comments_alert { - display: none !important; -} -/****************************** - COMMENT THREAD -*******************************/ -.comment_thread_box { - background: white; - border: 1px solid #bac7d4; - margin-bottom: 10px; - min-height: 40px; - padding: 5px; - position: relative; -} -.comment_thread_box:after, -.comment_thread_box:before { - right: 100%; - top: 23px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; -} -.comment_thread_box:after { - border-right-color: white; - border-width: 13px; - margin-top: -13px; -} -.comment_thread_box:before { - border-right-color: #c0ccd8 !important; - border-width: 15px; - margin-top: -15px; -} -.comment_thread_resolve { - cursor: pointer; - text-align: right; - margin-bottom: 10px; -} -.comment_thread_resolve span { - font-size: 8px; -} -.comment_thread_resolve:hover { - color: #4bb1d7; -} -.comment_thread_resolve.disabled { - color: #aaa; - cursor: default; -} -/****************************** - COMMENT ITEM -*******************************/ -.comment_content_wrap { - float: left; - width: 174px; -} -.comment_item { - /* border-bottom: 1px solid lighten(@dark_blue, 60%); */ - margin-bottom: 10px; - overflow: auto; -} -.comment_item:last-child { - border: 0; - padding-bottom: 20px; -} -.comment_author_picture { - border: 1px solid #bac7d4; - float: left; - margin-right: 6px; - margin-top: 2px; -} -.comment_author { - color: #3babe9; - margin-right: 3px; - font-weight: bold; -} -.comment_content, -.comment_content_resizer { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - line-height: 18px; - margin: 5px 0px 0px; - width: 174px; - white-space: pre-line; - word-wrap: break-word; -} -.comment_content.default_textfield, -.comment_content_resizer.default_textfield { - background: #FFF; - font-size: 12px; - min-height: 26px; - line-height: 18px; - margin: 2px 0 0 0; - overflow: hidden; - padding: 5px; - resize: none; - border-radius: 0; - border-color: #d9e1e8; - vertical-align: middle; -} -.comment_content.default_textfield { - height: 25px; -} -.comment_content.default_textfield:focus { - /* box-shadow: 0 0 3px #4bb1d7; */ -} -.comment_content_label { - position: relative; -} -.comment_content_label label { - position: absolute; - top: -20px; - left: 6px; - color: #9baec0; - font-style: italic; - font-family: Arial; - cursor: text; - font-size: 12px; -} -.comment_cancel { - float: right; - padding: 10px; -} -.comment_publish, -.comment_edit { - float: right; - height: 22px; - position: relative; - margin: 5px 0 0 0; -} -.comment_user_actions { - display: none; - margin: 8px 0; -} -.comment_user_actions .edit_light-img { - margin: 2px 20px 0 0; -} -.comment_timestamp { - margin-right: 23px; - line-height: 1.8; - float: left; - font-size: 10px; - color: #9baec0; -} -.comment_action { - padding: 5px; -} -.comment_content_resizer, -.comment_edit, -.comment_published.readOnly .comment_user_actions, -.comment_published.comment_editing .comment_user_actions, -.comment_published .comment_publish { - display: none; -} -.comment_editing .comment_edit, -.comment_published .comment_user_actions { - display: block; -} -.comment_editing { - padding-bottom: 35px; -} -.bottonShowComments, -.bottonHideComments { - display: none; -} -.comment_content_wrap .default_textfield { - border: 1px solid #bac7d4; -} - -/****************************** - Dashboard VIEW -*******************************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.dashboard_item { - width: 50%; - min-width: 460px; - height: 45%; - min-height: 300px; - padding: 10px 20px 0 4px; - margin-top: 5px; - overflow: auto; - float: left; -} -.dashboard_item_menu { - background: #EEE; - border-bottom: 1px solid #D6D4D5; - display: block; - font-size: 14px; - height: 35px; - padding: 10px 0px 5px 15px; - margin: 0; - list-style-type: none; -} -.dashboard_item_menu > li { - height: 65%; - float: left; - display: block; - margin-right: 10px; - padding-right: 14px; - padding-top: 9px; - border-right: solid 1px #D6D4D5; -} -.dashboard_item h2 { - margin-top: 2px; - display: block; - font-weight: normal; -} -.dashboard_item h2 a { - color: #374858; - text-decoration: none; -} -.dashboard_item .default_button { - float: right; - margin-right: 10px; -} -.eln_main_content_box.apps { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - margin: 0 25px 0 0; - padding: 20px; - height: 95%; - overflow: auto; -} -.apps_decoration { - opacity: 0.3; - font-size: 45px; - text-align: center; - margin-top: 50px; -} -.dashboard_apps_info { - cursor: default; - font-size: 14px; -} -.dashboard_apps_tooltip { - opacity: 0; - font-size: 14px; - transition: all ease-in 0.3s; -} -.dashboard_apps_info:hover + .dashboard_apps_tooltip { - opacity: 1; -} -.create_list, -.create_item { - background: rgba(255, 255, 255, 0.6); - border: 1px solid #bac7d4; - height: 25px; - padding-left: 5px; - color: #4b6277; - margin-top: 10px; - width: 90%; - font-size: 14px; - /* .inner-shadow(-1px, -1px, 1px, 0.2); */ -} -.create_item { - margin: 0 0 10px 0; -} -.done_item_wrap .listed_item { - text-decoration: line-through; -} -.todolist_btn { - text-align: left; - color: #4b6277; - background: #f3f5f7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #f3f5f7)); - background: -ms-linear-gradient(bottom, #e0e6eb, #f3f5f7); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #f3f5f7 100%); - background: -o-linear-gradient(#f3f5f7, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f5f7', endColorstr='#e0e6eb', GradientType=0); - border: 1px solid #9baec0; - width: 90%; - margin: 0 0 4px 0; - cursor: pointer; -} -.todolist_btn:hover { - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; - border: 1px solid #7b95ad; - -webkit-box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); - -moz-box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); - box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); -} -.todolist_btn:active { - color: #4b6277; - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #7b95ad; - background: #cad4de; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #cad4de)); - background: -ms-linear-gradient(bottom, #e0e6eb, #cad4de); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #cad4de 100%); - background: -o-linear-gradient(#cad4de, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cad4de', endColorstr='#e0e6eb', GradientType=0); -} -.active_todo_list { - background: white; - border: 1px solid #9baec0; - cursor: default; - position: relative; -} -.active_todo_list:hover, -.active_todo_list:active { - border: 1px solid #5e7b97; -} -.active_todo_list:after { - right: 0px; - top: 11px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-left-color: #374858; - border-width: 5px; - margin-top: -5px; -} -.todolist_collection { - width: 34%; - height: 100%; - padding-right: 3%; - display: inline-block; -} -.todolist_collection > ul { - margin: 0; - padding: 0; -} -.todolist_collection > ul li { - list-style-type: none; -} -.selected_list { - width: 65%; - min-height: 100%; - height: auto; - display: inline-block; - padding: 2% 2% 2% 5%; - vertical-align: top; - background: white; - border-radius: 3px; - border: 1px solid #9baec0; -} -.selected_list ul { - margin: 0; - padding: 0; - list-style: none; -} -.item_wrap { - margin: 3px 0; -} -.item_wrap .trash-img { - display: none; - cursor: pointer; -} -.item_wrap:hover { - background: #f3f5f7; -} -.item_wrap:hover .trash-img { - display: block; -} -.todolist_btn_wrap .trash-img { - display: none; - cursor: pointer; -} -.todolist_btn_wrap:hover .trash-img { - display: block; -} -.todolist_wrap { - padding-top: 20px; -} -.todolist_wrap label { - color: #a7b8c8; - font-size: 12px; -} -.todolist_wrap h3 { - font-weight: normal; - font-size: 14px; - margin: 0 0 10px 10px; - display: inline-block; -} -.todolist_wrap .trash-img { - margin-top: 2px; -} -.todolist_wrap input { - position: relative; - vertical-align: middle; - bottom: 1px; -} -.listed_item { - display: inline-block; -} -::-webkit-input-placeholder { - /* WebKit browsers */ - color: #9baec0; -} -:-moz-placeholder { - /* Mozilla Firefox 4 to 18 */ - color: #9baec0; - opacity: 1; -} -::-moz-placeholder { - /* Mozilla Firefox 19+ */ - color: #9baec0; - opacity: 1; -} -:-ms-input-placeholder { - /* Internet Explorer 10+ */ - color: #9baec0; -} -@media (max-width: 1380px) { - .todolist_btn { - width: 80%; - } -} -@media (max-width: 970px) { - .todolist_btn { - width: 88%; - } - .dashboard_item { - width: 100%; - } -} - -.re-deviceData { - background-image: url(/static/img/design/devices-icon.png); -} - -.re-deviceData:hover { - background-image: url(/static/img/design/devices-hover-icon.png); -} - -#devices_library .device_log { - padding: 10px; - margin: 10px; - border-bottom: 1px solid #BBB; -} - -#devices_library li { - list-style: none; -} - -#devices_library .device_line { - font-size: 14px; - line-height: 30px; - list-style: none; - width: 600px; - padding: 5px; -} - -#devices_library .device_line:hover { - background: #EDEDED; -} - -#devices_library .device_header { - font-size: 14px; - margin-bottom: 10px; -} - -.device_file, .device_data { - cursor: pointer !important; - float: right !important; - right: 0 !important; -} - -.devices_popup { - width: 750px !important; - left: 50% !important; - margin-left: -375px !important; -}/******************* -* eln_layout.css * -********************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -::selection { - background: #c5e6f8; -} -::-moz-selection { - background: #c5e6f8; -} -*, -*::before, -*::after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -a { - cursor: pointer; -} -body { - font-size: 14px; - margin: 0; - padding: 0; - font-family: arial, sans-serif; - height: 100%; - width: 100%; -} -html { - height: 100%; -} -.body_bg { - background: #ffffff url(../img/squares.png); - height: 100%; - width: 100%; - position: fixed; - z-index: -1; - top: 33px; - left: -10px; -} -a { - text-decoration: none; - color: #1995d8; - outline: none; -} -a:hover { - text-decoration: none; -} -img { - border: 0; -} -button { - margin: 0; -} -button::-moz-focus-inner { - border: 0; -} -.clear { - clear: both; -} -.content_top_margin { - margin-top: 50px; -} -/****************************** - DEFAULT BLUE BUTTONS -*******************************/ -.default_button { - border: 1px solid #455a6e; - padding: 4px 8px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - color: white; - opacity: 1; - line-height: 1.2; - background: #304d69; - font-size: 14px; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - -o-transition: all 0.1s linear; - transition: all 0.1s linear; - -webkit-backface-visibility: hidden; - cursor: pointer; - /* background-color:#374858; */ - /* border:1px solid #ffffff; */ - /* border-radius:6px; */ - /* box-shadow:0px 0px 1px black; */ - /* -webkit-box-sizing: border-box; */ - /* -moz-box-sizing: border-box; */ - /* box-sizing: border-box; */ - /* color:#ffffff; */ - /* cursor:pointer; */ - /* display:inline-block; */ - /* float:left; */ - /* font-family:din-medi; */ - /* font-size:14px; */ - /* height:28px; */ - /* line-height:28px; */ - /* margin:0 1px 1px 0; */ - /* outline: none; */ - /* padding: 0 10px; */ - /* transition: background-color 0.2s ease, box-shadow 0.2s ease; */ -} -.default_button:hover, -.default_button:focus { - background: #375877; - -ms-filter: none; - filter: none; - outline: 0; - color: white; - text-decoration: none; -} -.default_button:active { - background: #304d69; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.5); - -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.5); - box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.5); -} -.default_button:hover { - /* background-color: #607D99; */ - /* text-decoration:none; */ -} -.default_button:active { - opacity: 1.0; - /* box-shadow:0px 0px 10px #888888; */ - /* text-decoration:none; */ -} -.default_button.disabled { - opacity: 0.5; - /* background-color:#DDD; */ - /* border:1px solid #FFF; */ - /* box-shadow:0px 0px 1px #AAA; */ - /* color:#AAA; */ - /* cursor:default; */ -} -/****************************** - DEFAULT FIELDS -*******************************/ -.default_textfield { - background-color: white; - border: 0; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - font-family: Arial; - color: #4b6277; - font-size: 14px; - line-height: 1.8; - font-style: normal; - font-variant: normal; - font-weight: normal; - margin: 0 5px 5px 0; - padding-left: 5px; - min-height: 30px; - transition: box-shadow ease 0.2s; -} -.textfield_on_white { - border: solid 1px #bac7d4; -} -.default_textfield:hover { - /* box-shadow: 0 0 3px #69bfee; */ -} -.default_textfield:focus { - /* border: 1px solid #69bfee; */ - /* box-shadow: 0 0 6px #69bfee; */ -} -/****************************** - DEFAULT SELECT -*******************************/ -.default_select { - background: #FFF; - border: 1px solid #d9e1e8; - color: #4b6277; - cursor: pointer; - margin: 0 0 0 10px; - padding: 4px 4px 4px 8px; -} -.dialog_wide_select { - margin: 0; - width: 100%; -} -/****************************** - DEFAULT PROFILE PICTURE -*******************************/ -img.default_profile_picture { - border: 1px solid #888; - height: 100px; - width: 100px; -} -img.default_profile_picture_small { - border: 1px solid #888; - height: 32px; - width: 32px; - margin-top: 3px; -} -/* ****************** */ -/* more_options START */ -/* ****************** */ -.more_options { - float: right; - position: relative; -} -.more_options_panel { - position: absolute; - right: 0; - z-index: 10; - display: none; - -webkit-box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - border: 1px solid #CDCDCD; - /* border-radius: 10px; */ - background-color: #FDFDFD; -} -.more_options_panel.in_project { - top: 38px; -} -.more_options_panel.in_block { - top: 40px; -} -.more_options_item { - font-size: 12px; - /* line-height: 40px; */ - padding-left: 12px; - padding-right: 12px; - cursor: pointer; - /* border-top: 1px solid #D6D4D5; */ - transition: background ease 0.2s; -} -.more_options_item:hover { - /* background: #ededed; */ - /* color: #69bfee; */ -} -.more_options_item:first-child { - /* border-radius: 10px 10px 0 0; */ - /* border: 0; */ -} -.more_options_item:last-child { - /* border-radius: 0 0 10px 10px; */ -} -.more_options_item span { - position: absolute; - right: 0; -} -div.zoom_bar { - width: 180px; - padding: 4px 14px !important; - height: 44px; - -webkit-user-select: none; - /* Chrome all / Safari all */ - -moz-user-select: none; - /* Firefox all */ - -ms-user-select: none; - /* IE 10+ */ -} -div.zoom_bar:hover { - background: #e6ebef; -} -div.zoom_bar:hover { - color: #374858; -} -/* **************** */ -/* more_options END */ -/* **************** */ -/* ****************** */ -/* gear_button START */ -/* ****************** */ -/* ************ */ -/* layout START */ -/* ************ */ -/* generic rules */ -.eln_row { - left: 0; - right: 0; - /* overflow:hidden; */ - position: absolute; -} -.eln_scroll-x { - overflow-x: auto; -} -.eln_scroll-y { - overflow-y: scroll; -} -/* specific rules */ -.eln_header.eln_row { - position: relative; - /* height:50px; */ - /* background: #FFF; */ - /* box-shadow:0 3px 10px #BBB; */ - min-width: 800px; -} -.eln_content.eln_row { - top: 70px; - bottom: 0; - margin-left: 200px; - min-width: 600px; -} -.eln_main_title.eln_row { - top: 70px; - margin-right: 40px; - margin-left: 100px; - min-width: 436px; - overflow: visible; -} -.eln_main_content.eln_row { - top: 86px; - bottom: 0; - margin-left: 49px; - min-width: 600px; -} -.eln_folder_title.eln_row { - top: 70px; - margin-left: 100px; - min-width: 600px; - overflow: visible; -} -.eln_folder_content.eln_row { - top: 86px; - bottom: 0; - margin-left: 49px; - min-width: 640px; -} -.eln_project_title.eln_row { - top: 70px; - margin-left: 100px; - min-width: 640px; - overflow: visible; -} -.eln_project_content.eln_row { - top: 86px; - bottom: 0; - /* margin-left:100px; */ - margin-left: 29px; - min-width: 600px; -} -.eln_main_content_box { - height: auto; - min-height: 400px; - margin: 0 25px 25px 0; - background-color: white; - border-bottom: solid 1px #cad4de; - border-left: solid 1px #cad4de; - border-right: solid 1px #cad4de; - position: relative; - padding: 20px 20px 20px 135px; - color: #4b6277; -} -.eln_main_content_box .header { - display: block; - font-size: 24px; - height: 35px; -} -.eln_main_content_box .header button { - margin-right: 10px; -} -.app_wrap { - position: relative; - background: #f3f5f7; - border: solid 1px #cad4de; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - height: calc(95% - 15px); -} -.app_content_wrap { - max-width: 900px; - padding: 10px; - display: block; - line-height: 18px; - position: absolute; - overflow: auto; - top: 10px; - left: 0; - right: 0; - bottom: 0px; -} -.app_header { - height: 29px; - background: #cad4de; - padding: 6px; -} -.app_header > h2 { - display: block; - float: left; - font-size: 14px; - margin: 0 13px 0 0; - color: #374858; -} -.app_header .filter_dn_wrap { - top: 23px; -} -.app_header .dropdown_button { - height: 20px; -} -.app_header .dropdown_button p { - margin: 0; - float: left; -} -.app_header .dropdown_button span { - height: 4px; - width: 12px; - display: block; - float: left; - margin: 2px 0 0 4px; -} -.app_plus_btn { - width: 35px; - height: 18px; - line-height: 1; - margin-right: 2px !important; - padding: 0; -} -.get_more_apps { - height: 100%; - padding: 20px; -} -/* ********** */ -/* layout END */ -/* ********** */ -/* ****************** */ -/* action links START */ -/* ****************** */ -.action_link_submit { - background: url(/static/img/design/action/submit.png) top right no-repeat; - width: 112px; - height: 25px; - display: block; -} -.action_link_submit:hover { - background-image: url(/static/img/design/action/submit_hover.png); -} -.action_link_signout { - background: url(/static/img/design/action/signout.png); - width: 83px; - height: 24px; - display: block; - float: right; - margin: 10px 0; -} -.action_link_signout:hover { - background: url(/static/img/design/action/signout_hover.png); -} -.action_link_profile { - background: url(/static/img/design/action/profile.png); - width: 71px; - height: 24px; - display: block; - float: right; - margin: 10px 0; -} -.action_link_profile:hover { - background: url(/static/img/design/action/profile_hover.png); -} -/* **************** */ -/* action links END */ -/* **************** */ -/* ************ */ -/* header START */ -/* ************ */ -/* LOGO */ -.eln_header_logo { - float: left; - padding-top: 7px; - padding-left: 17px; -} -/* Storage icon */ -#eln_header_storage_button { - background: none repeat scroll 0 0 transparent; - border: none; - cursor: pointer; - float: right; - font-size: 14px; - margin-top: 5px; - padding: 0; - height: 27px; - width: 32px; -} -#eln_header_storage_button span { - font-size: 10px; - margin-top: 14px; - position: absolute; - text-align: center; - width: 32px; - z-index: 6; -} -#eln_header_storage_stored { - background-color: #ededed; - height: 32px; - width: 32px; -} -#eln_header_storage_mask { - position: absolute; - z-index: 5; -} -#eln_header_storage_fill { - background-color: #BDCA70; - bottom: -5px; - position: absolute; - width: 32px; - z-index: 2; -} -/* Storage drop down panel */ -#eln_header_storage_panel { - background-color: #FFFFFF; - border: 3px solid #DDDDDD; - top: 53px; - z-index: 7; -} -#eln_header_storage_info { - cursor: default; -} -#eln_header_storage_info:hover { - color: #374858; -} -#eln_header_storage_info span { - font-size: 14px; - padding-right: 10px; - text-align: right; - width: 80px; -} -/* Storage percent bar */ -#eln_header_storage_bar_container { - float: right; - padding: 12px 10px 0; -} -#eln_header_storage_bar { - border: 1px solid #888; - height: auto; - line-height: 15px; - padding: 2px; - position: relative; - width: 80px; -} -span#eln_header_storage_bar_percent { - font-size: 12px; - line-height: 12px; - padding: 0; - position: absolute; - text-align: center; - width: 80px; -} -#eln_header_storage_bar_fill { - background-color: #bdca70; - height: 10px; -} -#eln_header_name { - display: inline-block; - line-height: 40px; - text-align: center; - text-overflow: ellipsis; - overflow: hidden; - padding: 0 5px; - vertical-align: top; - white-space: nowrap; -} -#eln_header_name div { - display: inline; -} -#eln_header_actions { - margin-right: 43px; -} -#eln_header_actions_button { - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - background: none repeat scroll 0 0 transparent; - border: none; - cursor: pointer; - float: right; - font-size: 14px; - height: 50px; - margin: 0; - padding: 5px; -} -#eln_header_storage_button:hover, -#eln_header_actions_button:hover { - cursor: pointer; - background: #ededed; - border: none; - border-radius: 0; -} -#eln_header_storage_button:active { - margin: 5px 1px 0px 0px; -} -div#eln_header_actions_button.active { - background: #ededed; - border: none; - border-radius: 0; - margin: 0; -} -#eln_header_arrow span { - font-size: 18px; -} -#eln_header_arrow { - display: inline-block; - margin-top: 8px; - padding-left: 5px; - vertical-align: top; -} -#eln_header_actions_panel { - background-color: #FFFFFF; - position: absolute; - top: 53px; - z-index: 7; -} -.eln_header_actions_item { - border-top: 1px solid #D6D4D5; - cursor: pointer; - font-size: 14px; - line-height: 40px; - padding: 0 20px; -} -.eln_header_actions_item:first-child { - border-top: 0; -} -.eln_header_actions_item span { - float: right; - font-size: 18px; - line-height: 18px; - padding-top: 12px; - text-align: center; - width: 36px; -} -.eln_header_actions_item:hover { - background: #ededed; - color: #69bfee; -} -.colorbar { - height: 4px; - background: url(/static/img/design/colorbar.png); -} -/* ************ */ -/* header END */ -/* ************ */ -/* **************** */ -/* navigation START */ -/* **************** */ -#eln_navigation { - position: fixed; - top: 70px; - width: 75px; - border-radius: 0 10px 0 0; - box-shadow: 0 3px 10px #888; - background: #FFF; - bottom: 0; - left: 0; - z-index: 2; - text-align: center; -} -#eln_navigation a { - border-bottom: 1px solid #d6d4d5; - display: block; - text-decoration: none; - padding: 10px 0; - font-size: 12px; - color: #374858; - transition: all ease 0.2s; -} -#eln_navigation a:hover { - background: #ededed; - color: #69bfee; -} -#eln_navigation a:first-child { - border-radius: 0 10px 0 0; -} -#eln_navigation span { - display: block; - font-size: 24px; - margin-bottom: 3px; -} -#eln_navigation span.icon-group { - font-size: 20px; - margin-left: 9px; -} -#eln_navigation span.icon-inventory { - margin-left: 4px; -} -#eln_navigation span.icon-template { - margin-left: 5px; -} -#eln_navigation .highlight { - color: #69bfee; -} -#eln_navigation .disabled, -#eln_navigation .disabled:hover { - color: #ccc; -} -#eln_navigation button { - border: 5px solid white; - border-radius: 10px; - color: #FFF; - cursor: pointer; - font-size: 11px; - outline: none; - width: 70px; - height: 70px; -} -#feedback_button span, -#invite_button span { - font-size: 22px; -} -#invite_button { - background-color: #bdca70; -} -#feedback_submit { - margin-right: 6px; - width: 60px; - height: 30px; - font-weight: bold; -} -#feedback_button { - background-color: #ad4e88; -} -.eln_navigation_support_buttons { - margin-top: 100px; -} -#feedback_panel { - display: none; - position: fixed; - top: -2px; - left: 0; - z-index: 102; - background: #d9e1e8; - border: 3px solid #ab48a9; - -webkit-box-shadow: 2px 6px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 2px 6px 10px rgba(55, 72, 88, 0.3); - box-shadow: 2px 6px 10px rgba(55, 72, 88, 0.3); -} -.feedback_title { - background: #ab48a9; - color: white; - padding: 5px; - text-align: center; - font-size: 15px; - line-height: 20px; -} -.feedback_title h4 { - display: inline-block; -} -.feedback_title img { - vertical-align: top; - margin-left: 10px; -} -.feedback_content { - padding: 10px; - width: 390px; -} -.feedback_content h4 { - font-size: 12px; -} -#feedback_panel h4 { - margin: 10px; - margin-bottom: 5px; -} -#feedback_comment { - margin: 0 10px 30px 10px; - margin-top: 0; - width: 350px; - height: 120px; -} -#feedback_submit_loader { - display: none; - margin: 8px 15px; -} -/* ************** */ -/* navigation END */ -/* ************** */ -/* ********* */ -/* EPB START */ -/* ********* */ -#epb_container { - /* padding-top: 10px; */ - /* padding-bottom: 80px; */ -} -img.imageOriginal { - border: 1px solid #DDD; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - transition: all linear 0.2s; -} -img.imageLayer { - left: 0; - margin-left: auto; - margin-right: auto; - position: absolute; - right: 0; - top: 0; - transition: all linear 0.2s; -} -#commentBlock { - border-radius: 10px; - cursor: pointer; - position: absolute; - right: 15px; - width: 200px; - background: #FFF; - top: 1px; -} -#epb_older_blocks_panel, -#epb_newer_blocks_panel { - text-align: center; - color: #999; - height: 30px; - line-height: 30px; - margin: 10px 0; -} -.show_more_entries { - font-size: 13px; - margin: auto; - width: 300px; - background: white; - padding: 10px; - text-align: center; - -webkit-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.3); - box-shadow: 0 3px 4px rgba(55, 72, 88, 0.3); -} -.show_more_entries span { - color: #1995d8; - cursor: pointer; -} -.epb_entry { - /* background-color: white; */ - /* border: 1px solid #CCC; */ - /* border-radius: 10px; */ - display: inline-block; - /* margin-right:25px; */ - margin-bottom: 20px; -} -#epb_container { - padding-bottom: 60px; -} -#epb_container > div { - margin: 1.5em 0; -} -.epb_entry:last-child { - margin-bottom: 10px; -} -.epb_entry_removed { - border: 1px solid #F88; - box-sizing: border-box; -} -.epb_entry p { - margin: 0 !important; -} -.epb_header { - /* height: 35px; */ - /* min-width: 640px; */ - /* border-bottom: 1px solid #d6d4d5; */ - /* padding: 10px 10px 0 10px; */ - /* background-color: #ededed; */ - /* border-radius: 10px 10px 0 0; */ - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; -} -/* .epb_header_container { */ -/* height: 45px; */ -/* } */ -.epb_header_sticky { - position: fixed; - top: 86px; - z-index: 10; - transition: width ease-in 0.3s; -} -.epb_header_sticky div.action_button_text { - margin-left: 5px; -} -.epb_header_sticky div.more_options { - margin-right: 5px; -} -/*Hack for comments*/ -.epb_content_wrap { - display: table; - /* width: 100%; */ -} -.epb_show_comments .epb_content_container { - display: table-cell; - width: 85%; -} -.epb_show_comments .comment_block_container { - display: table-cell; -} -/*End of comment Hack */ -.epb_footer { - font-size: 9px; - height: auto; - margin-left: 30px; - margin-right: 45px; - position: relative; - padding: 5px; - background: #cad4de; - border-top: solid 1px white; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); -} -.epb_footer_signing_infos { - display: inline-block; - text-align: left; -} -.epb_footer_witness_actions { - display: inline-block; - margin-right: 10px; -} -.epb_footer_witness_actions a { - padding-left: 10px; - line-height: 25px; -} -.epb_date { - border-right: 1px solid #d6d4d5; - margin-right: 10px; - padding-right: 10px; - padding-top: 2px; - font-size: 12px; - float: right; - text-align: right; -} -.epb_author { - border-right: 1px solid #d6d4d5; - margin-right: 10px; - padding-right: 10px; - padding-top: 2px; - padding-left: 5px; - font-size: 12px; - float: right; -} -.epb_author_picture { - border: 1px solid #d6d4d5; - float: right; - margin-top: 2px; -} -.epb_comments_alert { - /* color: #FFFFFF; */ - /* float:right; */ - /* margin-right: 5px; */ - cursor: pointer; -} -.epb_comments_count { - /* position: relative; */ - /* top: 7px; */ - /* left: 50%; */ - /* margin-left: 3px; */ - /* vertical-align: top; */ -} -.epb_header_action { - line-height: 24px; - padding-right: 15px; - padding-top: 2px; - font-size: 12px; - float: left; -} -.epb_default_slider_container { - cursor: pointer; -} -div.epb_relative_zoom { - margin-left: 2px; - font-size: 14px; - display: inline-block; - position: relative; - width: 12px; - height: 16px; - vertical-align: text-bottom; -} -div.epb_relative_zoom:hover { - /* color: #69bfee; */ -} -.epb_default_slider { - background-color: #ededed; - border: 1px solid #DDDDDD; - border-radius: 7px; - box-shadow: #B6B4A8 0 1px 7px inset; - box-sizing: border-box; - cursor: pointer; - display: inline-block; - height: 14px; - max-width: 100%; - overflow: hidden; - padding: 0; - position: relative; - width: 114px; - margin: 0 5px 0 4px; -} -.epb_default_slider_active { - background-color: #EFEFE7; - border: 1px solid #99968F; - border-radius: 6px; - box-sizing: border-box; - height: 12px; - position: relative; - width: 12px; - transition: all ease 0.2s; - left: 0; - z-index: 2; -} -.epb_default_slider_active:hover { - box-shadow: #888888 -1px -1px 3px inset; -} -.epb_default_slider_active:active { - background-color: #DDD; - box-shadow: #AAA 1px 1px 2px inset; -} -.epb_default_slider_bar { - background: #69bfee; - /* fallback */ - background: rgba(75, 177, 215, 0.5); - box-shadow: #B6B4A8 0 1px 7px inset; - box-sizing: border-box; - border-bottom-left-radius: 6px; - border-top-left-radius: 6px; - border: 0; - height: 16px; - margin-top: -14px; - padding: 0; - position: relative; - width: 0px; - transition: all ease 0.2s; - z-index: 1; -} -.epb_default_slider_zoom { - cursor: default; - display: block; - line-height: 30px; - width: 100%; - text-align: center; -} -.epb_text_save_cancel { - display: none; -} -.epb_text_save_cancel a { - padding-left: 10px; -} -.epb_file { - margin: 20px 0; -} -.epb_image { - margin: 20px 0; - position: relative; -} -.epb_image .imageLayer { - position: absolute; - top: 0; - left: 0; -} -.epb_image_zoom { - margin-top: 5px; -} -.epb_image_zoom img { - cursor: pointer; -} -.epb_image_zoom_square { - background-color: transparent; - border: 1px solid #666; - margin: 0 1px; -} -.epb_image_zoom_square_active { - background-color: #666; -} -.epb_new_panel { - background: #ededed; - border: 2px solid #CCC; - border-bottom: none; - border-radius: 5px 5px 0 0; - bottom: 0; - height: 40px; - left: 50%; - margin-left: -250px; - padding: 5px; - position: absolute; - text-align: center; - z-index: 2; -} -.epb_new_panel_middle { - background: url(/static/img/design/epb_new_panel_middle.png) repeat-x; - float: left; - height: 55px; - padding-top: 25px; -} -.epb_new_panel_left { - background: url(/static/img/design/epb_new_panel_left.png) no-repeat; - float: left; - height: 80px; - width: 30px; - position: relative; -} -.epb_new_panel_right { - background: url(/static/img/design/epb_new_panel_right.png) no-repeat; - float: left; - height: 80px; - width: 30px; -} -.epb_new_panel .default_button { - margin: 0 5px; -} -#epb_new_panel_jump_to_end { - display: none; -} -#epb_new_panel_jump_to_end div { - float: left; - font-size: 14px; - line-height: 30px; -} -.epb_entry_removed_msg_head { - display: none; - margin: 0 200px; - text-align: center; - color: #F88; - padding-top: 5px; -} -/* ******* */ -/* EPB END */ -/* ******* */ -/* ******************* */ -/* block history START */ -/* ******************* */ -.block_history_table { - border-collapse: collapse; - width: 100%; -} -tr.history_row:nth-child(odd) { - background-color: #fff; - cursor: pointer; - height: 23px; -} -tr.history_row:nth-child(even) { - background-color: #f0f0f0; - cursor: pointer; - height: 23px; -} -.block_history_table td.col1 { - padding: 3px 0 3px 5px; -} -.block_history_table td.col2 { - padding: 3px 10px 3px 10px; -} -.block_history_table td.col3 { - padding: 3px 0; -} -#block_history_navigation { - position: absolute; - width: 350px; - bottom: 0; - top: 30px; - left: 0; - overflow: auto; - border-right: 2px solid #374858; -} -#block_history_item_content { - position: absolute; - right: 0; - bottom: 0; - top: 30px; - left: 350px; - padding: 0 20px; - overflow: scroll; -} -.block_history_row_selected { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - background-color: #DDD !important; - color: #4BB1D1; -} -/* ***************** */ -/* block history END */ -/* ***************** */ -/* ************** */ -/* plupload START */ -/* ************** */ -.plupload_select { - width: 110px; - height: 24px; - margin: 0 auto; -} -.plupload_drop { - border: 2px dashed black; - width: 200px; - height: 80px; - margin: 0 auto; - background-color: #77ff66; -} -#plupload_container { - position: absolute; - top: -100px; - left: 0; - width: 100px; - height: 50px; - overflow: hidden; -} -/* ************ */ -/* plupload END */ -/* ************ */ -/* *************** */ -/* workspace START */ -/* *************** */ -.workspace_header_actions { - height: 50px; -} -.workspace_header_actions .default_button { - margin-right: 15px; -} -.workspace_header_link { - margin-right: 15px; - line-height: 36px; -} -.workspace_header_link span { - font-weight: bold; -} -/** Modified at the end of the section -.workspace_header { - background-color: #F3F3F3; - border: 1px solid #DDD; - line-height: 36px; - padding: 5px; - padding-left: 15px; -}*/ -.workspace_header_path a { - outline: none; - color: #fff; - text-decoration: none; -} -.workspace_header_path a:hover { - color: #69bfee; -} -.project_list_children { - display: none; - margin-left: 30px; -} -.project_list_head { - border: 1px solid #DDD; - border-radius: 10px; - background-color: #f3f3f3; - padding: 10px 0; - height: 12px; -} -.project_list_head .name { - margin-left: 15px; -} -.project_list_head .updateTS { - float: right; - margin-right: 15px; -} -.project_list { - min-height: 350px; - margin: 0 25px 25px 0; - background-color: #ffffff; - border-bottom: solid 1px #cad4de; - border-left: solid 1px #cad4de; - border-right: solid 1px #cad4de; - position: relative; - padding: 20px 20px 20px 135px; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); -} -.project_list_line { - /* background: url(/static/icon/project40.png) no-repeat 0 -40px; */ - display: block; - outline: none; - color: #4b6277; - cursor: pointer; - text-decoration: none; - line-height: 1.2; - font-size: 14px; - padding: 5px 15px; - border: 1px solid transparent; - overflow: hidden; -} -.project_list_line > span { - color: #4b6277; - line-height: 1.2; - font-size: 14px; -} -.project_list_line:hover { - background-position: 0 0; - background: #ecf0f3; - text-decoration: none; -} -.project_list_line.is_folder { - background: url(/static/icon/folder40.png) no-repeat 0 -40px; -} -.project_list_line:hover.is_folder { - background-position: 0 0; -} -.project_list_line.is_group { - /* background: url(/static/icon/group40.png) no-repeat 0 -40px; */ -} -.project_list_line:hover.is_group { - background-position: 0 0; -} -.project_list_line img { - vertical-align: top; -} -.project_list_line .name { - font-size: 14px; -} -.project_list_line .updateTS { - font-size: 15px; - float: right; - margin-right: 15px; -} -a.order_link { - font-size: 12px; - outline: none; - color: #374858; - text-decoration: none; -} -a.order_link:hover { - color: #69bfee; -} -a.order_link_asc { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -65px; -} -a.order_link_desc { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -45px; -} -a.order_link_asc:hover { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -25px; -} -a.order_link_desc:hover { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -5px; -} -.workspace_header { - background: #374858 repeat-x 0 0; - border: 1px solid #DDD; - border-radius: 10px; - height: 35px; - line-height: 5px; - padding: 5px 10px; -} -.workspace_name { - color: #FFFFFF; - float: left; - font-size: 24px; - height: 32px; - line-height: 32px; - margin-top: 5px; - overflow: hidden; - text-overflow: ellipsis; - width: 90%; - white-space: nowrap; -} -.workspace_name a { - color: #FFF; -} -.workspace_name a:hover { - color: #69bfee; - text-decoration: none; -} -/* ************* */ -/* workspace END */ -/* ************* */ -/* ******************* */ -/* profile block START */ -/* ******************* */ -#user_settings_innovation_level_form select { - background: #ffffff; - border: 1px solid #d9e1e8; - color: #5e7b97; - cursor: pointer; - margin: 0 0 0 10px; - padding: 4px 4px 4px 8px; - outline: 0; -} -#profile_picture_edit_panel { - float: left; - margin-right: 20px; - margin-bottom: 15px; - padding-left: 5px; -} -#profile_picture_edit_panel img { - border: 1px solid #bac7d4; - margin-top: 10px; - width: 100px; - height: 100px; -} -.profile_block { - padding-left: 15px; - width: 550px; - margin-bottom: 20px; -} -.profile_block_edit { - display: block; - float: right; - margin-right: 5px; - font-size: 12px; -} -.profile_edit .placeholder_frame { - margin: 0 5px 5px 0; -} -.project_pdf_export_list { - background: #ffffff; - border: 1px solid #DDD; - height: 125px; - margin: 15px 0 30px 0; - padding: 5px; - overflow-y: scroll; -} -.project_pdf_export_list div { - line-height: 18px; - height: 18px; - overflow: hidden; -} -.pdf_range_export label { - display: block; - text-align: left; -} -/*FIND A BETTER WAY WITH last-child*/ -#profile_contact { - border: none; - padding-bottom: 0px; -} -#profile_picture_edit_link { - position: relative; -} -#profile_picture_edit_panel span { - opacity: 0; - height: 25px; - left: 0; - line-height: 25px; - position: absolute; - text-align: center; - top: 86px; - width: 100px; - -webkit-transition: all 0.3s ease; - -moz-transition: all 0.3s ease; - -o-transition: all 0.3s ease; - transition: all 0.3s ease; -} -#profile_picture_edit_panel:hover span { - background: rgba(75, 98, 119, 0.95); - opacity: 1; - color: white; -} -.profile_block_img { - display: block; -} -#updatePersonalForm .placeholder_frame { - float: none; - width: 380px; -} -.profile_block_key { - float: left; - font-weight: bold; - font-size: 12px; - height: 24px; - line-height: 24px; - margin-bottom: 10px; - width: 100px; -} -#profile_settings .profile_block_key { - padding-left: 5px; - width: 200px; -} -#profile_settings .profile_block h2 { - margin: 0 0 15px 0; -} -.edit_wrap { - width: 100%; - height: 10px; -} -.profile_block_value { - float: left; - line-height: 24px; - font-size: 12px; -} -.general_setting_item { - margin-bottom: 20px; -} -.profile_block_value input[type=text], -.profile_block_value input[type=password] { - width: 330px; -} -.profile_block_error { - color: red; - display: block; - line-height: 20px; -} -.cancel_save_panel { - float: right; - margin-right: 5px; - line-height: 36px; - margin-top: 20px; -} -.cancel_save_panel .cancel { - float: left; - padding-right: 10px; - font-size: 12px; -} -.profile_block h1 { - margin: 0; - font-size: 14px; -} -.profile_block h2 { - margin: 0 0 5px 0; - padding: 0 0 2px 4px; - color: #7b95ad; - border-bottom: 1px solid #9baec0; - font-size: 12px; - font-weight: normal; -} -.profile_show { - padding: 10px 0 2px 4px; - margin-bottom: 20px; -} -.profile_edit { - padding: 10px 0 2px 4px; - float: left; - display: block; -} -.profile_edit_personal { - width: 400px; -} -.profile_block h3 { - font-size: 12px; - margin: 10px 0; - font-weight: normal; -} -.profile_section { - min-height: 100px; - display: block; - overflow: auto; - margin-bottom: 20px; -} -.profile_prof_head { - width: 400px; -} -.profile_name_field { - width: 200px; -} -.placeholder_frame label.profile_personalEdit { - padding: 5px; -} -.profileTitle_field { - width: 200px; -} -#profile_personal .profile_show div { - display: inline; -} -/* ***************** */ -/* profile block END */ -/* ***************** */ -/* ******************** */ -/* sticky infobox START */ -/* ******************** */ -.sticky_infobox { - width: 350px; - height: 310px; - background: url(/static/img/design/sticky_infobox_big.png) 0 0 no-repeat; - padding: 50px 65px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -/* ****************** */ -/* sticky infobox END */ -/* ****************** */ -/* ************ */ -/* search START */ -/* ************ */ -.search_wrap { - padding-left: 15px; -} -.search_wrap .placeholder_frame { - height: 30px; -} -.search_wrap .placeholder_frame input { - height: 30px; -} -.search_wrap .placeholder_frame label { - padding: 4px 0 0 5px; - font-size: 14px; -} -.search_wrap .placeholder_frame button.search_button { - height: 30px; -} -.top_searchbox_form { - float: right; - position: relative; - top: 12px; - padding-right: 10px; -} -.search_result_item { - padding-bottom: 20px; - width: 560px; -} -.search_result_item_title { - text-decoration: underline; - font-size: 12px; -} -.search_result_item_title:hover { - text-decoration: underline; - color: #3b97ed; -} -.search_result_item_text { - font-size: 12px; -} -#search_result_load_more_spinner { - display: none; -} -#search_result_load_more_link { - display: none; -} -#search_result_error_message { - display: none; - color: red; -} -#search_result_num_all_results { - display: none; - color: #999; - font-size: 12px; - padding: 3px; -} -.search_result_content { - padding-top: 20px; -} -/* ********** */ -/* search END */ -/* ********** */ -.default_font { - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; - font-size: 15px; - line-height: 1.45em; - white-space: normal; -} -#data_element { - display: none; -} - - -/**************/ -/* IE WARNING */ -/**************/ -#ie_warning { - display: none; - background-color: #E66873; - color: #FFF; - font-size: 14px; - height: 30px; - left: 50%; - line-height: 14px; - margin-left: -310px; - padding: 5px; - position: fixed; - text-align: center; - width: 550px; - z-index: 9999; -} -a#ie_warning_close { - color: #FFF; - float: right; - font-size: 12px; - cursor: pointer; -} -a#ie_warning_update { - color: #FFF; - font-size: 14px; - text-decoration: underline; -} -/****************************/ -/* admin active weeks START */ -/****************************/ -.activeWeeksTable { - border-spacing: 0; - border-collapse: collapse; - font-size: 8px; - background-color: #e5e5e5; - text-align: center; -} -.activeWeeksTable th { - border: 1px solid #374858; -} -.activeWeeksTable td { - border: 1px solid #374858; -} -.activeWeeksTable .week { - width: 20px; - height: 20px; -} -.activeWeeksTable .week.status1 { - background-color: white; -} -.activeWeeksTable .week.status2 { - background-color: #fcc; -} -.activeWeeksTable .week.status3 { - background-color: #cfc; -} -.activeWeeksTable .week.status3 { - background-color: #cfc; -} -.activeWeeksTable .premium { - background-color: #cfc; -} -/**************************/ -/* admin active weeks END */ -/**************************/ -/**************************/ -/* pdf viewer START */ -/**************************/ -#pdf_viewer { - border: 0; - display: block; - height: 100%; - width: 100%; -} -/**************************/ -/* pdf viewer END */ -/**************************/ -.activeExcelSheet { - font-weight: bold; -} -a.editor_reference { - color: #a21621; - cursor: pointer; - font-weight: bold; - text-decoration: none; -} -.pdf_checkbox_label { - line-height: 32px; - margin-left: 25px; -} -.pdf_checkbox_sublabel { - line-height: 32px; - margin-left: 45px; -} -.pdf_setting_description { - margin-left: 50px; - font-size: 12px; -} -.pdf_filename_label { - display: block; - margin: 10px 0 10px 32px; -} -/**************************/ -/* END */ -/**************************/ -#block_history_item_content .extract_preview_link, -.readOnly .extract_preview_link { - display: none; -} -.extract_preview { - overflow: auto; -} -.extract_preview_confirm { - float: right !important; - margin-right: 25px; -} -/*********************/ -/* jsTemplates START */ -/*********************/ -#jsTemplates { - display: none; -} -p.jsTemplate_dialog_title { - display: none; -} -/*******************/ -/* jsTemplates END */ -/*******************/ -/***************/ -/* popup START */ -/***************/ -.popup { - display: none; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - z-index: 98; - -moz-opacity: .8; - opacity: 0.8; - background-color: white !important; -} -.popup_window { - display: none; - position: absolute; - z-index: 99; - background-color: white; - /* border: 2px solid #374858; */ - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); -} -.popup_window_default { - top: 75px; - bottom: 75px; - left: 75px; - right: 75px; -} -#my_popup_inner { - background-color: #cad4de; -} -.popup_dialog { - display: none; - position: absolute; - z-index: 99; - background-color: #cad4de; - top: 30%; - left: 50%; - width: 400px; - margin-top: -125px; - margin-left: -200px; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.8); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.8); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.8); -} -.popup_title { - height: 30px; - line-height: 30px; - margin-top: -1px; - padding-left: 5px; - background: #304d69; - color: white; -} -.popup_title_close { - font-size: 20px; - width: 20px; - height: 20px; - text-align: center; - line-height: 20px; - float: right; - cursor: pointer; - margin: 4px; -} -.popup_title_left { - float: left; -} -.popup_title_center { - text-align: center; -} -.popup_title_center span { - display: none; -} -.popup_loading_image { - margin: 50px auto; - background: url(/static/img/ajax-loader-big.gif) no-repeat; - width: 32px; - height: 32px; -} -.popup_dialog .popup_dialog_content { - max-height: 650px; - overflow: auto; - padding: 10px; -} -.popup_dialog_cancel_save_panel { - float: right; - margin-top: 10px; - line-height: 30px; -} -.popup_dialog_cancel_save_panel .cancel { - float: left; - padding-right: 5px; - font-size: 12px; - visibility: hidden; -} -.popup_dialog_cancel_save_panel .dialog_confirm { - visibility: hidden; -} -#import_footer .dialog_confirm { - visibility: visible; -} -.popup_dialog_cancel_save_panel .default_button { - margin-left: 5px; -} -.popup_scroll_content { - position: absolute; - right: 0; - bottom: 0; - top: 30px; - left: 0; - padding: 10px; - overflow: auto; -} -.popup_list_row { - padding-bottom: 15px; - margin-bottom: 15px; - border-bottom: 1px solid #DDD; -} -.popup_list_row .default_button { - float: right; -} -.popup_list_row .deny_link { - float: right; - line-height: 36px; - font-size: 12px; - margin: 0 5px; -} -.popup_list_row_desc { - padding-top: 12px; - margin-right: 125px; -} -.popup_dialog_error { - background-color: #E66873; - color: #FFF; - display: none; - font-size: 14px; - line-height: 18px; - padding: 5px; - text-align: center; -} -.popup_dialog_loading_button { - padding: 0 10px; -} -#my_popup_content { - height: calc(100% - 29px); - overflow: auto; -} -.input_block { - margin-bottom: 20px; - word-wrap: break-word; - font-size: 12px; -} -.input_block .folder_up-img { - background-position: -738px -5px; - width: 24px; - height: 13px; -} -.tagline_hidden { - display: none; -} -.input_title { - margin: 10px 0 5px; - font-size: 12px; - color: #4b6277; -} -#my_popup_content .input_title:first-of-type { - /* margin: 0 0 5px 0; */ -} -#my_popup_content .spinner { - display: block; - margin: auto; -} -#my_popup_content textarea { - color: #4b6277; - line-height: 1.4; - font-size: 14px; - height: 150px; - resize: none; -} -/*************/ -/* popup END */ -/*************/ -/**************************/ -/* custom selectbox START */ -/**************************/ -div.lfSelectBox { - position: relative; - cursor: pointer; - background-color: white; - width: 0; - float: left; -} -div.lfSelectTitle { - border: 1px solid black; -} -div.lfSelectOptions { - position: absolute; - border: 1px solid black; - background: white; - z-index: 99; - display: none; -} -div.lfSelectOption:hover { - color: #E7E7E7; - background: #3988e5; -} -/************************/ -/* custom selectbox END */ -/************************/ -/* ************ */ -/* button START */ -/* ************ */ -a.btn, -button.btn { - background: transparent url(/static/img/button/button_right.gif) no-repeat scroll top right; - border: 0; - color: #666; - cursor: pointer; - display: block; - float: left; - font-size: 14px; - line-height: 16px; - height: 24px; - margin-right: 6px; - outline: none; - padding-right: 16px; - padding-top: 0; - text-decoration: none; -} -a.btn span, -button.btn span { - background: transparent url(/static/img/button/button_left.gif) no-repeat; - display: block; - padding: 4px 0 4px 18px; -} -a.btn img, -button.btn img { - vertical-align: top; -} -a.btn:active, -button.btn:active { - background-position: bottom right; -} -a.btn:active span, -button.btn:active span { - background-position: bottom left; - padding: 5px 0 3px 18px; -} -/* a.btn36, button.btn36 { */ -/* background-color: transparent; */ -/* border: 0; */ -/* margin: 0; */ -/* padding: 0; */ -/* color: white; */ -/* cursor: pointer; */ -/* display: block; */ -/* float: left; */ -/* font-size: 14px; */ -/* line-height: 16px; */ -/* height: 36px; */ -/* outline: none; */ -/* text-decoration: none; */ -/* font-family: 'din-medi'; */ -/* } */ -/* a.btn36 img, button.btn36 img { */ -/* vertical-align: top; */ -/* margin-right: 7px; */ -/* } */ -/* a.btn36 span, button.btn36 span { */ -/* display: block; */ -/* float: left; */ -/* } */ -/* a.btn36 span.m, button.btn36 span.m { */ -/* background: url(/static/img/button/b36_m.png) repeat-x 0 0; */ -/* height: 16px; */ -/* padding: 10px 1px 10px 1px; */ -/* } */ -/* a.btn36 span.l, button.btn36 span.l { */ -/* background: url(/static/img/button/b36_l.png) no-repeat 0 0; */ -/* width: 15px; */ -/* height: 36px; */ -/* } */ -/* a.btn36 span.r, button.btn36 span.r { */ -/* background: url(/static/img/button/b36_r.png) no-repeat 0 0; */ -/* width: 15px; */ -/* height: 36px; */ -/* } */ -/* a.btn36:hover span, button.btn36:hover span { */ -/* background-position: 0 -36px; */ -/* } */ -/* a.btn36:active span, button.btn36:active span { */ -/* background-position: 0 -72px; */ -/* } */ -/* a.btn36:active span.m, button.btn36:active span.m { */ -/* padding: 11px 0px 9px 2px; */ -/* } */ -/* ********** */ -/* button END */ -/* ********** */ -/* ************ */ -/* errors START */ -/* ************ */ -.errorBox { - border: 1px solid red; -} -.errorInput { - background-color: red; -} -.errorMessage { - color: red; -} -/* ********** */ -/* errors END */ -/* ********** */ -/* *********************** */ -/* input placeholder START */ -/* *********************** */ -.placeholder_frame { - position: relative; - float: left; -} -.placeholder_frame label { - position: absolute; - padding: 7px 0 0 5px; - top: 2px; - left: 0; - color: #9baec0; - font-style: italic; - font-family: Arial; - cursor: text; - font-size: 14px; -} -.placeholder_frame input { - padding: 5px; - margin: 0; - font-size: 14px; - line-height: 14px; - color: #4b6277; -} -.placeholder_frame button { - position: absolute; - height: 28px; - padding: 7px; - top: 0; - right: 0; -} -.placeholder_frame input.searchbox_input { - width: 250px ; - padding-right: 30px; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} -.placeholder_frame.big label { - font-size: 20px; - padding: 10px 0 0 12px; -} -.placeholder_frame.big input { - padding: 10px; - padding-right: 50px; - width: 500px; - font-size: 20px; - line-height: 20px; -} -.placeholder_frame.big button { - padding: 10px; - font-size: 20px; -} -/* *********************** */ -/* input placeholder END */ -/* *********************** */ -/* ************ */ -/* inputs START */ -/* ************ */ -.input_with_padding { - padding: 3px; - width: 100%; -} -.form_around_input_with_padding { - padding-right: 5px; -} -/* ********** */ -/* inputs END */ -/* ********** */ -.aligned_radio_button { - display: -moz-inline-box; - display: inline-block; - vertical-align: middle; - line-height: 18px; - margin-bottom: 5px; -} -input { - outline: 0; -} -textarea { - outline-color: #69bfee; -} -input[type="checkbox"].default_checkbox { - position: absolute; - opacity: 0; -} -input[type="checkbox"].default_checkbox + div { - cursor: pointer; - display: inline-block; - vertical-align: middle; - width: 46px; - height: 13px; - border: 1px solid rgba(55, 72, 88, 0.47); - border-radius: 999px; - margin: 0 .5em; - background: #f9fafb; - background-image: linear-gradient(rgba(176, 205, 231, 0.2), rgba(0, 0, 0, 0)), linear-gradient(90deg, #374858, rgba(0, 0, 0, 0) 65%); - background-size: 200% 100%; - background-position: 100% 0; - background-origin: border-box; - background-clip: border-box; - overflow: hidden; - transition-duration: .3s; - transition-property: padding, width, background-position, text-indent; - box-shadow: 0 0.2em 0.4em rgba(14, 27, 37, 0.12) inset, 0 0.45em 0 0.1em rgba(45, 98, 133, 0.05) inset; - font-size: 150%; -} -input[type="checkbox"].default_checkbox:checked + div { - padding-left: 33px; - width: 46px; - background-position: 0 0; -} -input[type="checkbox"].default_checkbox + div:before { - content: 'On'; - float: left; - width: 13px; - height: 13px; - margin: -1px; - border: 1px solid rgba(55, 72, 88, 0.35); - border-radius: inherit; - background: white; - background-image: linear-gradient(#8fa1b4, transparent); - box-shadow: 0 0.1em 0.1em 0.1em rgba(255, 255, 255, 0.8) inset, 0 0 0.5em rgba(55, 72, 88, 0.3); - color: white; - text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.3); - text-indent: -2.5em; -} -input[type="checkbox"].default_checkbox:active + div:before { - background-color: #eee; -} -input[type="checkbox"].default_checkbox + div:before, -input[type="checkbox"].default_checkbox + div:after { - font-size: 9px; - line-height: 12px; - font-weight: bold; - text-transform: uppercase; -} -input[type="checkbox"].default_checkbox + div:after { - content: 'Off'; - float: left; - text-indent: .5em; - color: #4b6277; - text-shadow: none; -} -/* Draggable */ -div.action_button.dragging_helper { - width: 42px; - height: 24px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 2px 10px; - background-image: url('/static/img/design/blank.png') !important; - background-color: #FFF; - border-radius: 2px; - box-shadow: 0 1px 4px #646464; - color: #69bfee; - cursor: pointer; - opacity: 0.8; - text-decoration: none; - z-index: 50; -} -a.dragging_helper { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - background-image: url('/static/img/design/blank.png') !important; - background-color: #FFF; - border-radius: 2px; - box-shadow: 1px 1px 5px #000; - color: #69bfee; - cursor: pointer; - opacity: 0.5; - padding: 10px 30px; - text-decoration: none; - z-index: 50; -} -.dialog_message_form textarea { - min-height: 150px; -} -/************* -* header css * -**************/ -.arrow_box { - position: relative; - background: white; -} -.arrow_box:after, -.arrow_box:before { - bottom: 100%; - left: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; -} -.arrow_box:after { - border-color: rgba(0, 0, 0, 0); - border-bottom-color: white; - border-width: 5px; - margin-left: -4px; -} -.arrow_box:before { - border-color: rgba(0, 0, 0, 0); - border-bottom-color: #bac7d4; - border-width: 6px; - margin-left: -5px; -} -.headerbar_top { - width: 100%; - height: 50px; - background: white; - border-bottom: solid 1px #bac7d4; -} -.headerbar_top > header { - margin: 21px 0 0 65px; - font-weight: bold; - float: left; - position: relative; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: #415568; -} -.headerbar_top > header:hover .page_title { - position: absolute; - overflow: visible; - white-space: normal; - display: block; - margin-left: 21px; - z-index: 999; - background: white; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); -} -.headerbar_top h1 { - font-size: 14px; - font-weight: normal; - margin: 0; -} -.headerbar_top > nav { - float: right; - height: 50px; -} -.headerbar_top a { - color: inherit; - text-decoration: none; - cursor: pointer; -} -.page_title { - white-space: nowrap; - text-overflow: ellipsis; - display: block; - overflow: hidden; - padding: 0; - background: white; - margin-left: 0; -} -.page_title a { - white-space: nowrap; -} -.nav_top { - float: left; - margin: 0 100px 0 10px; -} -.nav_top > ul { - margin: 0; - padding: 0; -} -.nav_top > ul > li { - width: 72px; - height: 49px; - margin-left: -1px; - list-style-type: none; - float: left; - position: relative; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; - -o-transition: all 0.2s ease; - transition: all 0.2s ease; -} -.header_btn { - width: 100%; - height: 100%; - color: #4b6277; - padding: 0; - text-align: center; - font-size: 10px; - position: relative; - cursor: pointer; - background: transparent; - border-left: solid 1px transparent; - border-right: solid 1px transparent; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; - -o-transition: all 0.2s ease; - transition: all 0.2s ease; -} -.header_btn span { - margin-left: auto; - margin-right: auto; - margin-top: 2px; - display: block; - float: none; -} -.header_btn p { - margin: 7px 0; -} -.header_btn:hover { - background: #f3f5f7; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - border-left: solid 1px #cad4de; - border-right: solid 1px #cad4de; - padding-top: 0; -} -.header_btn:active { - background: #d9e1e8; - padding-top: 0; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); -} -.nav_top_active { - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - background: #e0e6eb !important; - border-left: solid 1px #cad4de !important; - border-right: solid 1px #cad4de !important; -} -.manage_hover:hover .header_btn { - background: #f3f5f7; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - border-left: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - padding-top: 0px; -} -.manage_hover:active .header_btn { - background: #d9e1e8; - padding-top: 0px; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); -} -.manage_dropdown { - position: absolute; - top: 49px; - left: 0; - font-size: 13px; - z-index: 999; -} -.manage_dropdown li { - width: 120px; -} -.manage_dropdown > span { - position: absolute; - top: -11px; - left: 25px; -} -.header_top_dropdown { - background: white; - display: none; - border: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - border-bottom: solid 1px #bac7d4; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - font-size: 13px; -} -.header_top_dropdown > ul { - margin: 0; - padding: 0; -} -.header_top_dropdown > ul li { - list-style-type: none; -} -.header_top_dropdown > ul { - padding: 12px 0 12px 0; -} -.header_top_dropdown > ul > li { - display: block; - text-align: left; - cursor: pointer; -} -.header_top_dropdown > ul > li > a { - padding: 8px 0 8px 12px; - display: block; -} -.header_top_dropdown > ul > li:hover { - background: #ecf0f3; -} -.bread_arrow { - font-size: 11px; -} -.options_top { - float: right; - margin: 10px 0 0 10px; - position: relative; -} -.options_top > ul { - margin: 0; - padding: 0; -} -.options_top > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.options_top > ul > li { - width: 40px; - height: 50px; - margin-right: 15px; - display: block; - float: left; - font-size: 10px; - position: relative; -} -.options_top > ul > li:first-child > span { - margin-left: 10px; -} -.signout_wrap { - position: relative; - display: block; - width: 40px; - height: 32px; -} -.notes_count { - padding: 2px 2px 1px 2px; - line-height: 10px; - color: white; - background: #22a6ee; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - position: absolute; - text-align: right; - left: 20px; - top: 0px; -} -.avatar { - border-radius: 50%; - width: 28px; - height: 28px; - background: #cad4de; - margin-top: -3px; - float: left; - -webkit-box-shadow: 0px 1px 2px rgba(55, 72, 88, 0.6); - -moz-box-shadow: 0px 1px 2px rgba(55, 72, 88, 0.6); - box-shadow: 0px 1px 2px rgba(55, 72, 88, 0.6); -} -.avatar span { - display: block; - float: none; -} -.avatar img { - border-radius: 50%; - width: 28px; - height: 28px; - position: absolute; -} -.avatar .avatar-img { - margin: 3px 0 0 4px; -} -.avatar .arrow_down_s-img { - position: absolute; - top: 12px; - right: 2px; -} -.dropdown_button { - cursor: pointer; -} -.search_dropdown { - width: 250px; - height: 51px; - padding: 10px; - position: absolute; - top: 39px; - left: -111px; - z-index: 999; -} -.search_dropdown > span { - position: absolute; - top: -11px; - left: 114px; -} -.search_dropdown input { - height: 30px; - width: 100%; - font-size: 14px; - color: #4b6277; - padding-left: 4px; - display: block; - margin: auto; - border: solid 1px #bac7d4; -} -.search_dropdown button { - position: absolute; - top: 10px; - right: 10px; - padding: 7px; - height: 30px; -} -.bell_dropdown { - position: absolute; - top: 39px; - left: -166px; - font-size: 12px; - line-height: 1.4; - z-index: 99; - max-height: 530px; - overflow-y: auto; - overflow-x: hidden; -} -.bell_dropdown > span { - position: absolute; - top: -11px; - left: 169px; -} -.bell_dropdown li { - width: 250px; - padding: 8px 0 8px 8px; -} -.bell_dropdown li span { - color: #69bfee; - font-weight: bold; -} -.bell_dropdown li article { - width: 200px; - display: inline-block; - margin-left: 10px; -} -.bell_dropdown li p { - color: #9baec0; - margin: 5px 0; -} -.bell_dropdown li:last-child { - text-align: center; - margin: 14px 0 -12px 0 !important; - background: #d9e1e8; -} -.profile_dropdown { - position: absolute; - top: 39px; - left: -70px; - font-size: 13px; - z-index: 999; - width: 120px; -} -.profile_dropdown > span { - position: absolute; - top: -11px; - left: 77px; -} -.profile_dropdown ul > li { - padding-left: 10px; -} -.profile_dropdown ul > li a { - width: 100%; -} -.med_blue_btn { - padding: 8px 17px 8px 17px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - color: white; - opacity: 1; - background: #3277b8; - font-size: 16px; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - -o-transition: all 0.1s linear; - transition: all 0.1s linear; - -webkit-backface-visibility: hidden; -} -.med_blue_btn:hover, -.med_blue_btn:focus { - background: #2a6398; - -ms-filter: none; - filter: none; - outline: 0; - color: white; - text-decoration: none; -} -.med_blue_btn:active { - background: #245684; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.4); - -moz-box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.4); - box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.4); -} -.orange_btn { - padding: 4px 17px 5px 17px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - color: #ffffff; - opacity: 1; - background: #e37900; - font-size: 20px; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - -o-transition: all 0.1s linear; - transition: all 0.1s linear; - -webkit-backface-visibility: hidden; -} -.upgrade_box { - position: relative; - background: #ffffff; - display: inline-block; - vertical-align: middle; - margin-right: 6px; -} -.upgrade_btn { - color: white; - background: #ff8617; - border: 0; - opacity: 1; - position: absolute; - top: 44px; - right: 40px; - border-radius: 3px; - color: white !important; - text-decoration: none; - padding: 3px 16px; - font-weight: bold; - height: 22px; - margin-top: 3px; - font-size: 14px; - display: block; -} -.upgrade_btn:hover { - background: #ffa14a; - outline: 0; -} -.upgrade_btn:active { - background: #ff8617; - outline: 0; - -webkit-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.3); - box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.3); -} -.upgrade_box:after { - left: 100%; - top: 50%; - border: solid rgba(0, 0, 0, 0); - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(213, 213, 213, 0); - border-left-color: #ffffff; - border-width: 4px; - margin-top: -5px; -} -.filterbox_wrap { - position: relative; - float: left; - min-width: 100px; - width: auto; -} -.filterbox_wrap .filter_btn { - border-left: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - border-top: solid 1px #bac7d4; -} -.filterbox_task_wrap { - position: relative; - float: left; - min-width: 150px; -} -.filterbox_task_wrap .filter_btn { - border-left: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - border-top: solid 1px #bac7d4; -} -.filter_box_dropdown { - width: auto; - min-width: 100px; - padding: 10px 0; - float: left; - border: solid 1px #cad4de; - background: white; - font-size: 12px; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); -} -.filter_box_dropdown > ul { - margin: 0; - padding: 0; -} -.filter_box_dropdown li { - list-style-type: none; - padding: 8px 8px 8px 8px; - cursor: pointer; -} -.filter_box_dropdown li:hover { - background: #ecf0f3; -} -.notebook_notification { - font-size: 16px; - margin: 40px auto; - width: 390px; - padding: 20px; - background: #ffffff; - -webkit-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - -moz-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); -} -/********************* -* overwrite jqueryUI * -*********************/ -.ui-datepicker { - -webkit-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); -} -.ui-corner-all, -.ui-corner-bottom, -.ui-corner-right, -.ui-corner-br { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} -.ui-widget-header { - border: 0 /*{borderColorHeader}*/; - background: #d9e1e8; - color: #4b6277; - /*{fcHeader}*/ - font-weight: normal; -} -.ui-datepicker .ui-datepicker-prev, -.ui-datepicker .ui-datepicker-next { - border: 0; - position: absolute; - top: 0; - width: 1.8em; - height: 100%; -} -.ui-datepicker .ui-datepicker-prev:hover, -.ui-datepicker .ui-datepicker-next:hover { - border: 0; - background: #bac7d4; -} -.ui-datepicker th { - padding: .7em .3em; - text-align: center; - font-weight: normal; - color: #4b6277; - border: 0; -} -.ui-widget-content { - border: 1px solid #9baec0; - background: #ecf0f3; - color: #4b6277; -} -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - border: 1px solid #cad4de; - background: white; - font-weight: normal /*{fwDefault}*/; -} -.ui-state-hover, -.ui-widget-content .ui-state-hover, -.ui-widget-header .ui-state-hover, -.ui-state-focus, -.ui-widget-content .ui-state-focus, -.ui-widget-header .ui-state-focus { - border: 1px solid #bac7d4 /*{borderColorHover}*/; - background: #e4eef7; - font-weight: normal /*{fwDefault}*/; - color: #4b6277; - /*{fcHover}*/ -} -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - color: #4b6277; -} -.ui-state-hover .ui-icon, -.ui-state-focus .ui-icon { - background-image: none; -} -.ui-widget-header .ui-icon { - background-image: none; -} -.ui-icon { - overflow: visible !important; -} -.ui-icon-circle-triangle-w { - position: relative; - background: white; - display: inline-block; - height: 0; - width: 0; -} -.ui-icon-circle-triangle-w:after { - right: 100%; - top: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-right-color: #4b6277; - border-width: 8px; - margin-top: -7px; -} -.ui-icon-circle-triangle-e { - position: relative; - background: white; - display: inline-block; - height: 0; - width: 0; -} -.ui-icon-circle-triangle-e:after { - left: 100%; - top: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-left-color: #4b6277; - border-width: 8px; - margin-top: -7px; -} -.ui-datepicker .ui-datepicker-prev span, -.ui-datepicker .ui-datepicker-next span { - display: block; - position: absolute; - left: 50%; - margin-left: -2px; - top: 50%; - margin-top: 0px; -} -.ui-tooltip { - padding: 5px 10px; - background: #374858; - -webkit-box-shadow: 0 2px 3px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 3px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 3px rgba(55, 72, 88, 0.3); - font: normal 14px; - color: white; - border: 0; - z-index: 11; -} -.ui-tooltip:after { - bottom: 100%; - left: 13px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: transparent; - border-bottom-color: #374858; - border-width: 7px; - margin-left: -7px; -} -/**************** -* media queries * -****************/ -@media (max-width: 1750px) { - .headerbar_top > header { - width: 30%; - } -} -@media (max-width: 1160px) { - .group_content_block { - width: 100%; - } - .headerbar_top > header { - width: 30%; - margin: 19px 0 0 20px; - } - .eln_main_content_box, - .project_list { - padding: 20px 20px 20px 20px; - width: auto; - } - #messages_content, - #task_content, - #comments_content { - padding: 0 10px 0 10px; - } -} -@media (max-width: 1100px) { - .author_firstname, - .author_lastname { - width: 100px; - } -} -@media (max-width: 970px) { - .nav_top { - margin: 0 30px 0 10px; - } - .headerbar_top > header { - width: 200px; - } - .page_title { - margin-top: 2px; - font-size: 12px; - } - .author_firstname, - .author_lastname { - width: 66px; - } - .group_content_box { - padding: 20px; - } - .profile_block { - max-width: 550px; - width: calc(100% - 25px); - } -} -@media (max-height: 600px) { - .popup_dialog { - top: 50%; - } -} - -/****************************** - GROUP HEADER AND NAVIGATION BAR -*******************************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.is_group .group-img { - margin-top: 1px; -} -.group_header { - background: #374858 repeat-x 0 0; - border-left: 1px solid #DDD; - border-right: 1px solid #DDD; - border-top: 1px solid #DDD; - border-radius: 10px 10px 0px 0px; - height: 35px; - line-height: 14px; - padding: 5px 10px; -} -/*.group_name{ - color: #FFFFFF; - display: block; - font-size: 24px; - height: 24px; - line-height: 24px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -}*/ -.group_tagline { - color: #FFFFFF; - display: block; - font-size: 14px; - height: 14px; - line-height: 14px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.group_nav { - font-size: 16px; - background-color: #FFF; - margin: 0; -} -.group_nav a { - color: #5e7b97; - border: 1px solid #D6D4D5; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - display: inline-block; - position: relative; - width: 20%; - padding: 8px 0; - text-align: center; - white-space: nowrap; - transition: all ease 0.2s; -} -.group_nav a:hover { - background: #ededed; - color: #69bfee; - text-decoration: none; -} -.group_nav .active { - color: #69bfee; - text-decoration: none; -} -.group_first_nav { - border-radius: 0px 0px 0px 10px; -} -.group_last_nav { - border-radius: 0px 0px 10px 0px; -} -.group_main_icon { - color: #FFFFFF; - display: inline-block; - float: left; - font-size: 24px; - margin-top: 5px; -} -.group_main_title { - height: 35px; -} -.group_search_form { - float: right; - margin: 2px 10px 0 0; -} -.group_search_input { - border: 1px solid #D6D4D5; - border-radius: 5px; - font-size: 14px; - padding: 5px; -} -/****************************** - GROUP CONTENT STYLES -*******************************/ -.group_content_box { - height: auto; - margin: 0 25px 25px 0; - background-color: #ffffff; - border-bottom: solid 1px #cad4de; - border-left: solid 1px #cad4de; - border-right: solid 1px #cad4de; - position: relative; - padding: 20px 20px 20px 135px; -} -.group_content_block { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - display: block; - width: 900px; - padding-left: 31px; -} -.group_content_block .tree_my_eln_projects { - max-width: 500px; -} -#group_activities { - float: left; -} -#group_about { - float: right; - width: 400px; - margin-right: 35px; -} -.group_content_header { - color: #7b95ad; - font-size: 12px; - white-space: nowrap; - padding: 0 0 2px 4px; - width: 100%; - border-bottom: 1px solid #bac7d4; - display: block; - margin-bottom: 10px; -} -.group_description { - padding-left: 4px; -} -.group_content_subheader { - display: block; - font-size: 18px; - height: 18px; - padding: 5px 0px 10px 0; - white-space: nowrap; -} -.group_header_add_search { - border-bottom: 1px solid #D6D4D5; - display: block; - font-size: 24px; - height: 35px; - padding: 10px 0px 5px 15px; -} -.group_header_add_search button { - margin-right: 10px; -} -.group_content { - display: block; - font-size: 12px; - line-height: 18px; - margin-bottom: 20px; -} -/****************************** - INDEX -*******************************/ -#group_invitations { - display: none; - font-size: 12px; - line-height: 1.4; - left: 0; - top: 25px; - padding: 10px; - position: absolute; - width: 230px; - z-index: 10; -} -#group_invitations span { - color: #69bfee; - font-weight: bold; -} -.group_invitations_options { - height: 20px; - padding: 10px 0; -} -.group_invitation_line { - padding: 6px 0 6px 0; -} -/* .group_invitation_line:last-of-type{ */ -/* border-bottom: 0 !important; */ -/* } */ -.invitation_count { - top: -2px; - padding: 1px 2px 1px 2px; - line-height: 1; - color: white; - background: #22a6ee; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - position: relative; - text-align: right; -} -#group_show_invite { - font-size: 12px; - display: block; - position: relative; -} -.group_invite_wrap { - display: block; - float: left; - padding: 6px 0 0 0; - position: relative; -} -#group_show_invite:hover { - cursor: pointer; -} -#group_boxes { - margin-top: 10px; -} -#group_boxes label { - cursor: pointer; -} -#group_row_features, -#group_mini_features, -#group_maxi_features { - display: inline-block; - border: 1px solid transparent; -} -#group_row_features div, -#group_mini_features div, -#group_maxi_features div { - padding: 5px; - height: 20px; - border: 1px solid #DDD; - box-sizing: box-border; - line-height: 20px; - margin: 0; -} -#group_mini_features div, -#group_maxi_features div { - text-align: center; -} -#group_mini_features.active, -#group_maxi_features.active { - color: #69bfee; - border: 1px solid #69bfee; -} -tr.pair_row { - background: #DDD; -} -.group_join { - float: right; -} -button.group_join { - margin: 0; -} -button.group_join:active { - margin: 0; -} -a.group_join { - margin-right: 10px; - margin-top: 8px; -} -td.group_features { - padding: 10px; - text-align: center; -} -#group_table { - width: 100%; -} -#group_table td.features { - padding: 10px; -} -#group_table td.feature_header { - background-color: #374858; - color: #FFF; - height: 25px; - text-align: center; -} -#group_table td.mini_feature, -#group_table td.maxi_feature { - height: 20px; - text-align: center; - width: 100px; -} -#group_table td.cross { - color: #ad1c28; -} -#group_table td.check { - color: #bdca70; -} -#group_table td.mini_feature button, -#group_table td.maxi_feature button { - float: none; - text-align: center; -} -/****************************** - OVERVIEW -*******************************/ -.group_feed_date { - padding-right: 4px; - font-size: 11px; - text-align: right; - float: right; -} -.group_feed { - display: table; - margin-bottom: 15px; - padding: 0 0 6px 4px; - width: 100%; -} -.feed_line { - border-bottom: 1px solid #d9e1e8; -} -.group_feed_pic { - display: block; - float: left; - margin-right: 10px; - width: auto; -} -.group_feed_pic img { - border: 1px solid #bac7d4; -} -.group_feed_text { - display: inline-block; - vertical-align: top; -} -.group_feed_text b { - color: #3babe9; -} -.group_stats_row { - display: table-row; -} -.group_stats_elem { - display: table-cell; - font-weight: bold; - width: 10em; -} -.group_stats_num { - display: table-cell; - text-align: left; - width: 5em; -} -/****************************** - MEMBERS -*******************************/ -#group_members div.content_block { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -#group_members a.group_treeline { - background: url("/static/img/design/t.png") repeat-y; - color: #4b6277; - cursor: pointer; - display: block; - height: 26px; - padding-left: 30px; - white-space: nowrap; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ -} -#group_members a.group_treeline:hover { - background-color: #ecf0f3 !important; - text-decoration: none; -} -#group_members a.group_treeline span.name { - display: inline-block; - height: 26px; - line-height: 1.5; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - width: 100%; -} -.tree_button button { - padding: 4px; - background: rgba(0, 0, 0, 0); - cursor: pointer; -} -/* #group_members .group_treeline:hover span.icon-user, */ -/* #group_members .group_treeline:hover span.icon-group, */ -/* #group_members .group_treeline:hover span.name{ */ -/* color: #69bfee; */ -/* } */ -/* #group_members a.group_treeline div.more_options_panel{ */ -/* margin-top: -5px; */ -/* } */ -.subgroup .menu_arrow-img { - position: absolute; - top: -11px !important; - left: 66px !important; -} -#group_members .more_options_panel .menu_arrow-img { - position: absolute; - top: -11px; - left: 100px; -} -#group_members a.group_treeline:last-of-type { - background: url("/static/img/design/l.png") no-repeat; - margin-top: -1px; -} -#group_members a.group_treeline div.tree_button { - float: right; - display: none; -} -#group_members a.group_treeline:hover div.tree_button { - display: inline; -} -#group_members div.group_treeline_children { - background: url("/static/img/design/straight.png") repeat-y; - padding-left: 34px; - margin-left: 0px; - box-sizing: border-box; -} -#group_members div.tree_my_eln_projects > div.group_treeline_children { - padding-left: 14px; -} -#group_members div.group_treeline_children:last-child { - background: url("/static/img/design/blank.png") repeat-y; -} -#group_members a.GROUP { - background-image: url("/static/img/design/blank.png") !important; - background-repeat: repeat-y !important; - font-size: 14px; - padding: 2px 8px 2px 4px; -} -#group_members a.GROUP span.name { - font-size: 14px; - height: 20px; - line-height: 1.5; -} -#group_members a.SUBGROUP { - padding: 2px 8px 2px 25px; -} -#group_members a.SUBGROUP span.icon-group { - font-size: 15px; - text-decoration: none; - line-height: 1.5; -} -#group_members a.SUBGROUP span.icon-group:before { - letter-spacing: 0.1em !important; -} -#group_members a.SUBGROUP span.name { - font-style: italic; -} -#group_members a.subgroup_selected { - background-color: #8ad97d !important; -} -#group_members a.MEMBER { - padding: 2px 8px 2px 25px; -} -#group_members a.MEMBER span.icon-user { - font-size: 14px; - line-height: 1; - padding-right: 2px; - text-decoration: none; -} -#group_members .droppable_group { - background-color: #e5ffe1 !important; -} -#group_members .hover_droppable_group { - background-color: #dde7ff !important; -} -/****************************** - PROJECTS -*******************************/ -.group_share_block { - display: none; -} -.group_share_member_tree { - background: white; - box-sizing: border-box; - max-height: 150px; - min-height: 70px; - overflow: auto; - padding: 10px; - margin-top: 10px; -} -.group_share_member_tree input[type=checkbox] { - vertical-align: middle; - position: relative; - bottom: 1px; -} -.group_share_member_tree a { - color: #374858; - line-height: 25px; - text-decoration: none; -} -.group_share_member_tree div.group_treeline_children { - padding-left: 15px; - margin-left: 0px; - box-sizing: border-box; -} -/****************************** - SETTINGS -*******************************/ -.group_settings { - float: right; -} -.group_settings_block { - background-color: white; - border: 1px solid #DDDDDD; - border-radius: 10px; - padding: 10px; - width: 595px; -} -.group_settings_block_key { - float: left; - font-size: 14px; - font-weight: bold; - line-height: 26px; - width: 200px; -} -.group_settings_block_value { - line-height: 26px; - font-size: 14px; - margin-left: 250px; -} -.group_settings_block_value input[type="text"], -.group_settings_block_value textarea { - width: 330px; -} -.group_settings_header h2 { - float: left; - margin: 5px 0 10px; -} -@media (max-width: 1200px) { - #group_about { - float: none; - margin-bottom: 60px; - } -} - -/**************************/ -/* i18n START */ -/**************************/ - -#i18n_translation_panel { - border: 1px solid black; - min-height: 150px; - background: #DDD; - position: fixed; - bottom: 0; - left: 75%; - right: 50px; - z-index: 10000; - font-family: 'Arial'; - padding: 10px; -} - -#i18n_translation_save_button { - width: 100%; - outline: none; - border: none; - color: #ffffff; - background: #69bfee; - height: 40px; - text-transform: uppercase; - cursor: pointer; - font-weight: bold; - transition: all ease-in 0.2s; -} - -#i18n_translation_save_button:hover { - background:#374858; -} - -#i18n_translation_save_button:active { - opacity: 0.8; - background:#374858; -} - -#i18n_translation_english_text { - padding: 15px; - display: block -} - -#i18n_translation_textarea { - padding: 10px; - width: 100%; - box-sizing: border-box; - margin-bottom: 10px; - font-size: 14px; -} - -.i18n_highlight.i18n_translation_untranslated { - color: #FF3D2B !important; -} - -.i18n_highlight.i18n_translation_translated { - color: #00AA00 !important; -} - -/**************************/ -/* i18n END */ -/**************************/@font-face { - font-family: 'LabFolderWebFont'; - src:url('../font/icons11.eot'); - src:url('../font/icons11.eot?#iefix') format('embedded-opentype'), - url('../font/icons11.svg#LabFolderWebFont') format('svg'), - url('../font/icons11.woff') format('woff'), - url('../font/icons11.ttf') format('truetype'); - font-weight: normal; - font-style: normal; -} - -/* Use the following CSS code if you want to use data attributes for inserting your icons */ -[data-icon]:before { - font-family: 'LabFolderWebFont'; - content: attr(data-icon); - speak: none; - font-weight: normal; - -webkit-font-smoothing: antialiased; -} - -/* Use the following CSS code if you want to have a class per icon */ -/* -Instead of a list of all class selectors, -you can use the generic selector below, but it's slower: -[class*="icon-"] { -*/ - -.icon-date, .icon-stop_contract, .icon-change_plan, .icon-update, .icon-add_notebook, .icon-sign, .icon-witness, .icon-checkbox, .icon-alert, .icon-speech, .icon-file, .icon-arrowhead, .icon-undo, .icon-text, .icon-selection, .icon-redo, .icon-rectangle, .icon-pencil, .icon-line, .icon-circle, .icon-asterisk, .icon-arrow, .icon-zoom_out, .icon-zoom_in, .icon-arrow_right, .icon-add_template, .icon-folder_selected, .icon-folder, .icon-add_group_notebook, .icon-add_group_folder, .icon-feedback, .icon-triangle_right, .icon-triangle_left, .icon-experiment3, .icon-add_folder, .icon-add_file, .icon-experiment2, .icon-triangle_down, .icon-sync, .icon-experiment1, .icon-edit_image, .icon-sign, .icon-search, .icon-edit, .icon-down_pdf, .icon-save, .icon-rename_proj, .icon-double_sign, .icon-double_arrow_right, .icon-remove, .icon-cross, .icon-copy, .icon-publish_to_world, .icon-publish_to_group, .icon-conf_drop, .icon-conf, .icon-print, .icon-notebook, .icon-check, .icon-back_up, .icon-template, .icon-invite_user, .icon-inventory, .icon-arrow_down, .icon-add_user, .icon-group_proj, .icon-group_folder_selected, .icon-add_text, .icon-add_proj, .icon-group_folder, .icon-group, .icon-add_notebook, .icon-forward, .icon-user_change, .icon-overview, .icon-user, .icon-add_img, .icon-drag_handle, .icon-add_protocol, .icon-save2, .icon-add_template2, .icon-add_entry, .icon-circle_arrow_down, .icon-arrow_up, .icon-expand, .icon-placeholder, .icon-dashboard, .icon-information { - font-family: 'LabFolderWebFont'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - -webkit-font-smoothing: antialiased; -} - - - -.icon-zoom_out:before { - content: "\e600"; -} -.icon-zoom_in:before { - content: "\e601"; -} -.icon-user_change:before { - content: "\e602"; -} -.icon-user:before { - content: "\e603"; -} -.icon-untitled12:before { - content: "\e604"; -} -.icon-undo:before { - content: "\e605"; -} -.icon-triangle_right:before { - content: "\e606"; -} -.icon-triangle_left:before { - content: "\e607"; -} -.icon-triangle_down:before { - content: "\e608"; -} -.icon-time:before { - content: "\e609"; -} -.icon-text:before { - content: "\e60a"; -} -.icon-template:before { - content: "\e60b"; -} -.icon-tell:before { - content: "\e60c"; -} -.icon-talk:before { - content: "\e60d"; -} -.icon-sync:before { - content: "\e60e"; -} -.icon-speech:before { - content: "\e60f"; -} -.icon-selection:before { - content: "\e610"; -} -.icon-search:before { - content: "\e611"; -} -.icon-save2:before { - content: "\e612"; -} -.icon-save:before { - content: "\e613"; -} -.icon-rename_proj:before { - content: "\e614"; -} -.icon-remove:before { - content: "\e615"; -} -.icon-redo:before { - content: "\e616"; -} -.icon-rectangle:before { - content: "\e617"; -} -.icon-raster:before { - content: "\e618"; -} -.icon-publish_to_world:before { - content: "\e619"; -} -.icon-publish_to_group:before { - content: "\e61a"; -} -.icon-print:before { - content: "\e61b"; -} -.icon-placeholder:before { - content: "\e61c"; -} -.icon-pencil:before { - content: "\e61d"; -} -.icon-overview:before { - content: "\e61e"; -} -.icon-outbox:before { - content: "\e61f"; -} -.icon-notebook:before { - content: "\e620"; -} -.icon-move_templ:before { - content: "\e621"; -} -.icon-move_folder:before { - content: "\e622"; -} -.icon-move_entr:before { - content: "\e623"; -} -.icon-man:before { - content: "\e624"; -} -.icon-lock_pen:before { - content: "\e625"; -} -.icon-line:before { - content: "\e626"; -} -.icon-invite_user:before { - content: "\e627"; -} -.icon-inventory:before { - content: "\e628"; -} -.icon-information:before { - content: "\e629"; -} -.icon-inbox:before { - content: "\e62a"; -} -.icon-group_proj:before { - content: "\e62b"; -} -.icon-group_folder_selected:before { - content: "\e62c"; -} -.icon-group_folder:before { - content: "\e62d"; -} -.icon-group:before { - content: "\e62e"; -} -.icon-forward:before { - content: "\e62f"; -} -.icon-folder_selected:before { - content: "\e630"; -} -.icon-folder:before { - content: "\e631"; -} -.icon-file:before { - content: "\e632"; -} -.icon-feedback:before { - content: "\e633"; -} -.icon-eye:before { - content: "\e634"; -} -.icon-experiment3:before { - content: "\e635"; -} -.icon-experiment2:before { - content: "\e636"; -} -.icon-experiment1:before { - content: "\e637"; -} -.icon-expand:before { - content: "\e638"; -} -.icon-edit_image:before { - content: "\e639"; -} -.icon-edit:before { - content: "\e63a"; -} -.icon-drag_handle:before { - content: "\e63b"; -} -.icon-down_pdf:before { - content: "\e63c"; -} -.icon-double_sign:before { - content: "\e63d"; -} -.icon-double_arrow_right:before { - content: "\e63e"; -} -.icon-delete_text:before { - content: "\e63f"; -} -.icon-delete_pen:before { - content: "\e640"; -} -.icon-date:before { - content: "\e641"; -} -.icon-dashboard:before { - content: "\e642"; -} -.icon-cross:before { - content: "\e643"; -} -.icon-copy:before { - content: "\e644"; -} -.icon-conf_drop:before { - content: "\e645"; -} -.icon-conf:before { - content: "\e646"; -} -.icon-clip:before { - content: "\e647"; -} -.icon-circle_arrow_down:before { - content: "\e648"; -} -.icon-circle:before { - content: "\e649"; -} -.icon-checkbox:before { - content: "\e64a"; -} -.icon-check:before { - content: "\e64b"; -} -.icon-back_up:before { - content: "\e64c"; -} -.icon-asterisk:before { - content: "\e64d"; -} -.icon-arrowhead:before { - content: "\e64e"; -} -.icon-arrow_up:before { - content: "\e64f"; -} -.icon-arrow_right:before { - content: "\e650"; -} -.icon-arrow_down:before { - content: "\e651"; -} -.icon-arrow:before { - content: "\e652"; -} -.icon-alert:before { - content: "\e653"; -} -.icon-alarm:before { - content: "\e654"; -} -.icon-add-date:before { - content: "\e655"; -} -.icon-add_user:before { - content: "\e656"; -} -.icon-add_text:before { - content: "\e657"; -} -.icon-add_template2:before { - content: "\e658"; -} -.icon-add_template:before { - content: "\e659"; -} -.icon-add_speech:before { - content: "\e65a"; -} -.icon-add_proj:before { - content: "\e65b"; -} -.icon-add_note:before { - content: "\e65c"; -} -.icon-add_label:before { - content: "\e65d"; -} -.icon-add_img:before { - content: "\e65e"; -} -.icon-add_folder:before { - content: "\e65f"; -} -.icon-add_file:before { - content: "\e660"; -} -.icon-add_entry:before { - content: "\e661"; -} -.icon-add_notebook:before { - content: "\e662"; -} -.icon-sign:before { - content: "\e663"; -} -.icon-witness:before { - content: "\e664"; -} -.icon-update:before { - content: "\e667"; -} -.icon-change_plan:before { - content: "\e665"; -} -.icon-stop_contract:before { - content: "\e666"; -} - - -/*Letter spacing grouping*/ - - -.icon-checkbox:before { - letter-spacing:0.3em; -} -.icon-speech:before { - letter-spacing:0.5em; -} -.icon-alert:before { - letter-spacing:0.3em; -} -.icon-publish_to_world:before { - letter-spacing:0.5em; -} -.icon-publish_to_group:before { - letter-spacing:0.5em; -} -.icon-invite_user:before { - letter-spacing:0.5em; -} -.icon-inventory:before { - letter-spacing: 0.5em; -} -.icon-group_proj:before { - letter-spacing: 0.5em; -} -.icon-group_folder_selected:before { - letter-spacing:0.5em; -} -.icon-group_folder:before { - letter-spacing: 0.5em; -} -.icon-group:before { - letter-spacing:0.5em; -} -.icon-copy:before{ - letter-spacing:0.5em; -} -.icon-conf_drop:before { - letter-spacing: 0em; -} -.icon-check:before { - letter-spacing:0.5em; -} -.icon-add_user:before { - letter-spacing:0.5em; -} -.icon-add_text:before { - letter-spacing:0.5em; -} -.icon-add_proj:before { - letter-spacing:0.5em; -} -.icon-add_notebook:before { - letter-spacing:0.5em; -} -.icon-add_template:before { - letter-spacing:0.5em; -} -.icon-add_img:before { - letter-spacing:0.5em; -} -.icon-add_group_proj:before { - letter-spacing:0.5em; -} -.icon-add_group_folder:before { - letter-spacing:0.5em; -} -.icon-add_folder:before { - letter-spacing:0.5em; -} -.icon-add_file:before { - letter-spacing:0.5em; -} -.icon-overview:before { - letter-spacing:0.5em; -} -.icon-add_protocol:before { - letter-spacing:0.5em; -} -.icon-add_template2:before { - letter-spacing:0.5em; -} -.icon-add_entry:before { - letter-spacing:0.5em; -} -.icon-update:before { - letter-spacing:0.5em; -} -.icon-change_plan{ - letter-spacing:0.5em; -} -.icon-stop_contract{ - letter-spacing:0.5em; -} -/**********************/ -/* image marker START */ -/**********************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -#image_marker_tools { - background: #FFF; - border: 0; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.3); - display: block; - height: 40px; - left: 0; - position: absolute; - right: 0; - top: 30px; - z-index: 95; -} -.image_marker_btn_group { - display: inline-block; - height: 30px; - margin: 5px 10px 5px 10px; - position: relative; - vertical-align: middle; - white-space: nowrap; -} -#more_options_image_marker, -#image_marker_zoom, -#image_marker_edition { - float: right; -} -button.image_marker_button { - border-radius: 0; - background-color: #FFF; - border: 1px solid transparent; - color: #374858; - cursor: pointer; - display: inline-block; - font-size: 14px; - height: 30px; - line-height: 20px; - margin-bottom: 0; - margin-left: -1px; - padding: 4px 10px; - position: relative; - text-align: center; - vertical-align: middle; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ -} -button.image_marker_delete_disabled, -button.image_marker_delete_disabled:hover { - color: #5e7b97 !important; - cursor: default !important; - z-index: 5; -} -button.image_marker_button:hover { - background: #f3f5f7; -} -button.image_marker_button_active { - border: 1px solid #69bfee; - z-index: 5; -} -div.image_marker_toolbar_label { - display: inline-block; - height: 30px; - padding: 0 5px; - text-align: center; -} -div.image_marker_options { - background: #FFF; - display: none; - line-height: 30px; - margin-top: 5px; - padding: 5px; - position: absolute; - z-index: 25; -} -#image_marker_toolbar_list, -#image_marker_opacity_list, -#image_marker_stroke_size_list, -#image_marker_font_size_list { - margin: 0; - padding: 0; - position: relative; - overflow: hidden; -} -li.image_marker_size_options { - border-top: none; - cursor: pointer; - display: list-item; - line-height: 15px; - list-style: none; - margin: 0; - padding: 8px 0; - text-align: center; -} -li.image_marker_size_options:hover { - background: #f3f5f7; -} -#image_marker_size_user_input input { - background: #f9fafb; - border: 1px solid #d9e1e8; - height: 25px; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - margin: 0 0 5px; - outline: none; - text-align: center; - width: 50px; -} -#image_marker_size_drop_down { - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - background: none repeat scroll 0 0 #FFFFFF; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.3); - margin-left: -2px; - position: absolute; - width: 60px; - z-index: 1010; -} -#image_marker_stroke_color_box { - background: #F00; - border: 1px solid #AAA; - display: inline-block; - height: 20px; - width: 20px; -} -#image_marker_stroke_empty_box { - height: 14px; - margin: 3px; - width: 14px; -} -div.image_marker_options.image_marker_stroke_color_options { - left: 65px; -} -#image_marker_stroke_color_list { - list-style-type: none; - width: 100px; - padding: 0; - margin: 0; - z-index: 99; -} -li.image_marker_stroke_color_options { - float: left; - margin: 0; -} -li.image_marker_stroke_color_options a { - background: url(/static/img/transparent_bg.png); - display: block; - width: 20px; - height: 20px; - text-decoration: none; - text-indent: -100000px; - outline: 0; - border: none; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ -} -#image_marker_fill_color_box { - background: url('/static/img/transparent_color.png'); - border: 1px solid #9baec0; - display: inline-block; - height: 20px; - width: 20px; -} -div.image_marker_options.image_marker_fill_color_options { - left: 65px; -} -#image_marker_fill_color_list { - list-style-type: none; - width: 100px; - padding: 0; - margin: 0; - z-index: 99; -} -li.image_marker_fill_color_options { - float: left; - margin: 0; -} -li.image_marker_fill_color_options a { - display: block; - width: 20px; - height: 20px; - text-decoration: none; - text-indent: -100000px; - outline: 0; - border: none; -} -li.image_marker_opacity_options { - border: 1px solid #5e7b97; - border-top: none; - cursor: pointer; - display: list-item; - line-height: 15px; - list-style: none; - margin: 0; - padding: 5px 0; - text-align: center; -} -li.image_marker_opacity_options:first-of-type { - border-top: 1px solid #5e7b97; -} -li.image_marker_opacity_options:hover { - color: #69bfee; -} -#image_marker_opacity_drop_down { - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - background: none repeat scroll 0 0 #FFFFFF; - box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15); - position: absolute; - right: 0; - width: 60px; - z-index: 1010; -} -li.image_marker_toolbar_options { - border-top: none; - cursor: pointer; - display: list-item; - line-height: 15px; - list-style: none; - margin: 0; - padding: 8px; - text-align: left; -} -li.image_marker_toolbar_options:hover { - background: #f9fafb; -} -#image_marker_toolbar_drop_down { - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - background: #e6ebef; - box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15); - top: 30px; - padding: 10px 0 10px 0; - position: absolute; - right: 0; - z-index: 1010; -} -#image_marker_toolbar_drop_down:after { - top: -11px; - right: 16px; - border: solid rgba(0, 0, 0, 0); - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-bottom-color: #e9edf1; - border-width: 7px; - margin-left: -3px; -} -.image_marker_options button.image_marker_button { - display: block; - width: 60px; - margin-top: -1px; -} -.image_marker_toolbar_label span { - vertical-align: middle; -} -/* .image_marker_settings{ */ -/* position:absolute; */ -/* background:#FFF; */ -/* width:100%; */ -/* height:50px; */ -/* overflow:auto; */ -/* display: block; */ -/* } */ -/* .image_marker_settings h4{ */ -/* padding: 0; */ -/* margin: 0; */ -/* text-decoration: underline; */ -/* margin-bottom: 10px; */ -/* } */ -#image_marker_settings button { - width: 55px; - padding-left: 0px; -} -#image_marker_settings span.icon-triangle_down { - font-size: 8px; - position: absolute; - right: 5px; - top: 14px; - vertical-align: top; -} -.image_marker_tools { - margin-bottom: 25px; -} -.image_marker_tools input:checked + label { - font-weight: bold; -} -.image_marker_options_name { - float: left; - width: 75px; - margin-bottom: 20px; -} -.image_marker_canvasview { - background: url(/static/img/transparent_bg.png); - position: absolute; - bottom: 0; - top: 70px; - left: 0; - right: 0; - overflow: auto; -} -.image_marker_pointer_cursor { - cursor: pointer; -} -.image_marker_text_cursor { - cursor: text; -} -#image_marker_canvaslayer { - position: absolute; - display: block; - z-index: 15; -} -#image_marker_canvastextarea { - background: rgba(255, 255, 255, 0.7); - border: none; - display: none; - font-family: sans-serif; - outline: none; - overflow: hidden; - position: absolute; - padding: 5px; - transition-property: width, height; - transition: 0.2s ease; - white-space: pre; - z-index: 2; -} -#image_marker_canvasframe { - position: relative; - -webkit-user-select: none; - /*Chrome all / Safari all*/ - -moz-user-select: none; - /*Firefox all*/ - -ms-user-select: none; - /*IE 10+*/ -} -#canvas_textarea_span { - font-family: sans-serif; - line-height: normal; - display: none; - color: white; - position: absolute; - padding: 5px; - word-wrap: normal; - white-space: nowrap; -} -.image_marker_notification { - display: none; - position: absolute; - left: 50%; - top: 50%; - width: 100px; - margin-left: -50px; - padding: 10px; - color: #fff; - font-size: 32; - text-align: center; - box-shadow: 4px 4px 5px #666; -} -#savingBox { - background: #ddb933; - z-index: 10; -} -#savedBox { - background: #bdca70; - z-index: 15; -} -#errorBox { - background-color: #E66873; -} -.image_marker_tooltip { - display: none; - background-color: #FFF; - border: 1px solid #9baec0; - color: #5e7b97; - font-size: 12px; - padding: 5px; - position: absolute; - top: 35px; - z-index: 100; -} -.image_marker_button:hover .image_marker_tooltip { - display: block; -} -#image_marker_popup { - z-index: 95; -} -#image_marker_popup_window { - z-index: 97; -} -/********************/ -/* image marker END */ -/********************/ - -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -#import_header { - border-bottom: 1px solid #DDD; - height: 50px; -} -#import_header .placeholder_frame { - display: inline-block; - float: right; - margin: 10px 10px 10px 0; -} -#import_header .placeholder_frame label { - width: 150px; -} -#import_loading { - position: absolute; - top: 50%; - left: 50%; - text-align: center; - width: 80px; - height: 80px; - margin-top: -40px; - margin-left: -40px; -} -.import_popup_content { - height: 100%; - position: relative; - width: 100%; -} -#import_container { - position: absolute; - left: 0; - right: 0; - top: 80px; - bottom: 60px; - overflow: auto; -} -#import_container ul { - padding-right: 40px; -} -#import_container li { - display: inline-block; - overflow: hidden; - width: 100%; -} -#import_container li > div { - border: 1px solid transparent; - position: relative; - cursor: pointer; - margin: 0 5px; - padding: 10px; - font-size: 18px; -} -#import_container .active > div { - background: #ededed; - font-weight: bold; - border: 1px solid #69bfee; - color: #69bfee; -} -#import_container li > div:hover { - border: 1px solid #69bfee; - color: #69bfee; -} -#import_container div > span { - position: absolute; - left: 10px; -} -#import_container div.info { - margin-left: 30px; -} -.info img { - width: 20px; - margin-left: 5px; - position: absolute; -} -#import_container .info div { - display: block; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} -#import_container .figshare_main_search { - left: 50%; - margin: -40px 0 0 -200px; - position: absolute; - height: 80px; - text-align: center; - top: 50%; - width: 400px; -} -#import_container .figshare_main_search input { - width: 400px; -} -#import_container h3, -#import_container .load_more { - font-weight: normal; - text-align: center; -} -#import_footer { - position: absolute; - bottom: 0; - height: 60px; - left: 0; - border-top: 1px solid #DDD; - right: 0; -} -#import_footer .popup_dialog_cancel_save_panel { - position: absolute; - bottom: 15px; - right: 15px; -} -#import_footer .select_file { - float: left; - font-size: 12px; -} -#import_footer .popup_dialog_error { - margin: 15px 150px; -} -#breadcrumbs { - position: absolute; - left: 0; - right: 200px; - font-size: 18px; - padding: 15px; -} -div.import_source, -div.export_source { - height: 180px; - width: 800px; -} -div.import_logo, -div.export_logo { - /* display: inline-block; */ - float: left; - width: 130px; - height: 130px; -} -.upload_btn_wrap { - margin: 55px 20px; -} -.upload_btn_wrap .btn_on_grey { - height: 50px; - width: 112px; - padding-left: 8px; -} -.import_logo img, -.export_logo img { - cursor: pointer; - border: 1px solid transparent; - background: #ffffff; - width: 100%; - -webkit-transition: all 0.1s ease; - -moz-transition: all 0.1s ease; - -o-transition: all 0.1s ease; - transition: all 0.1s ease; -} -.import_logo img:hover, -.export_logo img:hover { - border: 1px solid #bac7d4; -} -.import_logo_set, -.export_logo_set { - line-height: 18px; - text-align: center; -} -.dropbox_folder_view { - box-shadow: 0px 0px 10px #AAA; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - max-height: 150px; - overflow-x: hidden; - overflow-y: auto; - padding: 0 10px; - margin-top: 10px; -} -.dropbox_folder_view ul { - margin: 0; - padding: 10px 0; -} -.dropbox_folder_view .name { - margin-left: 10px; -} -.dropbox_folder_view .folder { - border: 1px solid transparent; - cursor: pointer; - display: inline-block; - padding: 2px; - overflow: hidden; - width: 100%; -} -.dropbox_folder_view .folder:hover { - border: 1px solid #69bfee; - color: #69bfee; -} - -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -#mendeley_auth { - background-color: #FFF; - border: 0; - border-radius: 5px; - height: 335px; - left: 50%; - margin: -155px 0 0 -235px; - outline: none; - overflow: hidden; - position: absolute; - top: 240px; - width: 470px; -} -.mendeley_auth_header { - text-align: center; -} -#my_popup_inner.mendeley_popup { - transition: all ease 1s; - overflow: hidden; -} -#mendeley_loading { - position: absolute; - top: 50%; - left: 50%; - text-align: center; - width: 80px; - height: 80px; - margin-top: -40px; - margin-left: -40px; -} -.reference_files_loading { - width: 20px; -} -.mendeley_library_loading { - position: absolute; - left: 41%; - text-align: center; - top: 35%; - font-size: 20px; -} -.mendeley_files_loading { - width: 20px; - margin-bottom: -4px; -} -.mendeley_popup_content { - height: 100%; - position: relative; - width: 100%; -} -#mendeley_library_view { - display: inline-block; - position: absolute; - width: 100%; - transition: all ease 0.5s; -} -.mendeley_library_progress { - display: none; - margin: 15px 0 0 15px; -} -.mendeley_loaded { - margin-left: 15px; -} -#mendeley_library_header .placeholder_frame { - float: right; - margin: 10px 10px 10px 0; -} -#mendeley_library_header .placeholder_frame label { - width: 150px; -} -#mend_lib_table { - width: 100%; -} -#mend_headers { - width: 100%; - height: 24px; - outline: 1px solid #DDD; - line-height: 24px; -} -#mend_headers th:hover { - color: #69bfee; -} -tr.mend_table_row_pair, -tr.mend_table_row { - display: block; - padding: 10px 0; - width: 100%; - min-height: 18px; -} -tr.mend_table_row:hover { - color: #69bfee; - outline: 1px solid #69bfee; - cursor: pointer; -} -tr.mend_table_row_pair { - background-color: #DDD; -} -#mend_headers th { - cursor: pointer; - display: inline-block; - -webkit-user-select: none; - /* Chrome all / Safari all */ - -moz-user-select: none; - /* Firefox all */ - -ms-user-select: none; - /* IE 10+ */ -} -td.mend_added, -td.mend_year { - text-align: center; -} -span.highlight { - background-color: yellow; -} -td.mend_author span { - margin-left: 10px; -} -td.mend_author, -#mend_header_author { - width: 25%; -} -td.mend_title { - width: 40%; -} -#mend_header_title { - width: 39%; -} -td.mend_year, -#mend_header_year { - width: 5%; -} -td.mend_published, -#mend_header_published { - text-align: center; - width: 15%; -} -td.mend_added, -#mend_header_added { - width: 10%; -} -#mend_lib_table_body { - overflow-x: hidden; - overflow-y: scroll; - height: 600px; - display: block; -} -#mend_lib_table th, -#mend_lib_table td { - display: inline-block; - height: 100%; -} -.placeholder_frame label { - pointer-events: none; -} -.epb_header_sticky div.action_button_import { - margin-left: 0px !important; -} -#mendeley_detail_view { - display: inline-block; - left: 100%; - position: absolute; - width: 100%; - height: 100%; - transition: all ease 0.5s; -} -#mendeley_detail_view div.popup_dialog_cancel_save_panel { - bottom: 25px; - left: 50px; - padding: 20px 0; - position: absolute; - right: 15px; -} -#mendeley_back_to_library { - background-color: #DDD; - cursor: pointer; - display: inline-block; - font-size: 30px; - height: 100%; - padding-right: 5px; - position: absolute; -} -#mendeley_back_to_library span { - margin-left: 5px; - top: calc(20%); - position: relative; -} -#mendeley_detail_page { - bottom: 30px; - display: inline-block; - left: 50px; - overflow: auto; - padding: 0 20px 20px 0; - position: absolute; - right: 0px; - top: 0px; -} -.reference_detail_label { - font-weight: bold; - margin-right: 5px; -} -button.mend_add_reference { - float: right !important; -} -div.mend_file_line { - height: 40px; - line-height: 30px; - padding-left: 20px; -} -.mend_file_line button { - margin-left: 20px; -} -.doc_details { - margin: 10px 0; -} -span.mend { - white-space: pre; -} - -/****************************** - MESSAGE LIST VIEW -*******************************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -#messages_header { - background: #EEE; - border-bottom: 1px solid #D6D4D5; - border-radius: 10px 10px 0 0; - display: block; - font-size: 14px; - height: 25px; - padding: 10px 0px 5px 15px; -} -#messages_content { - max-width: 900px; - padding-left: 10px; - display: block; - line-height: 18px; - overflow: auto; -} -.message_page_change { - box-sizing: border-box; - cursor: pointer; - display: inline-block; - width: 30px; - text-align: center; - font-size: 22px; - margin: 0; - line-height: 0.6; - height: 17px; - margin-top: 4px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; -} -.message_pagination, -.message_total, -.message_shown { - font-size: 11px; -} -.message_pagination { - position: relative; - float: left; -} -.pagination_count { - float: left; - position: relative; - width: auto; - margin-right: 20px; - padding-top: 7px; -} -.message_page_change.disabled { - color: #4b6277; - cursor: default; -} -.message_empty_folder { - padding: 50px; - text-align: center; - font-size: 12px; -} -.message_list { - font-size: 14px; -} -.message_list table { - border-collapse: collapse; - outline: none; - table-layout: fixed; - width: 100%; - position: relative; -} -.message_list table td { - line-height: 1.2; - position: relative; -} -.column_name { - min-width: 100px; - width: 25%; -} -.column_delete { - width: 30px; -} -.column_date { - width: 89px; -} -.message_list_line { - font-size: 12px; - border-bottom: 1px solid #bac7d4; - cursor: pointer; - height: 34px; - line-height: 1.2; - white-space: nowrap; -} -.message_list_line:last-child { - border: none; -} -.message_list_line:hover .message_line_delete { - display: block; -} -.message_list_line:hover { - background: #ecf0f3; -} -.message_list_line:first-child:hover { - background: none; - cursor: default; -} -.unread_message { - font-weight: bold; -} -.unread_message .message_line_name:after { - content: ""; - width: 4px; - height: 4px; - border-radius: 50%; - background: #69bfee; - position: absolute; - left: -4px; - top: 14px; -} -.message_line_name { - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: bottom; - overflow: hidden; - padding-left: 4px; -} -.message_line_text { - overflow: hidden; - text-overflow: ellipsis; -} -.message_line_content { - color: #9baec0; -} -.message_line_delete { - display: none; - text-align: center; -} -.message_line_delete .trash-img { - margin-top: -4px; -} -.message_line_delete:hover { - color: #4bb1d7; - text-align: center; -} -.message_line_date { - padding-right: 10px; - font-size: 11px; -} -.filter_dn_wrap { - width: 190px; - height: 200px; - position: absolute; - left: 0; - top: 25px; - z-index: 999; - display: none; -} -/****************************** - MESSAGE DIALOG VIEW -*******************************/ -#dialog_message_form div.input_block { - margin: 0; - padding: 3px 5px; -} -.message_content { - margin-top: 10px !important; - background: white; - color: #4b6277; - min-height: 150px; -} -#message_select_group { - margin: 0 0 10px 0; -} -#dialog_message_form .recipient_label { - display: inline-block; - vertical-align: top; - width: 22px; - padding: 5px 0 0 0; - margin-bottom: 5px; -} -#dialog_message_form .recipient_field { - cursor: text; - display: inline-block; - min-height: 33px; - width: 700px; -} -#dialog_message_form .add_recipient { - cursor: pointer; - display: inline-block; - margin-bottom: 5px; - padding: 5px 0 0 0; - vertical-align: top; - width: 20px; -} -#dialog_message_form .add_recipient.disabled { - cursor: default; - color: #bac7d4; -} -#recipientIds, -#recipientEmails { - display: none; -} -#dialog_message_form .recipient_token { - background: #f9fafb; - border: 1px solid #7b95ad; - border-radius: 3px; - cursor: move; - height: 25px; - width: auto; - display: inline-block; - padding: 5px; - margin: 0px 6px 0 0; -} -#dialog_message_form .recipient_token.selected { - border: 1px solid #4bb1d7 !important; -} -#dialog_message_form .recipient_token.invalid { - border: 1px solid #E66873; - color: #E66873; -} -#dialog_message_form .name_token { - display: inline-block; - line-height: 14px; - height: auto; - margin-right: 5px; - max-width: 250px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -#dialog_message_form .erase_token { - cursor: pointer; - display: inline-block; - vertical-align: top; -} -#dialog_message_form .message_recipient textarea, -#recipient_width { - border: 1px solid rgba(0, 0, 0, 0); - display: inline-block; - font-size: 12px; - font-family: arial, sans-serif; - color: #4b6277; - height: 26px; - line-height: 12px; - outline: none; - padding: 6px; - resize: none; - vertical-align: bottom; - overflow: hidden; -} -#recipient_width { - display: none; -} -#dialog_message_form .message_content { - max-height: 450px; - overflow: auto; -} -#dialog_message_form .message_content textarea { - display: block; - font-size: 14px; - color: #4b6277; - height: 200px; - margin: 0; - resize: none; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -#dialog_message_form .placeholder_frame { - float: none; - width: 100%; -} -.recipient_tree { - display: none; - position: relative; - background: #ecf0f3; - box-sizing: border-box; - max-height: 150px; - overflow: auto; - padding: 0 10px; - margin-bottom: 10px; - font-size: 12px; -} -.recipient_tree a { - color: #4b6277; - line-height: 25px; - text-decoration: none; -} -.recipient_tree div.group_treeline_children { - padding-left: 15px; - margin-left: 0px; - box-sizing: border-box; -} -.recipient { - line-height: 24px; -} -.recipient:after { - content: ", "; -} -.recipient:last-child:after { - content: ""; -} -.message_subject { - font-weight: bold; -} -.member_input { - vertical-align: middle; - position: relative; - bottom: 1px; -} - -/**************** -* notebook.less * -*****************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -#action_buttons { - display: inline-block; - float: right; - height: 250px; - left: 50%; - margin-left: 410px; - position: fixed; - top: 110px; - width: 150px; -} -/**************** -* button + input* -****************/ -button { - border: 0; - font-size: 12px; - padding: 3px 4px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; -} -button:focus { - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; -} -.search_button { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - border: solid 1px #bac7d4 !important; -} -.btn_on_grey { - color: #415568; - background: #f3f5f7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #f3f5f7)); - background: -ms-linear-gradient(bottom, #e0e6eb, #f3f5f7); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #f3f5f7 100%); - background: -o-linear-gradient(#f3f5f7, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f5f7', endColorstr='#e0e6eb', GradientType=0); - border: 1px solid #7b95ad; - line-height: 1.2; -} -.btn_on_grey:hover { - color: #415568; - background: #f3f5f7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #f3f5f7)); - background: -ms-linear-gradient(bottom, #e0e6eb, #f3f5f7); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #f3f5f7 100%); - background: -o-linear-gradient(#f3f5f7, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f5f7', endColorstr='#e0e6eb', GradientType=0); - outline: 0; - border: 1px solid #5e7b97; - -webkit-box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); - -moz-box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); - box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); -} -.btn_on_grey:active { - color: #4b6277; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #4b6277; - background: #cad4de; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #cad4de)); - background: -ms-linear-gradient(bottom, #e0e6eb, #cad4de); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #cad4de 100%); - background: -o-linear-gradient(#cad4de, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cad4de', endColorstr='#e0e6eb', GradientType=0); -} -.btn_on_white { - color: #4b6277; - background: #e6ebef; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #d9e1e8), color-stop(1, #e6ebef)); - background: -ms-linear-gradient(bottom, #d9e1e8, #e6ebef); - background: -moz-linear-gradient(center bottom, #d9e1e8 0%, #e6ebef 100%); - background: -o-linear-gradient(#e6ebef, #d9e1e8); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e6ebef', endColorstr='#d9e1e8', GradientType=0); - border: 1px solid #cad4de; - opacity: 1; - line-height: 13px; -} -.btn_on_white:hover:enabled { - -ms-filter: none; - filter: none; - outline: 0; - border: 1px solid #b4c2d0; -} -.btn_on_white:active { - color: #4b6277; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #c7d2dc; - background: #d9e1e8; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #d9e1e8), color-stop(1, #d0d9e2)); - background: -ms-linear-gradient(bottom, #d9e1e8, #d0d9e2); - background: -moz-linear-gradient(center bottom, #d9e1e8 0%, #d0d9e2 100%); - background: -o-linear-gradient(#d0d9e2, #d9e1e8); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0d9e2', endColorstr='#d9e1e8', GradientType=0); -} -.btn_on_white.disabled { - opacity: 0.6; -} -.btn_on_white.disabled:active { - color: #4b6277; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0); - border: 1px solid #cad4de; - background: #e6ebef; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #d9e1e8), color-stop(1, #e6ebef)); - background: -ms-linear-gradient(bottom, #d9e1e8, #e6ebef); - background: -moz-linear-gradient(center bottom, #d9e1e8 0%, #e6ebef 100%); - background: -o-linear-gradient(#e6ebef, #d9e1e8); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e6ebef', endColorstr='#d9e1e8', GradientType=0); -} -.btn_on_white.disabled:hover { - -ms-filter: none; - filter: none; - outline: 0; - border: 1px solid #cad4de; -} -.filter_btn { - color: #526c84; - background: #ecf0f3; - height: 24px; - padding: 2px 8px; - font-size: 12px; - cursor: pointer; - -webkit-border-radius: 0px; - -moz-border-radius: 0px; - border-radius: 0px; - -webkit-transition: all 0.1s ease; - -moz-transition: all 0.1s ease; - -o-transition: all 0.1s ease; - transition: all 0.1s ease; -} -.filter_btn > span { - height: 4px; - width: 12px; - display: block; - float: left; - margin: 2px 0 0 8px; -} -.filter_btn > p { - margin: 0; - float: left; -} -.filter_btn:hover { - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.1); - background: #e0e6eb; - padding-top: 2px; -} -.filter_btn:active { - -webkit-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - background: #cdd7e0; -} -span.close-x { - display: block; - float: left; - margin: 0 0 0 8px; - display: none; -} -.filter_on { - background: #527ca3; - color: white; -} -.filter_on:hover, -.filter_on:active { - background: #527ca3; - color: #e0e6eb; -} -.filter_active { - background: #5b96cd; - color: #ffffff; -} -.filter_active .arrow_down_s-img:after { - border-top-color: white; -} -.filter_active:hover { - background: #5b96cd; - color: #e6ebef; -} -.grey_link { - color: #4b6277; - background: transparent; - font-size: 12px; - padding: 0; - text-decoration: underline; - display: block; - cursor: pointer; -} -.grey_link:hover { - color: #415568; - text-decoration: underline; -} -.grey_link:active { - text-decoration: none; -} -.blue_link { - color: #1995d8; - background: transparent; - font-size: 12px; - padding: 0; - text-decoration: underline; - display: block; - cursor: pointer; -} -.blue_link:hover { - color: #69bfee; - text-decoration: underline; -} -.blue_link:active { - color: #1995d8; - text-decoration: none; -} -.feedback_btn { - color: white; - border: 1px solid #994097; - font-weight: bold; - font-size: 14px; - padding: 5px 0 5px 5px; - position: absolute; - top: 213px; - left: -2px; - z-index: 101; - background: #ab48a9; - cursor: pointer; -} -.feedback_btn > p { - margin: 0; -} -.feedback_btn:hover, -.feedback_btn:focus { - background: #ab48a9; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #bc60ba), color-stop(1, #ab48a9)); - background: -ms-linear-gradient(bottom, #bc60ba, #ab48a9); - background: -moz-linear-gradient(center bottom, #bc60ba 0%, #ab48a9 100%); - background: -o-linear-gradient(#ab48a9, #bc60ba); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ab48a9', endColorstr='#bc60ba', GradientType=0); -} -.feedback_btn:active { - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #873986; - background: #ab48a9; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #c575c3), color-stop(1, #ab48a9)); - background: -ms-linear-gradient(bottom, #c575c3, #ab48a9); - background: -moz-linear-gradient(center bottom, #c575c3 0%, #ab48a9 100%); - background: -o-linear-gradient(#ab48a9, #c575c3); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ab48a9', endColorstr='#c575c3', GradientType=0); -} -.feedback_btn_dialog { - color: white; - font-weight: bold; - font-size: 16px; - padding: 8px 10px; - background: #ab48a9; - cursor: pointer; - border: 0; - display: block; - margin: 90px auto 20px auto; -} -.feedback_btn_dialog > p { - margin: 0; -} -.feedback_btn_dialog:hover { - color: #e5c1e4; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); -} -.feedback_btn_dialog:active { - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); -} -.invite_btn_dialog { - color: white; - font-weight: bold; - font-size: 16px; - padding: 8px 10px; - background: #93ba48; - cursor: pointer; - border: 0; - display: block; - margin: 20px auto; -} -.invite_btn_dialog > p { - margin: 0; -} -.invite_btn_dialog:hover { - color: #e0ebca; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); -} -.invite_btn_dialog:active { - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); -} -.invite_btn { - border: 1px solid #85a940; - color: white; - font-weight: bold; - font-size: 14px; - padding: 4px 3px 5px 1px; - position: absolute; - top: 296px; - left: -2px; - z-index: 50; - background: #93ba48; - cursor: pointer; -} -.invite_btn > p { - margin: 0; - float: left; -} -.invite_btn > span { - margin: 2px 2px 0 4px; -} -.invite_btn:hover, -.invite_btnfocus { - background: #93ba48; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #a0c25e), color-stop(1, #93ba48)); - background: -ms-linear-gradient(bottom, #a0c25e, #93ba48); - background: -moz-linear-gradient(center bottom, #a0c25e 0%, #93ba48 100%); - background: -o-linear-gradient(#93ba48, #a0c25e); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#93ba48', endColorstr='#a0c25e', GradientType=0); -} -.invite_btn:active { - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #769639; - background: #93ba48; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #adcb74), color-stop(1, #93ba48)); - background: -ms-linear-gradient(bottom, #adcb74, #93ba48); - background: -moz-linear-gradient(center bottom, #adcb74 0%, #93ba48 100%); - background: -o-linear-gradient(#93ba48, #adcb74); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#93ba48', endColorstr='#adcb74', GradientType=0); -} -.checkbox_filled[type="checkbox"] { - display: none; -} -.checkbox_filled[type="checkbox"]:checked + label:after { - background: #69bfee; - border: 1px solid #5e7b97; -} -.checkbox_filled_bg { - font-size: 12px; - position: relative; - display: inline-block; - padding: 4px 0 4px 25px; - display: block; - width: 110px; - cursor: pointer; -} -.checkbox_filled_bg:hover { - background: #ecf0f3; -} -.checkbox_filled_bg:after { - content: ""; - position: absolute; - display: block; - top: 6px; - left: 5px; - width: 10px; - height: 10px; - border: 1px solid #bac7d4; -} -.checkbox_button_input[type="checkbox"] { - display: none; -} -.checkbox_button_input[type="checkbox"]:checked + label { - background: #e0e6eb; -} -.checkbox_button_input[type="checkbox"]:checked + label:after { - background: #69bfee; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - border: 1px solid #c5e6f8; -} -.empty_folder { - font-size: 12px; - color: #aabbca; -} -.checkbox_button { - font-size: 12px; - position: relative; - padding: 4px 0 4px 1px; - display: inline-block; - width: 100%; - margin: 0; - cursor: pointer; -} -.checkbox_button:hover { - background: #ecf0f3; -} -.checkbox_button b .folder_dn-img, -.checkbox_button b .folder_up-img { - margin-top: -2px; - margin-right: 6px; -} -.checkbox_button:after { - content: ""; - position: absolute; - display: block; - top: 5px; - right: 10px; - width: 10px; - height: 10px; - border: 1px solid #bac7d4; - border-radius: 50%; - -webkit-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); -} -.own_name { - font-size: 12px; - position: relative; - padding: 4px 0 4px 1px; - display: inline-block; - width: 100%; - margin: 0; - background: #ecf0f3; - padding-left: 10px; - margin-bottom: 14px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: default; -} -.own_name:after { - content: ""; - position: absolute; - display: block; - top: 5px; - right: 10px; - width: 10px; - height: 10px; - border-radius: 50%; - background: #69bfee; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - border: 1px solid #c5e6f8; -} -.label_title { - display: inline-block; - width: calc(80% - 12px); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.input_label_wrap { - position: relative; -} -.input_label_wrap p { - font-size: 12px; - margin: 0 0 4px 4px; -} -.input_label_wrap label { - position: absolute; - bottom: 4px; - left: 4px; - color: #aabbca; -} -/* div.action_button { */ -/* background: #FFF; */ -/* border: 1px solid #CCC; */ -/* border-radius: 5px 5px 5px 5px; */ -/* color: #374858; */ -/* cursor: pointer; */ -/* display: inline-block; */ -/* float: left; */ -/* font-size: 14px; */ -/* height: 25px; */ -/* line-height: 30px; */ -/* margin-right: 10px; */ -/* padding: 0 10px; */ -/* text-align: center; */ -/* top: 0; */ -/* } */ -/* div.action_button:hover { */ -/* color: #69bfee; */ -/* border: 1px solid #69bfee; */ -/* } */ -div.action_button_click_only { - cursor: pointer; -} -div.bigger_button { - font-size: 18px; - margin: 0; - padding: 5px; - width: 250px; - cursor: pointer; - transition: background 0.3s ease; -} -#button_add_entry { - /* margin-right: 10px; */ -} -.action_button { - height: 19px; - width: 24px; -} -.action_button img { - width: 24px; - height: 24px; - display: inline-block; - margin: auto; -} -.action_button p { - display: inline-block; - margin: 0; - margin-left: 5px; - text-align: left; -} -.file_upload_button { - width: auto; - height: 30px; -} -#saved_entry { - display: none; - background-color: #BDCA70; - border-radius: 5px; - color: white; - font-size: 18px; - left: 50%; - margin-left: -60px; - padding: 10px; - position: absolute; - text-align: center; - top: 0; - width: 100px; -} -div.dragging_entry { - background: #69bfee; - border-radius: 2px; - color: #FFF; - cursor: move; - font-size: 18px; - margin-top: -10px; - margin-left: -30px; - opacity: 0.5; - padding: 10px; - text-align: left; - width: 80px !important; - z-index: 100; -} -div.dd_entry_table { - display: table; - table-layout: fixed; - width: 100%; - height: 0; -} -div.dd_entry_row { - display: table-row; -} -div.dd_entry_cell { - border: 1px solid transparent; - display: table-cell; - vertical-align: top; -} -div.dd_entry_cell:hover { - border: 1px solid #CCC; -} -div.dd_entry_cell_wrapper { - position: relative; - height: 100%; - margin: 5px; -} -div.dd_entry_cell_content { - position: relative; - display: block; - min-height: 66px; - vertical-align: top; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - overflow: hidden; - /* For tables */ -} -.handsontable { - overflow: scroll; -} -div.dd_entry_empty_element { - font-size: 16px; - padding: 15px 10px; - text-align: center; - overflow: hidden; - word-break: break-word; -} -div.dd_entry_cell_content img { - -webkit-user-select: none; - /* Chrome all / Safari all */ - -moz-user-select: none; - /* Firefox all */ - -ms-user-select: none; - /* IE 10+ */ -} -div.dd_entry_cell_content .imageLayer { - left: 0; - margin-left: auto; - margin-right: auto; - position: absolute; - right: 0; - top: 0; -} -.file_placeholder { - text-align: center; - background-color: #d9e1e8; - border: 1px solid rgba(0, 0, 0, 0); - padding-top: 5px; - transition: background 0.3s ease; -} -.file_placeholder button { - cursor: pointer; - margin: 5px; - padding: 5px; -} -div.dd_entry_cell_file_download { - font-size: 16px; - padding: 15px 10px; - text-align: center; - overflow: hidden; - word-break: break-word; -} -div.dd_entry_cell_file_download span.icon-file { - font-size: 36px; -} -div.file_icon { - vertical-align: bottom; - display: inline-block; -} -div.file_extension { - position: absolute; - background-color: #374858; - color: #FFF; - font-size: 12px; - line-height: 12px; - margin: 12px 0 0 -16px; - padding: 2px; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - border: 1px solid #FFF; - width: 32px; -} -div.file_details { - display: inline-block; - text-align: left; - vertical-align: top; - line-height: 20px; -} -div.file_name { - display: block; - font-size: 18px; -} -div.file_size_link { - display: block; -} -div.file_size_link a { - margin-left: 10px; -} -div.dd_image_entry .dd_entry_cell_content { - text-align: center; - overflow: hidden; -} -.entry_button { - background-color: #e6ebef; - cursor: pointer; - display: none; - height: 30px; - margin: 0; - padding: 5px 0 0; - position: relative; - float: left; - text-align: center; - width: 35px; - z-index: 2; - font-size: 18px; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; - -o-transition: all 0.2s ease; - transition: all 0.2s ease; -} -.entry_button:hover { - background-color: #d9e1e8; -} -.entry_button:active { - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); -} -div.zoom_button, -div.settings_button { - /* border-bottom: 1px solid #CCC; */ - /* border-left: 1px solid #CCC; */ - border-right: 0; - border-top: 0; - border-radius: 0; - right: 0; -} -div.cancel_button, -div.drag_button { - /* right: 35px; */ -} -div.save_button, -div.edit_button { - /* border-right: 1px solid #CCCCCC; */ - /* right: 70px; */ -} -div.zoom_button { - /* border-right: 1px solid #CCCCCC; */ - /* right: 105px; */ -} -div.zoom_button span { - font-size: 14px; - margin: 10px; - line-height: 1.6; - color: #4b6277; -} -div.drag_button { - cursor: move; -} -div.cancel_button, -div.save_button { - display: none; -} -div.zoom_button:hover, -div.cancel_button:hover, -.save_button:hover, -.settings_button:hover, -.drag_button:hover, -.edit_button:hover { - /* color: #69bfee; */ -} -div.zoom_button:hover, -div.settings_button:hover { - margin: 0; -} -div.dd_entry_cell:hover div.zoom_button, -div.dd_entry_cell:hover div.settings_button, -div.dd_entry_cell:hover div.drag_button, -div.dd_entry_cell:hover div.edit_button { - display: block; -} -/* we need !important to override inline css set in labfolder-project.js when showing or hiding buttons for redactor enabled/disabled */ -div.epb_entry.readOnly div.cancel_button, -div.epb_entry.readOnly div.drag_button, -div.epb_entry.readOnly div.settings_button, -div.epb_entry.readOnly div.save_button, -div.epb_entry.readOnly div.edit_button, -div.epb_entry.readOnly div.zoom_button, -div.epb_entry.readOnly button.file_upload_button, -div.epb_entry.readOnly div.more_options_item_remove_block_element { - display: none !important; -} -div.disabled_button { - display: none !important; -} -/*TODO nest better hdrop*/ -.hdrop { - height: 15px; - display: table; - table-layout: fixed; - width: 100%; - transition: background 0.3s ease; -} -.hdrop:only-child { - box-sizing: border-box; - height: 100px; - padding: 40px; -} -.hdrop:only-child:before { - content: "This entry is empty. You can add a TEXT, a SKETCH, a TABLE or attach a FILE by clicking or dragging the buttons in the toolbar above."; - font-size: 13px; - background: #ffffff; - padding: 2px 4px; -} -.hdrop.drop_active:only-child:before { - content: "Drag it here."; -} -.hdrop.drop_hover:only-child:before { - content: "Now drop it."; -} -.hdrop:last-child { - /* border-radius: 0 0 10px 10px; */ -} -.vdrop { - width: 20px; - display: table-cell; - transition: background 0.3s ease; -} -#button_add_entry.drop_active, -.drop_active { - background-color: #aea; -} -.file_placeholder.drop_active { - background-color: #97d3f3; -} -#button_add_entry.drop_hover, -.drop_hover { - background: #69bfee; -} -.file_placeholder.drop_hover { - background-color: #69bfee; -} -.dragBar { - cursor: col-resize; - display: table-cell; - text-align: center; - vertical-align: middle; - width: 10px; -} -.dragBar img { - height: 10px; - width: 2px; -} -.dragBar:hover { - background-color: #DDD; -} -div.epb_entry.readOnly .dragBar { - cursor: default; -} -div.epb_entry.readOnly .dragBar img { - display: none; -} -div.epb_entry.readOnly .dragBar:hover { - background-color: initial; -} -.hidden_entry { - visibility: hidden; -} -.button_wrapper_sticky { - position: fixed !important; - top: 131px !important; - right: inherit !important; - z-index: 20; -} -.dd_entry_cell.ui-state-disabled, -.dd_entry_cell.ui-widget-content .ui-state-disabled, -.dd_entry_cell.ui-widget-header .ui-state-disabled { - background-image: none !important; - opacity: 1 !important; -} -#paste_hidden_input { - opacity: 0; - position: absolute; - right: 10000px; - top: -10000px; -} -/************* -* action bar * -**************/ -.action_bar { - width: 100%; - height: 36px; - min-width: 800px; - padding-top: 10px; - background: white; - border-bottom: solid 2px #a1b3c4; - -webkit-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.2); - -moz-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.2); - box-shadow: 0 3px 4px rgba(55, 72, 88, 0.2); -} -.plus_btn { - width: 64px; - height: 22px; - color: white; - background: #38abf7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0b89dd), color-stop(1, #38abf7)); - background: -ms-linear-gradient(bottom, #0b89dd, #38abf7); - background: -moz-linear-gradient(center bottom, #0b89dd 0%, #38abf7 100%); - background: -o-linear-gradient(#38abf7, #0b89dd); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#38abf7', endColorstr='#0b89dd', GradientType=0); - text-align: left; - font-size: 27px; - font-family: Arial !important; - line-height: 0.6; - padding: 2px 9px; - position: relative; -} -.plus_btn:hover { - outline: 0; - color: #dcf0fb; -} -.plus_btn:active { - -webkit-box-shadow: inset 0 3px 2px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 3px 2px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 3px 2px rgba(55, 72, 88, 0.5); -} -.plus_btn:after { - content: "Add"; - font-size: 13px; - position: absolute; - right: 10px; - top: 12px; - font-weight: bold; - line-height: 0; -} -.plus_btn_wrap { - width: 200px; - float: left; - margin-top: -3px; -} -.plus_btn_hover { - height: 23px; - margin: 0 0 0 55px; -} -.add_dropdown { - display: none; - position: absolute; - top: 85px; - left: 0; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - z-index: 999; -} -.add_dropdown .default_button { - border: 0; - background: none; -} -.add_dropdown .default_button:active { - background: #4fb9f3; - -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0); - -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0); - box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0); -} -.add_dropdown > ul { - width: 180px; - font-size: 14px; - color: white; - margin: 0; - padding: 12px 0 12px 0; - background: #18a2ed; -} -.add_dropdown > ul li { - list-style-type: none; - padding: 8px 10px 8px 50px; - cursor: pointer; -} -.add_dropdown > ul li:hover { - background: #4fb9f3; -} -.add_link { - padding: 0 0 0 50px !important; - height: 32px; -} -.add_link a { - width: auto; - padding: 8px 0 8px 0; - color: white; - text-decoration: none; - display: block; -} -.add_link a:hover { - text-decoration: none; -} -.action_menu_wrap { - float: left; - margin-top: -1px; -} -.filter_wrap > ul > li { - position: relative; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - border-left: solid 1px #bac7d4; - border-top: solid 1px #bac7d4; - height: 25px; -} -.filter_wrap > ul > li:last-child { - padding: 6px 3px 0 10px; - border-left: solid 1px #bac7d4; - border-top: 0; -} -.filter_wrap > ul > li:first-child { - background: none; - border: none; - color: #7b95ad; - font-size: 12px; - padding: 6px 10px 0 0; - margin-left: 18px; -} -.more_filters { - /* display: none; */ -} -.filter_dropdown_wrap { - width: 190px; - height: auto; - position: absolute; - left: -1px; - top: 25px; - z-index: 999; - display: none; - color: #4b6277; -} -.filter_dropdown_wrap .folder_dn-img { - margin-top: 2px; -} -.filter_dropdown_wrap .folder_up-img { - margin-top: 0; -} -.filter_dropdown_wrap header { - font-size: 11px; - color: #d9e1e8; - background: #4b6277; - padding: 3px 6px 2px 6px; - float: left; -} -.filter_dropdown_wrap header > p { - margin: 0; - float: left; -} -.filter_dropdown_wrap header > span { - float: right; - padding: 0px 0 3px 8px; - color: white; - cursor: pointer; -} -.filter_dropdown { - overflow-y: auto; - overflow-x: hidden; - min-width: 190px; - max-height: 600px; - width: auto; - padding-bottom: 20px; - float: left; - border: solid 1px #bac7d4; - background: white; - -webkit-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); -} -.filter_dropdown .list_vertical { - padding-top: 10px; -} -.filter_dropdown ul { - padding-left: 20px; -} -.filter_dropdown > ul { - margin: 0; - padding: 0; - width: 230px; -} -.filter_dropdown li { - list-style-type: none; -} -.filter_dropdown nav { - display: block; - height: 30px; - padding-top: 10px; -} -.filter_dropdown nav button { - float: left; - margin-right: 20px; -} -.filterOverlay.active { - opacity: 0.5; -} -.filter_project_dropdown > ul { - margin: 0; - padding: 0; - width: 270px; -} -.invalid_tag { - font-size: 12px; - color: #e66873; -} -.project_filter { - min-width: 255px !important; - padding: 0 6px 10px 4px; -} -.project_filter .tree_button { - display: none !important; -} -.project_filter .updateTS { - display: none !important; -} -.project_filter .treeline, -.project_filter .treeline_children_empty { - font-size: 12px; -} -.root_folder { - padding: 4px 0 4px 2px !important; - width: calc(100% - 29px); -} -.not_possible_project { - display: none; -} -.not_possible_author { - display: none; -} -.folder_label { - padding: 4px 0 4px 2px !important; - width: calc(100% - 29px); -} -.root_folder_wrap { - overflow: auto; - width: 100%; -} -.filter_date_header { - width: 190px; -} -.dropdown_padding { - padding: 10px; -} -.author_filter { - min-width: 255px !important; - padding: 0 6px 0 4px; -} -.tags_input { - margin-top: 10px; - border: solid 1px #bac7d4; - cursor: text; - padding: 2px; - min-height: 50px; - width: 100%; - overflow: auto; -} -.tags_input > span { - font-size: 11px; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; - height: 18px; - margin: 2px; - cursor: pointer; - display: inline-block; -} -.tags_input > span.selected_token { - border: 1px solid #4bb1d7; -} -.tags_input > span.invalid { - border: 1px solid #E66873; - color: #E66873; -} -.token_input { - border: none; - outline: none; - resize: none; - white-space: pre; - font-size: 11px; - line-height: 11px; - vertical-align: top; - font-family: arial, sans-serif; - padding: 5px 0 0 2px; - margin: 0px; - width: auto; - overflow: auto; -} -.token_input_width { - position: absolute; - height: 11px; - display: inline-block; - padding: 0px 10px; - visibility: hidden; -} -.tag_name { - display: inline-block; - margin-right: 5px; - max-width: 250px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.delete_tag { - color: #9baec0; - cursor: pointer; - display: inline-block; - padding: 1px 3px 1px 0px; - vertical-align: top; -} -.delete_tag:after { - content: "\00d7"; -} -.tag_data_wrap { - margin-top: 10px; -} -.tag_data_wrap > ul { - margin: 0; - padding: 0; -} -.tag_data_wrap > ul li { - list-style-type: none; -} -.tag_index { - padding-right: 5px; - text-align: center; - font-size: 10px; - font-weight: bold; - border-right: solid 1px #bac7d4; - float: left; -} -.tag_index > ul { - margin: 0; - padding: 0; -} -.tag_index > ul li { - list-style-type: none; -} -.tag_index li { - width: 15px; - padding: 3px 0 3px 0; - margin-bottom: 1px; - display: block; - cursor: pointer; -} -.tag_index li:hover { - background: #ecf0f3; -} -.existing_tag { - cursor: pointer; -} -.existing_tag.disabled { - color: white; - background: #7b95ad; - border: 1px solid #7b95ad; -} -li.index_selected { - background: #d9e1e8; -} -li.index_selected:hover { - background: #d9e1e8; -} -.all_tags_head { - font-size: 12px; - margin: 10px 0 5px 0; -} -.all_tags { - font-size: 12px; - margin: 40px 0 5px 0; -} -.tag_register { - overflow: auto; - max-height: 300px; - width: 100%; - float: left; - margin-left: 10px; - font-size: 11px; -} -.tag_register ul { - margin: 0; - padding: 0; -} -.tag_register ul li { - list-style-type: none; -} -.tag_register > ul > li { - margin-bottom: 15px; -} -.tag { - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; - display: inline-block; -} -.my_tags li { - margin-bottom: 5px; -} -.my_tags span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.my_tags .selected_tag { - background: #38abf7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0b89dd), color-stop(1, #38abf7)); - background: -ms-linear-gradient(bottom, #0b89dd, #38abf7); - background: -moz-linear-gradient(center bottom, #0b89dd 0%, #38abf7 100%); - background: -o-linear-gradient(#38abf7, #0b89dd); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#38abf7', endColorstr='#0b89dd', GradientType=0); - color: #ffffff; -} -.my_tags .selected_tag.disabled.selected_tag { - background: #f3f5f7; - border: 1px solid #E66873; - color: #E66873; -} -.group_tags li { - margin-bottom: 7px; -} -.group_tags span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.managed_tags li { - margin-bottom: 7px; -} -.managed_tags span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.custom_selectbox { - min-width: 100px; -} -.filter_date_input { - background: white; - border: solid 1px #bac7d4; - width: 120px; - height: 26px; - padding: 2px; - color: #4b6277; -} -.datepicker_wrap { - margin-top: 20px; -} -.datepicker_wrap > div:first-child { - margin-bottom: 15px; -} -.input_label_wrap label.hidden { - display: none; -} -.filter_date_icon { - display: block; - position: absolute; - right: 24px; - top: 20px; - font-size: 20px; - cursor: pointer; -} -.empty_filter_message { - font-size: 12px; - margin: 0 0 10px 10px; -} -/******* -* entry * -********/ -#epb_container { - position: relative; - width: 100%; -} -.epb_entry { - width: 100%; - margin: 19px 0 15px 0; - display: inline-block; -} -.readOnly .entry_toolbar_btns { - display: none; -} -.entry_loading { - background: rgba(255, 255, 255, 0.7); - position: fixed; - top: 85px; - bottom: 0; - left: 0; - z-index: 99; - right: 0; -} -.entry_loading span { - padding: 25px; - background: #fff; - opacity: 1; - border-radius: 10px; - border: 1px solid #9baec0; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - color: #5e7b97; - font-size: 24px; - top: 300px; - width: 250px; - margin-left: -125px; - left: 50%; - text-align: center; - position: absolute; -} -.entry_container { - min-width: 726px; - margin-right: 45px; -} -.entry_header { - width: 100%; - height: 33px; - font-size: 12px; - background: #cdd7e0; -} -.entry_author { - color: #374858; - float: left; -} -.entry_author > ul { - margin: 0; - padding: 0; -} -.entry_author > ul li { - list-style-type: none; -} -.entry_author figure { - background: #ecf0f3; - border: solid 1px #7b95ad; - margin: 2px; - width: 29px; - height: 29px; - float: left; - position: relative; -} -.entry_author figure img { - width: 27px; - height: 27px; - position: absolute; - top: 0; - left: 0; -} -.entry_author figure > span { - margin-left: 4px; -} -.author_name { - float: left; - padding: 2px; - line-height: 1.3; - width: 196px; -} -.author_firstname, -.author_lastname { - white-space: nowrap; - text-overflow: ellipsis; - display: block; - overflow: hidden; - padding: 0; - margin-left: 0; -} -.entry_title_wrap { - float: left; - position: relative; - padding: 2px 4px 3px 4px; - line-height: 1.3; - border-left: 1px solid #ffffff; -} -.entry_name_menu { - float: left; - height: 30px; - overflow: hidden; -} -.entry_name_menu > ul { - margin: 0; - padding: 0; -} -.entry_name_menu > ul li { - list-style-type: none; -} -.entry_name_menu p { - margin: 0; - display: inline-block; -} -.entry_name_menu li { - max-width: 800px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} -.entry_name_menu li:first-child { - float: left; - color: #4f677e; - margin-right: 10px; - font-size: 11px; - line-height: 1.4; -} -.entry_name_menu li:last-child { - float: left; -} -.entry_menu_list { - float: left; - width: 164px; - height: 30px; - overflow: hidden; -} -.entry_menu_list > ul { - margin: 0; - padding: 0; -} -.entry_menu_list > ul li { - list-style-type: none; -} -.entry_menu_list p { - margin: 0; - display: inline-block; -} -.entry_menu_list li { - width: 100%; - display: block; - clear: both; - white-space: nowrap; -} -.entry_menu_list li span { - display: inline-block; - vertical-align: top; -} -.entry_menu_list li span:first-child { - min-width: 45px; - max-width: 92px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - float: left; - margin-right: 10px; - color: #4f677e; - font-size: 11px; -} -.entry_menu_list li span:last-child { - float: left; - color: #374858; -} -.entry_menus { - height: 100%; - float: right; - position: relative; -} -.entry_menus > ul { - margin: 0; - padding: 0; -} -.entry_menus > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.entry_menus > ul { - height: 100%; -} -.entry_menus > ul > li { - width: 200px; - border-right: solid 1px white; - padding: 2px 4px 3px 4px; - height: 33px; - line-height: 1.3; - background: #cdd7e0; - position: relative; -} -.entry_menus > ul > li:first-child { - border-left: solid 1px white; -} -.entry_menus > ul > li:last-child { - border-right: none; - width: 90px; -} -.entry_menu_more { - min-height: 33px; - height: auto !important; - overflow: visible; - border-bottom: solid 1px #ffffff; - border-left: solid 1px #ffffff; - -webkit-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - -moz-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - z-index: 10; -} -.entry_menu_more .entry_menu_options span:last-child { - position: absolute; - bottom: 6px; -} -.show_list_more { - height: auto; -} -.readOnly .drop_edit_menu { - display: none; -} -.entry_menu_less { - /* overflow: hidden; */ -} -.entry_menu_show { - overflow: visible; -} -.entry_menu_edit .entry_dropdown { - display: block; -} -.entry_menu_options { - float: right; - margin-left: 10px; - padding-left: 4px; - height: 100%; - width: 15px; -} -.entry_menu_options > span { - display: block; - margin-right: 0; - cursor: pointer; -} -.entry_menu_options .arrow_menu_dn-img { - height: 10px !important; - margin-top: 7px; -} -.entry_options { - padding-top: 5px; - float: right; -} -.entry_options > ul { - margin: 0; - padding: 0; -} -.entry_options > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.entry_options > ul > li { - margin-left: 6px; -} -.entry_options > span { - cursor: pointer; -} -.epb_comments_count { - color: #ffffff; - width: 17px; - display: block; - text-align: center; - margin-top: 1px; - font-size: 9px; - height: 12px; - line-height: 12px; -} -@-moz-document url-prefix() { - .epb_comments_count { - line-height: 11px; - } -} -.entry_toolbar { - height: 25px; - margin-left: 31px; - position: relative; - padding: 5px; - background: #cdd7e0; - border-top: solid 1px white; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); -} -.entry_toolbar > ul { - margin: 0; - padding: 0; -} -.entry_toolbar > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.entry_toolbar > ul > li { - margin-right: 12px; - cursor: pointer; -} -.entry_toolbar > ul > li:first-child { - margin-left: 6px; -} -.entry_toolbar_btns { - /*display: none;*/ -} -.entry_content { - min-height: 300px; - background: #f9fafb; - border: solid 1px #cad4de; -} -.entry_footer { - margin-left: 30px; - height: 25px; - background: #cad4de; -} -.tag { - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.entry_tags { - float: left; - height: 100%; - overflow: hidden; - max-width: 138px; -} -.entry_tags > span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; - float: left; - line-height: 1; - padding: 0px 3px; - border: solid 1px #aabbca; - margin-right: 2px; -} -.entry_dropdown { - width: 101%; - min-width: 260px; - height: auto; - padding: 10px; - background: #cdd7e0; - border-left: solid 1px white; - border-right: solid 1px white; - border-bottom: solid 1px white; - position: absolute; - top: 0; - right: -1px; - z-index: 14; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - display: none; -} -.entry_dropdown > ul { - margin: 0; - padding: 0; -} -.entry_dropdown > ul li { - list-style-type: none; -} -.entry_dropdown input { - border: none; - height: 28px; - font-size: 12px; - padding-left: 6px; - width: 100%; - color: #4b6277; -} -.entry_dropdown label { - font-size: 11px; - display: block; - margin-bottom: 4px; -} -.entry_dropdown > nav { - width: 100%; - height: 18px; -} -.entry_name { - right: auto !important; - left: -1px !important; -} -.entry_name select { - width: 60%; -} -.entry_name > ul > li { - margin: 4px 0 12px 0; -} -.entry_name > ul > li:first-child { - margin-top: -8px; -} -.project_tree { - width: 100%; - height: 140px; - overflow: auto; - background: white; -} -.close_entry_menu { - height: 18px; - width: 100%; - margin-top: -5px; -} -.close_entry_menu span { - float: right; -} -.save_entry_menu { - height: 20px; - float: right; - margin-top: 10px; -} -.save_entry_menu .grey_link { - display: block; - float: left; - padding: 4px 20px 0 0; -} -.select_entry_menu { - width: 100%; - height: 25px; - float: left; - margin-top: 20px; -} -.select_entry_menu span, -.select_entry_menu button { - float: left; - margin-right: 15px; -} -.select_entry_menu .blue_link { - color: #3b97ed; -} -.entry_tag_index li:hover { - background: #d9e1e8; -} -.entry_tag_index li.index_selected { - background: #e6ebef; -} -.entry_tag_index li.index_selected:hover { - background: #e6ebef; -} -.entry_tags_input { - margin: 0; - background: white; - border: none; -} -.entry_dates { - width: 100%; -} -.entry_dates > li { - display: block; - width: 100%; - clear: both; - overflow: auto; - margin-bottom: 15px; -} -.entry_dates > li > span { - margin: 5px 0 0 6px; - cursor: pointer; -} -.entry_dates > li > span:active { - margin: 6px 0 0 6px; -} -.entry_dates input { - height: 25px; - background: #e9edf1; -} -.entry_dates input:focus { - background: white; -} -.entry_dates > li:last-child { - margin-bottom: 5px; -} -.entry_dates > li:last-child input { - background: white; -} -.entry_dates > li:first-child { - margin-bottom: 0; -} -.drag_handle { - background: #d9e1e8; - width: 9px; - height: 25px; - padding: 5px 3px; - float: left; - cursor: move; -} -.drag_handle span { - width: 3px; - height: 3px; - display: block; - background: #bac7d4; - margin: 1px 0 2px 0; -} -.date_key { - width: 120px; - float: left; - margin-right: 10px; - position: relative; -} -.date_key:after { - content: ":"; - position: absolute; - left: 123px; - top: 4px; - font-size: 12px; - font-weight: bold; -} -.date_value { - width: 80px; - float: left; - position: relative; -} -.entry_settings { - width: 150px; - background: white; - line-height: 1.0; - position: absolute !important; - top: 24px; - right: -13px; - z-index: 30; - display: none; - margin-right: 0 !important; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.8); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.8); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.8); -} -.entry_settings > ul { - margin: 0; - padding: 0; -} -.entry_settings > ul li { - list-style-type: none; -} -.entry_settings .trash_dark-img { - right: 4px; -} -.entry_settings ul { - padding: 10px 0 10px 0; -} -.entry_settings li { - font-size: 12px; - padding: 8px 10px; - display: block; - cursor: pointer; -} -.entry_settings li:hover { - background: #e0e6eb; -} -.entry_settings_arrow { - position: relative; - background: #f9fafb; -} -.entry_settings_arrow:after { - top: -11px; - right: 19px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-bottom-color: #f9fafb; - border-width: 7px; - margin-left: -3px; -} -.epb_content_wrap { - display: table; - min-width: 696px; - margin-left: 30px; - margin-right: 45px; - min-height: 100px; - background: #f3f5f7; - border: solid 1px #aabbca; -} -.handsontable th { - background: #d9e1e8; - font-size: 12px; - color: #4b6277; -} -.handsontable th, -.handsontable td { - border-right: 1px solid #cad4de; - border-bottom: 1px solid #cad4de; -} -.handsontable tr:first-child th, -.handsontable tr:first-child td { - border-top: 1px solid #cad4de; -} -.handsontable th:first-child, -.handsontable td:first-child, -.handsontable .htNoFrame + th, -.handsontable .htNoFrame + td { - border-left: 1px solid #cad4de; -} -div.dd_entry_cell { - border: 1px solid #d9e1e8; - -webkit-transition: border 0.2s ease; - -moz-transition: border 0.2s ease; - -o-transition: border 0.2s ease; - transition: border 0.2s ease; -} -div.dd_entry_cell:hover { - border: 1px solid #3babe9; -} -div.dd_entry_cell:hover .button_wrapper { - display: block; -} -#button_add_entry.drop_active, -.drop_active { - background-color: #d8f1ff; -} -#button_add_entry.drop_hover, -.drop_hover { - background: #69bfee; -} -.settings_button span { - margin-top: 10px; - display: block; -} -.edit_button span { - margin: 5px 0 0 12px; -} -.drag_button span { - margin: 3px 0 0 10px; -} -.drag_button:active { - -webkit-box-shadow: inset 0 0 0 rgba(55, 72, 88, 0) !important; - -moz-box-shadow: inset 0 0 0 rgba(55, 72, 88, 0) !important; - box-shadow: inset 0 0 0 rgba(55, 72, 88, 0) !important; -} -.cancel_button span { - margin: 5px 0 0 12px; -} -.save_button span { - margin: 2px 0 0 10px; -} -.button_wrapper { - position: absolute; - right: -1px; - top: -1px; - display: none; - border: solid 1px #cad4de; - z-index: 8; - -webkit-box-shadow: -2px 1px 1px rgba(55, 72, 88, 0.1) !important; - -moz-box-shadow: -2px 1px 1px rgba(55, 72, 88, 0.1) !important; - box-shadow: -2px 1px 1px rgba(55, 72, 88, 0.1) !important; -} -.button_wrapper .more_options_panel { - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4) !important; - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4) !important; - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4) !important; - border: 0; -} -.button_wrapper .more_options_item { - min-width: 140px; -} -.more_options_panel.in_block { - right: -1px; - top: 36px; - padding: 10px 0 10px 0; - background-color: #e6ebef; -} -.more_options_item_remove_block_element span { - float: left; -} -.more_options_item { - padding: 6px; -} -.more_options_item:hover { - background: #f9fafb; -} -/********* -* tables * -**********/ -.htContextMenu table.htCore { - outline: 1px solid #d9e1e8; - line-height: 1.0; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4); -} -.htContextMenu table tbody tr td { - font-size: 12px; - color: #4b6277; - background: #e9edf1; -} -.htContextMenu table tbody tr td:hover { - background: #f9fafb; -} -.htContextMenu table tbody tr td.current { - background: #f9fafb; -} -.htContextMenu table tbody tr td.htSeparator { - border-top: 1px solid #cad4de; -} -/**************** -* media queries * -****************/ -@media (max-height: 750px) { - .filter_dropdown { - max-height: 460px; - } -} -@media (max-width: 1750px) { - .entry_name_menu li { - max-width: 400px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } -} -@media (max-width: 1380px) { - .entry_name_menu li { - max-width: 190px; - } - .entry_menus > ul > li { - width: 174px; - } - .entry_menu_list { - width: 138px; - } - .entry_menu_list li span { - font-size: 11px; - } - .entry_menu_list li span:first-child { - margin: 0; - } -} -@media (max-width: 1100px) { - .author_name { - width: auto; - margin-right: 20px; - } - .author_firstname, - .author_lastname { - width: 100px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } -} -@media (max-width: 970px) { - .page_title { - margin-top: 2px; - font-size: 12px; - } - .plus_btn_wrap { - width: 130px; - } - .author_firstname, - .author_lastname { - width: 66px; - } - .entry_menus > ul > li { - width: 120px; - } - .entry_menu_list { - width: 84px; - } - .entry_menu_list li span:first-child { - display: block; - float: none; - } - .entry_tags { - width: 84px; - } - .entry_tags > span { - max-width: 84px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} -@media (max-width: 870px) { - .entry_name_menu li { - max-width: 90px; - } -} - - - -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -/********* -* icons * -**********/ -.icon_source { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; -} -.logo-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -6px -10px; - width: 130px; - height: 30px; - margin: 16px 0 0 22px; -} -.author_only-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -140px -3px; - width: 15px; - height: 15px; -} -.add_text-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -161px -3px; - width: 22px; - height: 15px; -} -.add_text-img:hover { - background-position: -161px -31px; -} -.add_text-img:active { - margin-top: 1px; -} -.add_sketch-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -190px -3px; - width: 22px; - height: 15px; -} -.add_sketch-img:hover { - background-position: -190px -31px; -} -.add_sketch-img:active { - margin-top: 1px; -} -.add_table-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -218px -3px; - width: 23px; - height: 15px; -} -.add_table-img:hover { - background-position: -218px -31px; -} -.add_table-img:active { - margin-top: 1px; -} -.add_upload-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -942px -3px; - width: 18px; - height: 15px; -} -.add_upload-img:hover { - background-position: -942px -31px; -} -.add_upload-img:active { - margin-top: 1px; -} -.add_import-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -246px -3px; - width: 23px; - height: 15px; -} -.add_import-img:hover { - background-position: -246px -31px; -} -.add_import-img:active { - margin-top: 1px; -} -.wheel-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -282px -3px; - width: 15px; - height: 15px; -} -.wheel-img:hover { - background-position: -282px -31px; -} -.arrow_down-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -303px -3px; - width: 15px; - height: 15px; - cursor: pointer; -} -.arrow_down-img:hover { - background-position: -303px -31px; -} -.arrow_up-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -327px -3px; - width: 15px; - height: 15px; - cursor: pointer; -} -.arrow_up-img:hover { - background-position: -327px -31px; -} -.comment-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -348px -3px; - width: 19px; - height: 19px; -} -.comment-img:hover { - background-position: -348px -31px; -} -.todo-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1085px -4px; - width: 14px; - height: 13px; -} -.project-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -375px -3px; - width: 16px; - height: 16px; - margin-top: 6px !important; -} -/* .project-img:hover{ */ -/* background-position: -375px -31px; */ -/* } */ -.manage-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -400px -2px; - width: 20px; - height: 20px; -} -.manage_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1050px -35px; - width: 10px; - height: 10px; - margin-top: 2px; -} -.desk-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -428px -3px; - width: 16px; - height: 16px; - margin-top: 6px !important; -} -.desk_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1067px -35px; - width: 10px; - height: 10px; - margin-top: 3px; -} -.template_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -796px -3px; - width: 10px; - height: 16px; -} -.bell-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -454px -1px; - width: 22px; - height: 22px; -} -.bell-img:hover { - background-position: -454px -29px; -} -.search-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -488px -1px; - width: 26px; - height: 23px; -} -.search-img:hover { - background-position: -488px -29px; -} -.avatar-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -522px 1px; - width: 16px; - height: 22px; -} -.avatar_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -837px -37px; - width: 8px; - height: 10px; - margin-top: 4px; -} -.group-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -853px -35px; - width: 20px; - height: 13px; - margin-top: 3px; -} -.arrow_down_s-img { - position: relative; - background: transparent; -} -.arrow_down_s-img:after { - top: 100%; - left: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(213, 213, 213, 0); - border-top-color: #374858; - border-width: 4px; - margin-left: -4px; -} -.arrow_down_s-img:hover { - background-position: -691px -39px; -} -.close_x-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -895px -8px; - width: 10px; - height: 9px; -} -.feedback-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -912px -2px; - width: 10px; - height: 61px; -} -.invite-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -925px -2px; - width: 10px; - height: 52px; -} -.pending-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1011px -9px; - width: 17px; - height: 10px; -} -.single_tag_img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -970px -5px; - width: 12px; - height: 14px; -} -.root_tag_img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -986px -4px; - width: 19px; - height: 15px; -} -.menu_arrow-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -853px -7px; - width: 14px; - height: 11px; -} -.folder_up-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -738px -3px; - width: 24px; - height: 15px; -} -.folder_dn-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -764px -5px; - width: 24px; - height: 13px; -} -.project_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -814px -5px; - width: 12px; - height: 14px; -} -.notebook_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1035px -34px; - width: 10px; - height: 12px; - margin-top: 2px; -} -.edit-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -659px -7px; - width: 11px; - height: 10px; -} -.trash_dark-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -631px -5px; - width: 10px; - height: 13px; -} -.trash-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -646px -4px; - width: 10px; - height: 13px; -} -.trash-img:hover { - background-position: -631px -4px; -} -.edit_light-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -674px -7px; - width: 11px; - height: 10px; -} -.edit_light-img:hover { - background-position: -659px -7px; -} -.edit_light-img:active { - margin-top: 1px; - margin-bottom: -1px; -} -.arrow_menu_dn-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -729px -11px; - width: 9px; - height: 5px; -} -.arrow_menu_dn-img:hover { - background-position: -729px -39px; -} -.arrow_menu_up-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -716px -11px; - width: 9px; - height: 5px; -} -.arrow_menu_up-img:hover { - background-position: -716px -39px; -} -.close_box-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - float: right; - margin: 0; - background-position: -546px -5px; - width: 17px; - height: 15px; - cursor: pointer; -} -.close_box-img:hover { - background-position: -546px -33px; -} -.close_box-img:active { - -webkit-box-shadow: 0 0 5px #ffffff; - -moz-box-shadow: 0 0 5px #ffffff; - box-shadow: 0 0 5px #ffffff; - background-position: -546px -5px; -} -.save-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - margin: 0; - background-position: -585px -5px; - width: 15px; - height: 15px; - cursor: pointer; -} -.drag-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - margin: 0; - background-position: -608px -5px; - width: 15px; - height: 15px; - cursor: pointer; -} -.close_dark_x-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -569px -8px; - width: 10px; - height: 9px; -} -.edit_dark-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -659px -7px; - width: 11px; - height: 10px; -} - -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.signing_statement { - margin-bottom: 10px; -} -.signing_method { - margin: 0; - padding: 0; -} -.signpad_canvas { - width: 100%; - height: 150px; - border: 1px solid black; - background-color: #ffffff; -} -#signing_clear_button { - font-size: 12px; - cursor: pointer; -} -.signing_method_container { - display: block; - border: 1px solid #d2d2d2; - margin-bottom: 10px; - transition: background-color 0.3s ease; -} -.signing_method_container.selected { - background: #ededed; -} -.signing_content_title { - line-height: 26px; - padding: 10px; -} -.signing_method_description { - display: block; -} -.signing_method_container .signing_content_body { - padding: 0 10px; -} -.selected .signing_content_body { - padding: 0 10px 10px 10px; -} -.signing_toggle { - cursor: pointer; -} -.signing_label { - display: inline-block; - margin-right: 50px; -} -.signing_method_container .triangle { - display: inline-block; - font-size: 10px; - margin: 10px 10px 0 0; -} -/* .signing_method_container .icon-triangle_down { */ -/* margin-top: 10px; */ -/* } */ - -/****************************** - TASK LIST VIEW -*******************************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.eln_main_content_box.tasks { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - height: auto; - min-height: 400px; - margin: 0 25px 0 0; -} -#tasks_header { - background: #EEE; - border-bottom: 1px solid #D6D4D5; - border-radius: 10px 10px 0 0; - display: block; - font-size: 14px; - height: 35px; - padding: 10px 0px 5px 15px; -} -#task_filter_status.hidden { - display: none; -} -#task_filter_status .checkbox_filled_bg:hover { - background: none; -} -#task_content { - max-width: 1300px; - padding-left: 10px; - display: block; - line-height: 18px; - position: relative; - overflow: auto; -} -.task_empty_folder { - display: none; - padding: 50px; - text-align: center; - font-size: 12px; -} -.task_list { - font-size: 14px; -} -.task_list table { - border-collapse: collapse; - outline: none; - table-layout: fixed; - width: 100%; -} -.task_list table tr td:last-child { - font-size: 11px; -} -.column_task_name { - min-width: 100px; - width: 25%; -} -.column_task_delete { - width: 30px; -} -.column_task_date { - width: 89px; -} -.task_list_line { - font-size: 12px; - border-bottom: 1px solid #bac7d4; - cursor: pointer; - height: 34px; - line-height: 1.2; - white-space: nowrap; -} -.task_list_line:last-child { - border: none; -} -.task_list_line:hover { - background: #ecf0f3; -} -.task_list_line:hover .task_line_delete { - display: block; -} -.task_list_line:first-child { - cursor: auto; -} -.task_list_line:first-child:hover { - background: none; -} -.unread_task { - background: #EEF; -} -.task_line_name { - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: bottom; - overflow: hidden; - padding-left: 4px; -} -.task_line_text { - overflow: hidden; - text-overflow: ellipsis; -} -.task_line_content { - color: #AAA; -} -.task_line_delete { - display: none; - text-align: center; -} -.task_line_delete:hover { - color: #4bb1d7; -} -.task_line_date { - padding-right: 10px; - text-align: right; -} -.task_checkbox_wrap { - position: relative; - float: left; - display: block; - font-size: 12px; -} -/****************************** - TASK DIALOG VIEW -*******************************/ -.task_select_left { - float: left; -} -.task_select { - border: 0; - outline: 0; - background: #FFF; - cursor: pointer; - margin-right: 10px; - padding: 4px 4px 4px 8px; - color: #5e7b97; -} -.task_options { - height: 45px; -} -.task_set_option { - display: inline-block; - margin: 5px 15px 0 15px; -} -#choose_asignee, -#choose_status, -#status_created { - display: none; -} -#dialog_task_form .input_block { - margin: 0; - padding-bottom: 20px; - overflow: auto; - height: auto; -} -#dialog_task_form .task_recipient_label { - display: inline-block; - vertical-align: top; - width: 20px; - padding: 5px 0 0 0; - margin-bottom: 5px; -} -.task_info_label { - margin-left: 16px; - margin-bottom: 6px; -} -.task_content_bg { - background: white; - padding: 0 10px 10px 10px; -} -#dialog_task_form .task_recipient_field { - cursor: text; - display: inline-block; - min-height: 33px; - width: 700px; -} -#dialog_task_form .add_task_recipient { - cursor: pointer; - display: inline-block; - margin-bottom: 5px; - padding: 5px 0 0 0; - vertical-align: top; -} -#dialog_task_form .add_task_recipient.disabled { - cursor: default; - color: #AAA; -} -#taskRecipientIds, -#taskRecipientEmails { - display: none; -} -#dialog_task_form .task_recipient textarea, -#task_recipient_width { - border: 1px solid transparent; - display: inline-block; - font-size: 14px; - color: #374858; - height: 14px; - margin: 0 5px 5px 0; - outline: none; - padding: 5px; - resize: none; - vertical-align: bottom; - overflow: hidden; -} -#task_recipient_width { - display: none; -} -#dialog_task_form .task_message_content { - max-height: 450px; - height: auto; - overflow: auto; -} -.task_message_text { - margin: 10px 0 0 15px; -} -#dialog_task_form .task_message_content textarea { - font-size: 14px; - height: 200px; - margin: 0; - resize: none; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -#dialog_task_form .placeholder_frame { - float: none; - width: 100%; -} -.task_recipient_tree { - display: none; - position: relative; - box-shadow: 0px 0px 10px #AAA; - box-sizing: border-box; - max-height: 150px; - overflow: auto; - padding: 0 10px; -} -.task_recipient_tree a { - color: #374858; - line-height: 25px; - text-decoration: none; -} -.task_recipient_tree div.group_treeline_children { - padding-left: 15px; - margin-left: 0px; - box-sizing: border-box; -} -.task_recipient { - line-height: 24px; -} -.task_recipient:last-child:after { - content: ""; -} -/****************************** - TASK FILTERING -*******************************/ -.task_filter { - list-style-type: none; - overflow: auto; - margin: 0; - padding: 6px 0 0 10px; -} -.task_filter > li { - float: left; - padding-left: 6px; - padding-right: 6px; -} -.task_filter label { - vertical-align: middle; - bottom: 3px; - position: relative; - margin-left: 2px; -} -.CLOSED, -.not_assigned, -.assigned { - display: none; -} - -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.treeInPopup .treeline { - background-repeat: no-repeat; - color: #374858; - cursor: pointer; - border: 1px solid transparent; - display: block; - font-size: 14px; - height: 21px; - line-height: 22px; - outline: none; - padding-left: 5px; - text-decoration: none; -} -/* .treeline:hover{ */ -/* background-position: 0 0; */ -/* border: 1px solid #69bfee; */ -/* text-decoration: none; */ -/* } */ -.treeline:hover .icon-arrow_down, -.treeline:hover .icon-arrow_right, -.treeline:hover .icon-folder, -.treeline:hover .icon-notebook, -.treeline:hover .icon-template, -.treeline:hover .name, -.treeline:hover .updateTS { - /* color: #69bfee; */ -} -.treeline.active { - background-color: #ededed; -} -.treeInPopup .treeline.active { - background-color: transparent; -} -.treeline.is_hidden_item .icon-arrow_down, -.treeline.is_hidden_item .icon-arrow_right, -.treeline.is_hidden_item .icon-folder, -.treeline.is_hidden_item .icon-notebook, -.treeline.is_hidden_item .icon-template, -.treeline.is_hidden_item .name, -.treeline.is_hidden_item .updateTS, -.treeline.is_hidden_item:hover .icon-arrow_down, -.treeline.is_hidden_item:hover .icon-arrow_right, -.treeline.is_hidden_item:hover .icon-folder, -.treeline.is_hidden_item:hover .icon-notebook, -.treeline.is_hidden_item:hover .icon-template, -.treeline.is_hidden_item:hover .name, -.treeline.is_hidden_item:hover .updateTS { - color: #CCC; -} -.treeline img { - vertical-align: top; -} -.treeline .icon-arrow_right { - font-size: 33px; - margin-right: -10px; - margin-left: -3px; - vertical-align: -4px; -} -.treeInPopup .icon-arrow_right { - font-size: 23px; - margin-right: -6px; - line-height: 14px; - margin-left: -3px; -} -.treeline span { - /* float: left; */ - margin-right: 5px; -} -.treeline .icon-template { - float: left; -} -.treeline .name { - overflow: hidden; - margin-left: 5px; -} -.treeInPopup .name { - font-size: 12px; - overflow: hidden; -} -.treeline .updateTS { - font-size: 15px; - float: right; - margin-right: 15px; -} -.treeline .tree_button { - float: right; - display: none; - margin-top: 0; - margin-right: 10px; -} -.droppable_folder { - background-color: #e4eef7 !important; -} -.hover_droppable_folder { - background-color: #d0e1f1 !important; -} -.treeline:hover .tree_button { - display: inline; -} -.treeline.active .tree_button { - display: inline; -} -.treeline_children { - display: none; - margin-left: 30px; -} -.treeInPopup .treeline_children { - margin-left: 20px; -} -.treeline_children_empty { - font-size: 15px; - font-style: italic; - padding: 10px 0 10px 30px; -} -.treeInPopup .treeline_children_empty { - font-size: 12px; - font-style: italic; - padding: 0 0 0 25px; -} -.treeInPopupContainer { - display: none; - background: white; - box-sizing: border-box; - max-height: 150px; - margin-top: 10px; - overflow-y: auto; - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); -} -.treeInPopupContainer img { - display: block; - margin: auto; -} -.treeInPopup { - overflow-y: auto; - height: 148px; - padding-top: 10px; - margin-top: 2px; -} -.treeInPopup .treeline.selected { - background-color: #e6ebef; -} -.tree_my_eln_projects, -.tree_my_eln_templates { - max-width: 900px; -} -.tree_my_eln_projects .folder_dn-img, -.tree_my_eln_templates .folder_dn-img, -.tree_my_eln_projects .project_s-img, -.tree_my_eln_templates .project_s-img { - margin-top: 2px; -} -.treeline { - color: #4b6277; - background-repeat: no-repeat; - cursor: pointer; - border: 1px solid transparent; - display: block; - font-size: 14px; - height: 26px; - line-height: 20px; - outline: none; - padding: 2px 8px 2px 4px; - text-decoration: none; - transition: background 0.1s ease; -} -.treeline:hover { - background: #e0e6eb; - text-decoration: none; -} -.treeline .updateTS { - font-size: 13px; - float: right; - margin-right: 15px; -} -.treeline .tree_button { - float: right; - display: none; - margin: 0 10px; -} -.treeline .tree_button button { - padding: 3px; - background: transparent; - cursor: pointer; -} -.treeline .name { - white-space: nowrap; - text-overflow: ellipsis; - display: block; - overflow: hidden; - padding: 0; - margin-left: 0; - line-height: 1.5; - float: left; -} -.treeline .icon-template { - margin-top: 3px; -} -.more_options_panel { - position: absolute; - right: 10px; - z-index: 10; - display: none; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - border: solid 1px #bac7d4; -} -.more_options_panel > ul { - margin: 0; - padding: 0; -} -.more_options_panel > ul li { - list-style-type: none; -} -.more_options_panel .more_options_item { - min-width: 140px; - font-size: 12px; - padding-left: 5px; - cursor: pointer; -} -.more_options_panel .menu_arrow-img { - position: absolute; - top: -11px; - left: 60px; -} -.more_options_panel > ul > li { - padding: 2px 7px 2px 6px; - display: block; - text-align: left; - cursor: pointer; - line-height: 20px; - position: relative; -} -.more_options_panel > ul > li:hover { - background: #ecf0f3; -} -.more_options_panel > ul > li > span { - right: 0; - top: 3px; - position: absolute; -} -.more_options_panel > ul li:first-child { - margin-top: 8px; -} -.more_options_panel.in_tree { - top: 23px; -} -.group_more_options { - width: 200px; -} - -/****************************** - WITNESS COLLECTION -*******************************/ -.eln_main_content_box.witness { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - height: 95%; - margin: 0 25px 0 0; -} -#witness_header { - background: #EEE; - border-bottom: 1px solid #D6D4D5; - border-radius: 10px 10px 0 0; - display: block; - font-size: 14px; - height: 35px; - padding: 10px 0px 5px 15px; -} -#witness_content { - display: block; - line-height: 18px; - position: absolute; - overflow: auto; - padding: 10px; - top: 50px; - left: 0; - right: 0; - bottom: 0px; -} -.witness_empty_folder { - padding: 50px; - text-align: center; - font-size: 12px; -} -.witness_list { - font-size: 14px; -} -.witness_list table { - border-collapse: collapse; - outline: none; - table-layout: fixed; - width: 100%; -} -.witness_list table tr td:last-child { - font-size: 11px; -} -.witness_list_line { - border-bottom: 1px solid #DDD; - cursor: pointer; - height: 40px; - line-height: 40px; - white-space: nowrap; -} -.witness_list_line:hover { - background: #EEE; -} -.witness_list_line:first-child:hover { - background: none; - cursor: default; -} -.witness_line_name { - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: bottom; - overflow: hidden; - padding-left: 10px; -} -.witness_line_text { - overflow: hidden; - text-overflow: ellipsis; -} -.column_witness_name { - min-width: 100px; - width: 25%; -} -.column_witness_project { - min-width: 100px; - width: 60%; -} -.column_witness_date { - width: 106px; -} - diff --git a/unittests/example_labfolder_data/static/css/data-elements.css b/unittests/example_labfolder_data/static/css/data-elements.css deleted file mode 100644 index 5d451615..00000000 --- a/unittests/example_labfolder_data/static/css/data-elements.css +++ /dev/null @@ -1,104 +0,0 @@ -.data-elements { - display: block; - font-family: 'Open Sans', Helvetica, Arial, sans-serif; -} -.notebook-element-content { - height: calc(100% - 10px); - background: #FFF; - padding: 1.25em 0 0.75em; -} -.notebook-element-content .data-element { - display: block; - -webkit-touch-callout: none; - /* iOS Safari */ - -webkit-user-select: none; - /* Chrome/Safari/Opera */ - -khtml-user-select: none; - /* Konqueror */ - -moz-user-select: none; - /* Firefox */ - -ms-user-select: none; - /* Internet Explorer/Edge */ - user-select: none; - /* Non-prefixed version, currently not supported by any browser */ -} -/* Match element or class (class is used in compose mode) */ -.data-element-wrap { - margin-bottom: 0.75em; - margin-right: 1em; - display: flex; - align-items: baseline; - position: relative; -} -.data-element-wrap .data-element-icon { - width: 12px; - height: 12px; - margin: 0.65em; - margin-right: 0.75em; - margin-left: 1.15em; - fill: #9D9D9D; - flex-shrink: 0; -} -.data-element-wrap .data-element-display { - border: solid 1px #c0c0c0; - border-radius: 5px; - padding: 0.5em 0.75em; - overflow-wrap: break-word; - word-wrap: break-word; - -ms-word-break: break-all; - word-break: break-all; - word-break: break-word; -} -.data-element-wrap .data-element-display .empty-value { - color: #9D9D9D; - font-size: 1.75em; - line-height: 0.25em; -} -.data-element-wrap .data-element-display .element-title { - font-weight: bold; -} -.data-group-wrap .data-group-icon { - align-self: flex-start; -} -.data-group-wrap .data-group-content.display-mode { - /** - * Fix for nested flexbox sizing in IE11. See: - * https://github.com/philipwalton/flexbugs/issues/170 - * https://github.com/philipwalton/flexbugs/issues/71 - */ - min-width: 0%; - border: solid 1px #c0c0c0; - border-radius: 5px; - padding: 0.5em 0.75em 0; -} -.data-group-wrap .data-group-content.display-mode .data-element-display { - border: none; - padding: 0; -} -.data-group-wrap .data-group-content .data-group-header .element-title { - font-weight: bold; -} -.data-group-wrap .data-group-content .data-element-icon { - margin: 0; - margin-right: 0.75em; -} -.data-group-wrap .data-group-content .data-group-icon { - margin-top: 0.75em; -} -.descriptive-element-wrap { - align-items: baseline; -} -.descriptive-element-wrap .descriptive-element-display .element-title { - font-weight: bold; -} -.material-element-wrap { - align-items: flex-start; -} -.material-element-wrap .material-element-display .element-title { - color: #6cc0ec; - font-weight: bold; - word-wrap: break-word; -} -.material-element-wrap .material-element-display .element-title:hover { - color: #96dbff; -} diff --git a/unittests/example_labfolder_data/static/css/eln_layout.css b/unittests/example_labfolder_data/static/css/eln_layout.css deleted file mode 100644 index 97944ad5..00000000 --- a/unittests/example_labfolder_data/static/css/eln_layout.css +++ /dev/null @@ -1,3101 +0,0 @@ -/******************* -* eln_layout.css * -********************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -::selection { - background: #c5e6f8; -} -::-moz-selection { - background: #c5e6f8; -} -*, -*::before, -*::after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -a { - cursor: pointer; -} - -@font-face { - font-family: 'Oxygen'; - src: url('/static/font/Oxygen-Regular.ttf'); - font-weight: normal; - font-style: normal; -} -@font-face { - font-family: 'Oxygen Bold'; - src: url('/static/font/Oxygen-Bold.woff'); - font-weight: normal; - font-style: normal; -} -@font-face { - font-family: 'Source Sans Pro Light'; - src: url('/static/font/SourceSansPro-Light.ttf'); - font-weight: normal; - font-style: normal; -} -@font-face { - font-family: 'Source Sans Pro'; - src: url('/static/font/SourceSansPro-Regular.woff'); - font-weight: normal; - font-style: normal; -} -body { - font-size: 14px; - margin: 0; - padding: 0; - font-family: arial, sans-serif; - height: 100%; - width: 100%; -} -html { - height: 100%; -} -.body_bg { - background: #ffffff url(../img/squares.png); - height: 100%; - width: 100%; - position: fixed; - z-index: -1; - top: 33px; - left: -10px; -} -a { - text-decoration: none; - color: #1995d8; - outline: none; -} -a:hover { - text-decoration: none; -} -img { - border: 0; -} -button { - margin: 0; -} -button::-moz-focus-inner { - border: 0; -} -.clear { - clear: both; -} -.content_top_margin { - margin-top: 50px; -} -/****************************** - DEFAULT BLUE BUTTONS -*******************************/ -.default_button { - border: 1px solid #455a6e; - padding: 4px 8px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - color: white; - opacity: 1; - line-height: 1.2; - background: #304d69; - font-size: 14px; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - -o-transition: all 0.1s linear; - transition: all 0.1s linear; - -webkit-backface-visibility: hidden; - cursor: pointer; - /* background-color:#374858; */ - /* border:1px solid #ffffff; */ - /* border-radius:6px; */ - /* box-shadow:0px 0px 1px black; */ - /* -webkit-box-sizing: border-box; */ - /* -moz-box-sizing: border-box; */ - /* box-sizing: border-box; */ - /* color:#ffffff; */ - /* cursor:pointer; */ - /* display:inline-block; */ - /* float:left; */ - /* font-family:din-medi; */ - /* font-size:14px; */ - /* height:28px; */ - /* line-height:28px; */ - /* margin:0 1px 1px 0; */ - /* outline: none; */ - /* padding: 0 10px; */ - /* transition: background-color 0.2s ease, box-shadow 0.2s ease; */ -} -.default_button:hover, -.default_button:focus { - background: #375877; - -ms-filter: none; - filter: none; - outline: 0; - color: white; - text-decoration: none; -} -.default_button:active { - background: #304d69; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.5); - -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.5); - box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.5); -} -.default_button:hover { - /* background-color: #607D99; */ - /* text-decoration:none; */ -} -.default_button:active { - opacity: 1.0; - /* box-shadow:0px 0px 10px #888888; */ - /* text-decoration:none; */ -} -.default_button.disabled { - opacity: 0.5; - /* background-color:#DDD; */ - /* border:1px solid #FFF; */ - /* box-shadow:0px 0px 1px #AAA; */ - /* color:#AAA; */ - /* cursor:default; */ -} -/****************************** - DEFAULT FIELDS -*******************************/ -.default_textfield { - background-color: white; - border: 0; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - font-family: Arial; - color: #4b6277; - font-size: 14px; - line-height: 1.8; - font-style: normal; - font-variant: normal; - font-weight: normal; - margin: 0 5px 5px 0; - padding-left: 5px; - min-height: 30px; - transition: box-shadow ease 0.2s; -} -.textfield_on_white { - border: solid 1px #bac7d4; -} -.default_textfield:hover { - /* box-shadow: 0 0 3px #69bfee; */ -} -.default_textfield:focus { - /* border: 1px solid #69bfee; */ - /* box-shadow: 0 0 6px #69bfee; */ -} -/****************************** - DEFAULT SELECT -*******************************/ -.default_select { - background: #FFF; - border: 1px solid #d9e1e8; - color: #4b6277; - cursor: pointer; - margin: 0 0 0 10px; - padding: 4px 4px 4px 8px; -} -.dialog_wide_select { - margin: 0; - width: 100%; -} -/****************************** - DEFAULT PROFILE PICTURE -*******************************/ -img.default_profile_picture { - border: 1px solid #888; - height: 100px; - width: 100px; -} -img.default_profile_picture_small { - border: 1px solid #888; - height: 32px; - width: 32px; - margin-top: 3px; -} -/* ****************** */ -/* more_options START */ -/* ****************** */ -.more_options { - float: right; - position: relative; -} -.more_options_panel { - position: absolute; - right: 0; - z-index: 10; - display: none; - -webkit-box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 6px rgba(55, 72, 88, 0.3); - border: 1px solid #CDCDCD; - /* border-radius: 10px; */ - background-color: #FDFDFD; -} -.more_options_panel.in_project { - top: 38px; -} -.more_options_panel.in_block { - top: 40px; -} -.more_options_item { - font-size: 12px; - /* line-height: 40px; */ - padding-left: 12px; - padding-right: 12px; - cursor: pointer; - /* border-top: 1px solid #D6D4D5; */ - transition: background ease 0.2s; -} -.more_options_item:hover { - /* background: #ededed; */ - /* color: #69bfee; */ -} -.more_options_item:first-child { - /* border-radius: 10px 10px 0 0; */ - /* border: 0; */ -} -.more_options_item:last-child { - /* border-radius: 0 0 10px 10px; */ -} -.more_options_item span { - position: absolute; - right: 0; -} -div.zoom_bar { - width: 180px; - padding: 4px 14px !important; - height: 44px; - -webkit-user-select: none; - /* Chrome all / Safari all */ - -moz-user-select: none; - /* Firefox all */ - -ms-user-select: none; - /* IE 10+ */ -} -div.zoom_bar:hover { - background: #e6ebef; -} -div.zoom_bar:hover { - color: #374858; -} -/* **************** */ -/* more_options END */ -/* **************** */ -/* ****************** */ -/* gear_button START */ -/* ****************** */ -/* ************ */ -/* layout START */ -/* ************ */ -/* generic rules */ -.eln_row { - left: 0; - right: 0; - /* overflow:hidden; */ - position: absolute; -} -.eln_scroll-x { - overflow-x: auto; -} -.eln_scroll-y { - overflow-y: scroll; -} -/* specific rules */ -.eln_header.eln_row { - position: relative; - /* height:50px; */ - /* background: #FFF; */ - /* box-shadow:0 3px 10px #BBB; */ - min-width: 800px; -} -.eln_content.eln_row { - top: 70px; - bottom: 0; - margin-left: 200px; - min-width: 600px; -} -.eln_main_title.eln_row { - top: 70px; - margin-right: 40px; - margin-left: 100px; - min-width: 436px; - overflow: visible; -} -.eln_main_content.eln_row { - top: 86px; - bottom: 0; - margin-left: 49px; - min-width: 600px; -} -.eln_folder_title.eln_row { - top: 70px; - margin-left: 100px; - min-width: 600px; - overflow: visible; -} -.eln_folder_content.eln_row { - top: 86px; - bottom: 0; - margin-left: 49px; - min-width: 640px; -} -.eln_project_title.eln_row { - top: 70px; - margin-left: 100px; - min-width: 640px; - overflow: visible; -} -.eln_project_content.eln_row { - top: 86px; - bottom: 0; - /* margin-left:100px; */ - margin-left: 29px; - min-width: 600px; -} -.eln_main_content_box { - height: auto; - min-height: 400px; - margin: 0 25px 25px 0; - background-color: white; - border-bottom: solid 1px #cad4de; - border-left: solid 1px #cad4de; - border-right: solid 1px #cad4de; - position: relative; - padding: 20px 20px 20px 135px; - color: #4b6277; -} -.eln_main_content_box .header { - display: block; - font-size: 24px; - height: 35px; -} -.eln_main_content_box .header button { - margin-right: 10px; -} -.app_wrap { - position: relative; - background: #f3f5f7; - border: solid 1px #cad4de; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - height: calc(95% - 15px); -} -.app_content_wrap { - max-width: 900px; - padding: 10px; - display: block; - line-height: 18px; - position: absolute; - overflow: auto; - top: 10px; - left: 0; - right: 0; - bottom: 0px; -} -.app_header { - height: 29px; - background: #cad4de; - padding: 6px; -} -.app_header > h2 { - display: block; - float: left; - font-size: 14px; - margin: 0 13px 0 0; - color: #374858; -} -.app_header .filter_dn_wrap { - top: 23px; -} -.app_header .dropdown_button { - height: 20px; -} -.app_header .dropdown_button p { - margin: 0; - float: left; -} -.app_header .dropdown_button span { - height: 4px; - width: 12px; - display: block; - float: left; - margin: 2px 0 0 4px; -} -.app_plus_btn { - width: 35px; - height: 18px; - line-height: 1; - margin-right: 2px !important; - padding: 0; -} -.get_more_apps { - height: 100%; - padding: 20px; -} -/* ********** */ -/* layout END */ -/* ********** */ -/* ****************** */ -/* action links START */ -/* ****************** */ -.action_link_submit { - background: url(/static/img/design/action/submit.png) top right no-repeat; - width: 112px; - height: 25px; - display: block; -} -.action_link_submit:hover { - background-image: url(/static/img/design/action/submit_hover.png); -} -.action_link_signout { - background: url(/static/img/design/action/signout.png); - width: 83px; - height: 24px; - display: block; - float: right; - margin: 10px 0; -} -.action_link_signout:hover { - background: url(/static/img/design/action/signout_hover.png); -} -.action_link_profile { - background: url(/static/img/design/action/profile.png); - width: 71px; - height: 24px; - display: block; - float: right; - margin: 10px 0; -} -.action_link_profile:hover { - background: url(/static/img/design/action/profile_hover.png); -} -/* **************** */ -/* action links END */ -/* **************** */ -/* ************ */ -/* header START */ -/* ************ */ -/* LOGO */ -.eln_header_logo { - float: left; - padding-top: 7px; - padding-left: 17px; -} -/* Storage icon */ -#eln_header_storage_button { - background: none repeat scroll 0 0 transparent; - border: none; - cursor: pointer; - float: right; - font-size: 14px; - margin-top: 5px; - padding: 0; - height: 27px; - width: 32px; -} -#eln_header_storage_button span { - font-size: 10px; - margin-top: 14px; - position: absolute; - text-align: center; - width: 32px; - z-index: 6; -} -#eln_header_storage_stored { - background-color: #ededed; - height: 32px; - width: 32px; -} -#eln_header_storage_mask { - position: absolute; - z-index: 5; -} -#eln_header_storage_fill { - background-color: #BDCA70; - bottom: -5px; - position: absolute; - width: 32px; - z-index: 2; -} -/* Storage drop down panel */ -#eln_header_storage_panel { - background-color: #FFFFFF; - border: 3px solid #DDDDDD; - top: 53px; - z-index: 7; -} -#eln_header_storage_info { - cursor: default; -} -#eln_header_storage_info:hover { - color: #374858; -} -#eln_header_storage_info span { - font-size: 14px; - padding-right: 10px; - text-align: right; - width: 80px; -} -/* Storage percent bar */ -#eln_header_storage_bar_container { - float: right; - padding: 12px 10px 0; -} -#eln_header_storage_bar { - border: 1px solid #888; - height: auto; - line-height: 15px; - padding: 2px; - position: relative; - width: 80px; -} -span#eln_header_storage_bar_percent { - font-size: 12px; - line-height: 12px; - padding: 0; - position: absolute; - text-align: center; - width: 80px; -} -#eln_header_storage_bar_fill { - background-color: #bdca70; - height: 10px; -} -#eln_header_name { - display: inline-block; - line-height: 40px; - text-align: center; - text-overflow: ellipsis; - overflow: hidden; - padding: 0 5px; - vertical-align: top; - white-space: nowrap; -} -#eln_header_name div { - display: inline; -} -#eln_header_actions { - margin-right: 43px; -} -#eln_header_actions_button { - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - background: none repeat scroll 0 0 transparent; - border: none; - cursor: pointer; - float: right; - font-size: 14px; - height: 50px; - margin: 0; - padding: 5px; -} -#eln_header_storage_button:hover, -#eln_header_actions_button:hover { - cursor: pointer; - background: #ededed; - border: none; - border-radius: 0; -} -#eln_header_storage_button:active { - margin: 5px 1px 0px 0px; -} -div#eln_header_actions_button.active { - background: #ededed; - border: none; - border-radius: 0; - margin: 0; -} -#eln_header_arrow span { - font-size: 18px; -} -#eln_header_arrow { - display: inline-block; - margin-top: 8px; - padding-left: 5px; - vertical-align: top; -} -#eln_header_actions_panel { - background-color: #FFFFFF; - position: absolute; - top: 53px; - z-index: 7; -} -.eln_header_actions_item { - border-top: 1px solid #D6D4D5; - cursor: pointer; - font-size: 14px; - line-height: 40px; - padding: 0 20px; -} -.eln_header_actions_item:first-child { - border-top: 0; -} -.eln_header_actions_item span { - float: right; - font-size: 18px; - line-height: 18px; - padding-top: 12px; - text-align: center; - width: 36px; -} -.eln_header_actions_item:hover { - background: #ededed; - color: #69bfee; -} -.colorbar { - height: 4px; - background: url(/static/img/design/colorbar.png); -} -/* ************ */ -/* header END */ -/* ************ */ -/* **************** */ -/* navigation START */ -/* **************** */ -#eln_navigation { - position: fixed; - top: 70px; - width: 75px; - border-radius: 0 10px 0 0; - box-shadow: 0 3px 10px #888; - background: #FFF; - bottom: 0; - left: 0; - z-index: 2; - text-align: center; -} -#eln_navigation a { - border-bottom: 1px solid #d6d4d5; - display: block; - text-decoration: none; - padding: 10px 0; - font-size: 12px; - color: #374858; - transition: all ease 0.2s; -} -#eln_navigation a:hover { - background: #ededed; - color: #69bfee; -} -#eln_navigation a:first-child { - border-radius: 0 10px 0 0; -} -#eln_navigation span { - display: block; - font-size: 24px; - margin-bottom: 3px; -} -#eln_navigation span.icon-group { - font-size: 20px; - margin-left: 9px; -} -#eln_navigation span.icon-inventory { - margin-left: 4px; -} -#eln_navigation span.icon-template { - margin-left: 5px; -} -#eln_navigation .highlight { - color: #69bfee; -} -#eln_navigation .disabled, -#eln_navigation .disabled:hover { - color: #ccc; -} -#eln_navigation button { - border: 5px solid white; - border-radius: 10px; - color: #FFF; - cursor: pointer; - font-size: 11px; - outline: none; - width: 70px; - height: 70px; -} -#feedback_button span, -#invite_button span { - font-size: 22px; -} -#invite_button { - background-color: #bdca70; -} -#feedback_submit { - margin-right: 6px; - width: 60px; - height: 30px; - font-weight: bold; -} -#feedback_button { - background-color: #ad4e88; -} -.eln_navigation_support_buttons { - margin-top: 100px; -} -#feedback_panel { - display: none; - position: fixed; - top: -2px; - left: 0; - z-index: 102; - background: #d9e1e8; - border: 3px solid #ab48a9; - -webkit-box-shadow: 2px 6px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 2px 6px 10px rgba(55, 72, 88, 0.3); - box-shadow: 2px 6px 10px rgba(55, 72, 88, 0.3); -} -.feedback_title { - background: #ab48a9; - color: white; - padding: 5px; - text-align: center; - font-size: 15px; - line-height: 20px; -} -.feedback_title h4 { - display: inline-block; -} -.feedback_title img { - vertical-align: top; - margin-left: 10px; -} -.feedback_content { - padding: 10px; - width: 390px; -} -.feedback_content h4 { - font-size: 12px; -} -#feedback_panel h4 { - margin: 10px; - margin-bottom: 5px; -} -#feedback_comment { - margin: 0 10px 30px 10px; - margin-top: 0; - width: 350px; - height: 120px; -} -#feedback_submit_loader { - display: none; - margin: 8px 15px; -} -/* ************** */ -/* navigation END */ -/* ************** */ -/* ********* */ -/* EPB START */ -/* ********* */ -#epb_container { - /* padding-top: 10px; */ - /* padding-bottom: 80px; */ -} -img.imageOriginal { - border: 1px solid #DDD; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - transition: all linear 0.2s; -} -img.imageLayer { - left: 0; - margin-left: auto; - margin-right: auto; - position: absolute; - right: 0; - top: 0; - transition: all linear 0.2s; -} -#commentBlock { - border-radius: 10px; - cursor: pointer; - position: absolute; - right: 15px; - width: 200px; - background: #FFF; - top: 1px; -} -#epb_older_blocks_panel, -#epb_newer_blocks_panel { - text-align: center; - color: #999; - height: 30px; - line-height: 30px; - margin: 10px 0; -} -.show_more_entries { - font-size: 13px; - margin: auto; - width: 300px; - background: white; - padding: 10px; - text-align: center; - -webkit-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.3); - box-shadow: 0 3px 4px rgba(55, 72, 88, 0.3); -} -.show_more_entries span { - color: #1995d8; - cursor: pointer; -} -.epb_entry { - /* background-color: white; */ - /* border: 1px solid #CCC; */ - /* border-radius: 10px; */ - display: inline-block; - /* margin-right:25px; */ - margin-bottom: 20px; -} -#epb_container { - padding-bottom: 60px; -} -.epb_entry:last-child { - margin-bottom: 10px; -} -.epb_entry_removed { - border: 1px solid #F88; - box-sizing: border-box; -} -.epb_entry p { - margin: 0 !important; -} -.epb_header { - /* height: 35px; */ - /* min-width: 640px; */ - /* border-bottom: 1px solid #d6d4d5; */ - /* padding: 10px 10px 0 10px; */ - /* background-color: #ededed; */ - /* border-radius: 10px 10px 0 0; */ - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; -} -/* .epb_header_container { */ -/* height: 45px; */ -/* } */ -.epb_header_sticky { - position: fixed; - top: 86px; - z-index: 10; - transition: width ease-in 0.3s; -} -.epb_header_sticky div.action_button_text { - margin-left: 5px; -} -.epb_header_sticky div.more_options { - margin-right: 5px; -} -/*Hack for comments*/ -.epb_content_wrap { - display: table; - /* width: 100%; */ -} -.epb_show_comments .epb_content_container { - display: table-cell; - width: 85%; -} -.epb_show_comments .comment_block_container { - display: table-cell; -} -/*End of comment Hack */ -.epb_footer { - font-size: 9px; - height: auto; - margin-left: 30px; - margin-right: 45px; - position: relative; - padding: 5px; - background: #cad4de; - border-top: solid 1px white; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); -} -.epb_footer_signing_infos { - display: inline-block; - text-align: left; -} -.epb_footer_witness_actions { - display: inline-block; - margin-right: 10px; -} -.epb_footer_witness_actions a { - padding-left: 10px; - line-height: 25px; -} -.epb_date { - border-right: 1px solid #d6d4d5; - margin-right: 10px; - padding-right: 10px; - padding-top: 2px; - font-size: 12px; - float: right; - text-align: right; -} -.epb_author { - border-right: 1px solid #d6d4d5; - margin-right: 10px; - padding-right: 10px; - padding-top: 2px; - padding-left: 5px; - font-size: 12px; - float: right; -} -.epb_author_picture { - border: 1px solid #d6d4d5; - float: right; - margin-top: 2px; -} -.epb_comments_alert { - /* color: #FFFFFF; */ - /* float:right; */ - /* margin-right: 5px; */ - cursor: pointer; -} -.epb_comments_count { - /* position: relative; */ - /* top: 7px; */ - /* left: 50%; */ - /* margin-left: 3px; */ - /* vertical-align: top; */ -} -.epb_header_action { - line-height: 24px; - padding-right: 15px; - padding-top: 2px; - font-size: 12px; - float: left; -} -.epb_default_slider_container { - cursor: pointer; -} -div.epb_relative_zoom { - margin-left: 2px; - font-size: 14px; - display: inline-block; - position: relative; - width: 12px; - height: 16px; - vertical-align: text-bottom; -} -div.epb_relative_zoom:hover { - /* color: #69bfee; */ -} -.epb_default_slider { - background-color: #ededed; - border: 1px solid #DDDDDD; - border-radius: 7px; - box-shadow: #B6B4A8 0 1px 7px inset; - box-sizing: border-box; - cursor: pointer; - display: inline-block; - height: 14px; - max-width: 100%; - overflow: hidden; - padding: 0; - position: relative; - width: 114px; - margin: 0 5px 0 4px; -} -.epb_default_slider_active { - background-color: #EFEFE7; - border: 1px solid #99968F; - border-radius: 6px; - box-sizing: border-box; - height: 12px; - position: relative; - width: 12px; - transition: all ease 0.2s; - left: 0; - z-index: 2; -} -.epb_default_slider_active:hover { - box-shadow: #888888 -1px -1px 3px inset; -} -.epb_default_slider_active:active { - background-color: #DDD; - box-shadow: #AAA 1px 1px 2px inset; -} -.epb_default_slider_bar { - background: #69bfee; - /* fallback */ - background: rgba(75, 177, 215, 0.5); - box-shadow: #B6B4A8 0 1px 7px inset; - box-sizing: border-box; - border-bottom-left-radius: 6px; - border-top-left-radius: 6px; - border: 0; - height: 16px; - margin-top: -14px; - padding: 0; - position: relative; - width: 0px; - transition: all ease 0.2s; - z-index: 1; -} -.epb_default_slider_zoom { - cursor: default; - display: block; - line-height: 30px; - width: 100%; - text-align: center; -} -.epb_text_save_cancel { - display: none; -} -.epb_text_save_cancel a { - padding-left: 10px; -} -.epb_file { - margin: 20px 0; -} -.epb_image { - margin: 20px 0; - position: relative; -} -.epb_image .imageLayer { - position: absolute; - top: 0; - left: 0; -} -.epb_image_zoom { - margin-top: 5px; -} -.epb_image_zoom img { - cursor: pointer; -} -.epb_image_zoom_square { - background-color: transparent; - border: 1px solid #666; - margin: 0 1px; -} -.epb_image_zoom_square_active { - background-color: #666; -} -.epb_new_panel { - background: #ededed; - border: 2px solid #CCC; - border-bottom: none; - border-radius: 5px 5px 0 0; - bottom: 0; - height: 40px; - left: 50%; - margin-left: -250px; - padding: 5px; - position: absolute; - text-align: center; - z-index: 2; -} -.epb_new_panel_middle { - background: url(/static/img/design/epb_new_panel_middle.png) repeat-x; - float: left; - height: 55px; - padding-top: 25px; -} -.epb_new_panel_left { - background: url(/static/img/design/epb_new_panel_left.png) no-repeat; - float: left; - height: 80px; - width: 30px; - position: relative; -} -.epb_new_panel_right { - background: url(/static/img/design/epb_new_panel_right.png) no-repeat; - float: left; - height: 80px; - width: 30px; -} -.epb_new_panel .default_button { - margin: 0 5px; -} -#epb_new_panel_jump_to_end { - display: none; -} -#epb_new_panel_jump_to_end div { - float: left; - font-size: 14px; - line-height: 30px; -} -.epb_entry_removed_msg_head { - display: none; - margin: 0 200px; - text-align: center; - color: #F88; - padding-top: 5px; -} -/* ******* */ -/* EPB END */ -/* ******* */ -/* ******************* */ -/* block history START */ -/* ******************* */ -.block_history_table { - border-collapse: collapse; - width: 100%; -} -tr.history_row:nth-child(odd) { - background-color: #fff; - cursor: pointer; - height: 23px; -} -tr.history_row:nth-child(even) { - background-color: #f0f0f0; - cursor: pointer; - height: 23px; -} -.block_history_table td.col1 { - padding: 3px 0 3px 5px; -} -.block_history_table td.col2 { - padding: 3px 10px 3px 10px; -} -.block_history_table td.col3 { - padding: 3px 0; -} -#block_history_navigation { - position: absolute; - width: 350px; - bottom: 0; - top: 30px; - left: 0; - overflow: auto; - border-right: 2px solid #374858; -} -#block_history_item_content { - position: absolute; - right: 0; - bottom: 0; - top: 30px; - left: 350px; - padding: 0 20px; - overflow: scroll; -} -.block_history_row_selected { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - background-color: #DDD !important; - color: #4BB1D1; -} -/* ***************** */ -/* block history END */ -/* ***************** */ -/* ************** */ -/* plupload START */ -/* ************** */ -.plupload_select { - width: 110px; - height: 24px; - margin: 0 auto; -} -.plupload_drop { - border: 2px dashed black; - width: 200px; - height: 80px; - margin: 0 auto; - background-color: #77ff66; -} -#plupload_container { - position: absolute; - top: -100px; - left: 0; - width: 100px; - height: 50px; - overflow: hidden; -} -/* ************ */ -/* plupload END */ -/* ************ */ -/* *************** */ -/* workspace START */ -/* *************** */ -.workspace_header_actions { - height: 50px; -} -.workspace_header_actions .default_button { - margin-right: 15px; -} -.workspace_header_link { - margin-right: 15px; - line-height: 36px; -} -.workspace_header_link span { - font-weight: bold; -} -/** Modified at the end of the section -.workspace_header { - background-color: #F3F3F3; - border: 1px solid #DDD; - line-height: 36px; - padding: 5px; - padding-left: 15px; -}*/ -.workspace_header_path a { - outline: none; - color: #fff; - text-decoration: none; -} -.workspace_header_path a:hover { - color: #69bfee; -} -.project_list_children { - display: none; - margin-left: 30px; -} -.project_list_head { - border: 1px solid #DDD; - border-radius: 10px; - background-color: #f3f3f3; - padding: 10px 0; - height: 12px; -} -.project_list_head .name { - margin-left: 15px; -} -.project_list_head .updateTS { - float: right; - margin-right: 15px; -} -.project_list { - min-height: 350px; - margin: 0 25px 25px 0; - background-color: #ffffff; - border-bottom: solid 1px #cad4de; - border-left: solid 1px #cad4de; - border-right: solid 1px #cad4de; - position: relative; - padding: 20px 20px 20px 135px; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.1); -} -.project_list_line { - /* background: url(/static/icon/project40.png) no-repeat 0 -40px; */ - display: block; - outline: none; - color: #4b6277; - cursor: pointer; - text-decoration: none; - line-height: 1.2; - font-size: 14px; - padding: 5px 15px; - border: 1px solid transparent; - overflow: hidden; -} -.project_list_line > span { - color: #4b6277; - line-height: 1.2; - font-size: 14px; -} -.project_list_line:hover { - background-position: 0 0; - background: #ecf0f3; - text-decoration: none; -} -.project_list_line.is_folder { - background: url(/static/icon/folder40.png) no-repeat 0 -40px; -} -.project_list_line:hover.is_folder { - background-position: 0 0; -} -.project_list_line.is_group { - /* background: url(/static/icon/group40.png) no-repeat 0 -40px; */ -} -.project_list_line:hover.is_group { - background-position: 0 0; -} -.project_list_line img { - vertical-align: top; -} -.project_list_line .name { - font-size: 14px; -} -.project_list_line .updateTS { - font-size: 15px; - float: right; - margin-right: 15px; -} -a.order_link { - font-size: 12px; - outline: none; - color: #374858; - text-decoration: none; -} -a.order_link:hover { - color: #69bfee; -} -a.order_link_asc { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -65px; -} -a.order_link_desc { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -45px; -} -a.order_link_asc:hover { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -25px; -} -a.order_link_desc:hover { - padding-right: 12px; - background: url(/static/icon/order_sign.png) no-repeat right -5px; -} -.workspace_header { - background: #374858 repeat-x 0 0; - border: 1px solid #DDD; - border-radius: 10px; - height: 35px; - line-height: 5px; - padding: 5px 10px; -} -.workspace_name { - color: #FFFFFF; - float: left; - font-size: 24px; - height: 32px; - line-height: 32px; - margin-top: 5px; - overflow: hidden; - text-overflow: ellipsis; - width: 90%; - white-space: nowrap; -} -.workspace_name a { - color: #FFF; -} -.workspace_name a:hover { - color: #69bfee; - text-decoration: none; -} -/* ************* */ -/* workspace END */ -/* ************* */ -/* ******************* */ -/* profile block START */ -/* ******************* */ -#user_settings_innovation_level_form select { - background: #ffffff; - border: 1px solid #d9e1e8; - color: #5e7b97; - cursor: pointer; - margin: 0 0 0 10px; - padding: 4px 4px 4px 8px; - outline: 0; -} -#profile_picture_edit_panel { - float: left; - margin-right: 20px; - margin-bottom: 15px; - padding-left: 5px; -} -#profile_picture_edit_panel img { - border: 1px solid #bac7d4; - margin-top: 10px; - width: 100px; - height: 100px; -} -.profile_block { - padding-left: 15px; - width: 550px; - margin-bottom: 20px; -} -.profile_block_edit { - display: block; - float: right; - margin-right: 5px; - font-size: 12px; -} -.profile_edit .placeholder_frame { - margin: 0 5px 5px 0; -} -.project_pdf_export_list { - background: #ffffff; - border: 1px solid #DDD; - height: 125px; - margin: 15px 0 30px 0; - padding: 5px; - overflow-y: scroll; -} -.project_pdf_export_list div { - line-height: 18px; - height: 18px; - overflow: hidden; -} -.pdf_range_export label { - display: block; - text-align: left; -} -/*FIND A BETTER WAY WITH last-child*/ -#profile_contact { - border: none; - padding-bottom: 0px; -} -#profile_picture_edit_link { - position: relative; -} -#profile_picture_edit_panel span { - opacity: 0; - height: 25px; - left: 0; - line-height: 25px; - position: absolute; - text-align: center; - top: 86px; - width: 100px; - -webkit-transition: all 0.3s ease; - -moz-transition: all 0.3s ease; - -o-transition: all 0.3s ease; - transition: all 0.3s ease; -} -#profile_picture_edit_panel:hover span { - background: rgba(75, 98, 119, 0.95); - opacity: 1; - color: white; -} -.profile_block_img { - display: block; -} -#updatePersonalForm .placeholder_frame { - float: none; - width: 380px; -} -.profile_block_key { - float: left; - font-weight: bold; - font-size: 12px; - height: 24px; - line-height: 24px; - margin-bottom: 10px; - width: 100px; -} -#profile_settings .profile_block_key { - padding-left: 5px; - width: 200px; -} -#profile_settings .profile_block h2 { - margin: 0 0 15px 0; -} -.edit_wrap { - width: 100%; - height: 10px; -} -.profile_block_value { - float: left; - line-height: 24px; - font-size: 12px; -} -.general_setting_item { - margin-bottom: 20px; -} -.profile_block_value input[type=text], -.profile_block_value input[type=password] { - width: 330px; -} -.profile_block_error { - color: red; - display: block; - line-height: 20px; -} -.cancel_save_panel { - float: right; - margin-right: 5px; - line-height: 36px; - margin-top: 20px; -} -.cancel_save_panel .cancel { - float: left; - padding-right: 10px; - font-size: 12px; -} -.profile_block h1 { - margin: 0; - font-size: 14px; -} -.profile_block h2 { - margin: 0 0 5px 0; - padding: 0 0 2px 4px; - color: #7b95ad; - border-bottom: 1px solid #9baec0; - font-size: 12px; - font-weight: normal; -} -.profile_show { - padding: 10px 0 2px 4px; - margin-bottom: 20px; -} -.profile_edit { - padding: 10px 0 2px 4px; - float: left; - display: block; -} -.profile_edit_personal { - width: 400px; -} -.profile_block h3 { - font-size: 12px; - margin: 10px 0; - font-weight: normal; -} -.profile_section { - min-height: 100px; - display: block; - overflow: auto; - margin-bottom: 20px; -} -.profile_prof_head { - width: 400px; -} -.profile_name_field { - width: 200px; -} -.placeholder_frame label.profile_personalEdit { - padding: 5px; -} -.profileTitle_field { - width: 200px; -} -#profile_personal .profile_show div { - display: inline; -} -/* ***************** */ -/* profile block END */ -/* ***************** */ -/* ******************** */ -/* sticky infobox START */ -/* ******************** */ -.sticky_infobox { - width: 350px; - height: 310px; - background: url(/static/img/design/sticky_infobox_big.png) 0 0 no-repeat; - padding: 50px 65px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -/* ****************** */ -/* sticky infobox END */ -/* ****************** */ -/* ************ */ -/* search START */ -/* ************ */ -.search_wrap { - padding-left: 15px; -} -.search_wrap .placeholder_frame { - height: 30px; -} -.search_wrap .placeholder_frame input { - height: 30px; -} -.search_wrap .placeholder_frame label { - padding: 4px 0 0 5px; - font-size: 14px; -} -.search_wrap .placeholder_frame button.search_button { - height: 30px; -} -.top_searchbox_form { - float: right; - position: relative; - top: 12px; - padding-right: 10px; -} -.search_result_item { - padding-bottom: 20px; - width: 560px; -} -.search_result_item_title { - text-decoration: underline; - font-size: 12px; -} -.search_result_item_title:hover { - text-decoration: underline; - color: #3b97ed; -} -.search_result_item_text { - font-size: 12px; -} -#search_result_load_more_spinner { - display: none; -} -#search_result_load_more_link { - display: none; -} -#search_result_error_message { - display: none; - color: red; -} -#search_result_num_all_results { - display: none; - color: #999; - font-size: 12px; - padding: 3px; -} -.search_result_content { - padding-top: 20px; -} -/* ********** */ -/* search END */ -/* ********** */ -.default_font { - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; - font-size: 15px; - line-height: 1.45em; - white-space: normal; -} -#data_element { - display: none; -} - -/**************/ -/* IE WARNING */ -/**************/ -#ie_warning { - display: none; - background-color: #E66873; - color: #FFF; - font-size: 14px; - height: 30px; - left: 50%; - line-height: 14px; - margin-left: -310px; - padding: 5px; - position: fixed; - text-align: center; - width: 550px; - z-index: 9999; -} -a#ie_warning_close { - color: #FFF; - float: right; - font-size: 12px; - cursor: pointer; -} -a#ie_warning_update { - color: #FFF; - font-size: 14px; - text-decoration: underline; -} -/****************************/ -/* admin active weeks START */ -/****************************/ -.activeWeeksTable { - border-spacing: 0; - border-collapse: collapse; - font-size: 8px; - background-color: #e5e5e5; - text-align: center; -} -.activeWeeksTable th { - border: 1px solid #374858; -} -.activeWeeksTable td { - border: 1px solid #374858; -} -.activeWeeksTable .week { - width: 20px; - height: 20px; -} -.activeWeeksTable .week.status1 { - background-color: white; -} -.activeWeeksTable .week.status2 { - background-color: #fcc; -} -.activeWeeksTable .week.status3 { - background-color: #cfc; -} -.activeWeeksTable .week.status3 { - background-color: #cfc; -} -.activeWeeksTable .premium { - background-color: #cfc; -} -/**************************/ -/* admin active weeks END */ -/**************************/ -/**************************/ -/* pdf viewer START */ -/**************************/ -#pdf_viewer { - border: 0; - display: block; - height: 100%; - width: 100%; -} -/**************************/ -/* pdf viewer END */ -/**************************/ -.activeExcelSheet { - font-weight: bold; -} -a.editor_reference { - color: #a21621; - cursor: pointer; - font-weight: bold; - text-decoration: none; -} -.pdf_checkbox_label { - line-height: 32px; - margin-left: 25px; -} -.pdf_checkbox_sublabel { - line-height: 32px; - margin-left: 45px; -} -.pdf_setting_description { - margin-left: 50px; - font-size: 12px; -} -.pdf_filename_label { - display: block; - margin: 10px 0 10px 32px; -} -/**************************/ -/* END */ -/**************************/ -#block_history_item_content .extract_preview_link, -.readOnly .extract_preview_link { - display: none; -} -.extract_preview { - overflow: auto; -} -.extract_preview_confirm { - float: right !important; - margin-right: 25px; -} -/*********************/ -/* jsTemplates START */ -/*********************/ -#jsTemplates { - display: none; -} -p.jsTemplate_dialog_title { - display: none; -} -/*******************/ -/* jsTemplates END */ -/*******************/ -/***************/ -/* popup START */ -/***************/ -.popup { - display: none; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - z-index: 98; - -moz-opacity: .8; - opacity: 0.8; - background-color: white !important; -} -.popup_window { - display: none; - position: absolute; - z-index: 99; - background-color: white; - /* border: 2px solid #374858; */ - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); -} -.popup_window_default { - top: 75px; - bottom: 75px; - left: 75px; - right: 75px; -} -#my_popup_inner { - background-color: #cad4de; -} -.popup_dialog { - display: none; - position: absolute; - z-index: 99; - background-color: #cad4de; - top: 30%; - left: 50%; - width: 400px; - margin-top: -125px; - margin-left: -200px; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.8); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.8); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.8); -} -.popup_title { - height: 30px; - line-height: 30px; - margin-top: -1px; - padding-left: 5px; - background: #304d69; - color: white; -} -.popup_title_close { - font-size: 20px; - width: 20px; - height: 20px; - text-align: center; - line-height: 20px; - float: right; - cursor: pointer; - margin: 4px; -} -.popup_title_left { - float: left; -} -.popup_title_center { - text-align: center; -} -.popup_title_center span { - display: none; -} -.popup_loading_image { - margin: 50px auto; - background: url(/static/img/ajax-loader-big.gif) no-repeat; - width: 32px; - height: 32px; -} -.popup_dialog .popup_dialog_content { - max-height: 650px; - overflow: auto; - padding: 10px; -} -.popup_dialog_cancel_save_panel { - float: right; - margin-top: 10px; - line-height: 30px; -} -.popup_dialog_cancel_save_panel .cancel { - float: left; - padding-right: 5px; - font-size: 12px; - visibility: hidden; -} -.popup_dialog_cancel_save_panel .dialog_confirm { - visibility: hidden; -} -#import_footer .dialog_confirm { - visibility: visible; -} -.popup_dialog_cancel_save_panel .default_button { - margin-left: 5px; -} -.popup_scroll_content { - position: absolute; - right: 0; - bottom: 0; - top: 30px; - left: 0; - padding: 10px; - overflow: auto; -} -.popup_list_row { - padding-bottom: 15px; - margin-bottom: 15px; - border-bottom: 1px solid #DDD; -} -.popup_list_row .default_button { - float: right; -} -.popup_list_row .deny_link { - float: right; - line-height: 36px; - font-size: 12px; - margin: 0 5px; -} -.popup_list_row_desc { - padding-top: 12px; - margin-right: 125px; -} -.popup_dialog_error { - background-color: #E66873; - color: #FFF; - display: none; - font-size: 14px; - line-height: 18px; - padding: 5px; - text-align: center; -} -.popup_dialog_loading_button { - padding: 0 10px; -} -#my_popup_content { - height: calc(100% - 29px); - overflow: auto; -} -.input_block { - margin-bottom: 20px; - word-wrap: break-word; - font-size: 12px; -} -.input_block .folder_up-img { - background-position: -738px -5px; - width: 24px; - height: 13px; -} -.tagline_hidden { - display: none; -} -.input_title { - margin: 10px 0 5px; - font-size: 12px; - color: #4b6277; -} -#my_popup_content .input_title:first-of-type { - /* margin: 0 0 5px 0; */ -} -#my_popup_content .spinner { - display: block; - margin: auto; -} -#my_popup_content textarea { - color: #4b6277; - line-height: 1.4; - font-size: 14px; - height: 150px; - resize: none; -} -/*************/ -/* popup END */ -/*************/ -/**************************/ -/* custom selectbox START */ -/**************************/ -div.lfSelectBox { - position: relative; - cursor: pointer; - background-color: white; - width: 0; - float: left; -} -div.lfSelectTitle { - border: 1px solid black; -} -div.lfSelectOptions { - position: absolute; - border: 1px solid black; - background: white; - z-index: 99; - display: none; -} -div.lfSelectOption:hover { - color: #E7E7E7; - background: #3988e5; -} -/************************/ -/* custom selectbox END */ -/************************/ -/* ************ */ -/* button START */ -/* ************ */ -a.btn, -button.btn { - background: transparent url(/static/img/button/button_right.gif) no-repeat scroll top right; - border: 0; - color: #666; - cursor: pointer; - display: block; - float: left; - font-size: 14px; - line-height: 16px; - height: 24px; - margin-right: 6px; - outline: none; - padding-right: 16px; - padding-top: 0; - text-decoration: none; -} -a.btn span, -button.btn span { - background: transparent url(/static/img/button/button_left.gif) no-repeat; - display: block; - padding: 4px 0 4px 18px; -} -a.btn img, -button.btn img { - vertical-align: top; -} -a.btn:active, -button.btn:active { - background-position: bottom right; -} -a.btn:active span, -button.btn:active span { - background-position: bottom left; - padding: 5px 0 3px 18px; -} -/* a.btn36, button.btn36 { */ -/* background-color: transparent; */ -/* border: 0; */ -/* margin: 0; */ -/* padding: 0; */ -/* color: white; */ -/* cursor: pointer; */ -/* display: block; */ -/* float: left; */ -/* font-size: 14px; */ -/* line-height: 16px; */ -/* height: 36px; */ -/* outline: none; */ -/* text-decoration: none; */ -/* font-family: 'din-medi'; */ -/* } */ -/* a.btn36 img, button.btn36 img { */ -/* vertical-align: top; */ -/* margin-right: 7px; */ -/* } */ -/* a.btn36 span, button.btn36 span { */ -/* display: block; */ -/* float: left; */ -/* } */ -/* a.btn36 span.m, button.btn36 span.m { */ -/* background: url(/static/img/button/b36_m.png) repeat-x 0 0; */ -/* height: 16px; */ -/* padding: 10px 1px 10px 1px; */ -/* } */ -/* a.btn36 span.l, button.btn36 span.l { */ -/* background: url(/static/img/button/b36_l.png) no-repeat 0 0; */ -/* width: 15px; */ -/* height: 36px; */ -/* } */ -/* a.btn36 span.r, button.btn36 span.r { */ -/* background: url(/static/img/button/b36_r.png) no-repeat 0 0; */ -/* width: 15px; */ -/* height: 36px; */ -/* } */ -/* a.btn36:hover span, button.btn36:hover span { */ -/* background-position: 0 -36px; */ -/* } */ -/* a.btn36:active span, button.btn36:active span { */ -/* background-position: 0 -72px; */ -/* } */ -/* a.btn36:active span.m, button.btn36:active span.m { */ -/* padding: 11px 0px 9px 2px; */ -/* } */ -/* ********** */ -/* button END */ -/* ********** */ -/* ************ */ -/* errors START */ -/* ************ */ -.errorBox { - border: 1px solid red; -} -.errorInput { - background-color: red; -} -.errorMessage { - color: red; -} -/* ********** */ -/* errors END */ -/* ********** */ -/* *********************** */ -/* input placeholder START */ -/* *********************** */ -.placeholder_frame { - position: relative; - float: left; -} -.placeholder_frame label { - position: absolute; - padding: 7px 0 0 5px; - top: 2px; - left: 0; - color: #9baec0; - font-style: italic; - font-family: Arial; - cursor: text; - font-size: 14px; -} -.placeholder_frame input { - padding: 5px; - margin: 0; - font-size: 14px; - line-height: 14px; - color: #4b6277; -} -.placeholder_frame button { - position: absolute; - height: 28px; - padding: 7px; - top: 0; - right: 0; -} -.placeholder_frame input.searchbox_input { - width: 250px ; - padding-right: 30px; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} -.placeholder_frame.big label { - font-size: 20px; - padding: 10px 0 0 12px; -} -.placeholder_frame.big input { - padding: 10px; - padding-right: 50px; - width: 500px; - font-size: 20px; - line-height: 20px; -} -.placeholder_frame.big button { - padding: 10px; - font-size: 20px; -} -/* *********************** */ -/* input placeholder END */ -/* *********************** */ -/* ************ */ -/* inputs START */ -/* ************ */ -.input_with_padding { - padding: 3px; - width: 100%; -} -.form_around_input_with_padding { - padding-right: 5px; -} -/* ********** */ -/* inputs END */ -/* ********** */ -.aligned_radio_button { - display: -moz-inline-box; - display: inline-block; - vertical-align: middle; - line-height: 18px; - margin-bottom: 5px; -} -input { - outline: 0; -} -textarea { - outline-color: #69bfee; -} -input[type="checkbox"].default_checkbox { - position: absolute; - opacity: 0; -} -input[type="checkbox"].default_checkbox + div { - cursor: pointer; - display: inline-block; - vertical-align: middle; - width: 46px; - height: 13px; - border: 1px solid rgba(55, 72, 88, 0.47); - border-radius: 999px; - margin: 0 .5em; - background: #f9fafb; - background-image: linear-gradient(rgba(176, 205, 231, 0.2), rgba(0, 0, 0, 0)), linear-gradient(90deg, #374858, rgba(0, 0, 0, 0) 65%); - background-size: 200% 100%; - background-position: 100% 0; - background-origin: border-box; - background-clip: border-box; - overflow: hidden; - transition-duration: .3s; - transition-property: padding, width, background-position, text-indent; - box-shadow: 0 0.2em 0.4em rgba(14, 27, 37, 0.12) inset, 0 0.45em 0 0.1em rgba(45, 98, 133, 0.05) inset; - font-size: 150%; -} -input[type="checkbox"].default_checkbox:checked + div { - padding-left: 33px; - width: 46px; - background-position: 0 0; -} -input[type="checkbox"].default_checkbox + div:before { - content: 'On'; - float: left; - width: 13px; - height: 13px; - margin: -1px; - border: 1px solid rgba(55, 72, 88, 0.35); - border-radius: inherit; - background: white; - background-image: linear-gradient(#8fa1b4, transparent); - box-shadow: 0 0.1em 0.1em 0.1em rgba(255, 255, 255, 0.8) inset, 0 0 0.5em rgba(55, 72, 88, 0.3); - color: white; - text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.3); - text-indent: -2.5em; -} -input[type="checkbox"].default_checkbox:active + div:before { - background-color: #eee; -} -input[type="checkbox"].default_checkbox + div:before, -input[type="checkbox"].default_checkbox + div:after { - font-size: 9px; - line-height: 12px; - font-weight: bold; - text-transform: uppercase; -} -input[type="checkbox"].default_checkbox + div:after { - content: 'Off'; - float: left; - text-indent: .5em; - color: #4b6277; - text-shadow: none; -} -/* Draggable */ -div.action_button.dragging_helper { - width: 42px; - height: 24px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 2px 10px; - background-image: url('/static/img/design/blank.png') !important; - background-color: #FFF; - border-radius: 2px; - box-shadow: 0 1px 4px #646464; - color: #69bfee; - cursor: pointer; - opacity: 0.8; - text-decoration: none; - z-index: 50; -} -a.dragging_helper { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - background-image: url('/static/img/design/blank.png') !important; - background-color: #FFF; - border-radius: 2px; - box-shadow: 1px 1px 5px #000; - color: #69bfee; - cursor: pointer; - opacity: 0.5; - padding: 10px 30px; - text-decoration: none; - z-index: 50; -} -.dialog_message_form textarea { - min-height: 150px; -} -/************* -* header css * -**************/ -.arrow_box { - position: relative; - background: white; -} -.arrow_box:after, -.arrow_box:before { - bottom: 100%; - left: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; -} -.arrow_box:after { - border-color: rgba(0, 0, 0, 0); - border-bottom-color: white; - border-width: 5px; - margin-left: -4px; -} -.arrow_box:before { - border-color: rgba(0, 0, 0, 0); - border-bottom-color: #bac7d4; - border-width: 6px; - margin-left: -5px; -} -.headerbar_top { - width: 100%; - height: 50px; - background: white; - border-bottom: solid 1px #bac7d4; -} -.headerbar_top > header { - margin: 21px 0 0 65px; - font-weight: bold; - float: left; - position: relative; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: #415568; -} -.headerbar_top > header:hover .page_title { - position: absolute; - overflow: visible; - white-space: normal; - display: block; - margin-left: 21px; - z-index: 999; - background: white; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); -} -.headerbar_top h1 { - font-size: 14px; - font-weight: normal; - margin: 0; -} -.headerbar_top > nav { - float: right; - height: 50px; -} -.headerbar_top a { - color: inherit; - text-decoration: none; - cursor: pointer; -} -.page_title { - white-space: nowrap; - text-overflow: ellipsis; - display: block; - overflow: hidden; - padding: 0; - background: white; - margin-left: 0; -} -.page_title a { - white-space: nowrap; -} -.nav_top { - float: left; - margin: 0 100px 0 10px; -} -.nav_top > ul { - margin: 0; - padding: 0; -} -.nav_top > ul > li { - width: 72px; - height: 49px; - margin-left: -1px; - list-style-type: none; - float: left; - position: relative; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; - -o-transition: all 0.2s ease; - transition: all 0.2s ease; -} -.header_btn { - width: 100%; - height: 100%; - color: #4b6277; - padding: 0; - text-align: center; - font-size: 10px; - position: relative; - cursor: pointer; - background: transparent; - border-left: solid 1px transparent; - border-right: solid 1px transparent; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; - -o-transition: all 0.2s ease; - transition: all 0.2s ease; -} -.header_btn span { - margin-left: auto; - margin-right: auto; - margin-top: 2px; - display: block; - float: none; -} -.header_btn p { - margin: 7px 0; -} -.header_btn:hover { - background: #f3f5f7; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - border-left: solid 1px #cad4de; - border-right: solid 1px #cad4de; - padding-top: 0; -} -.header_btn:active { - background: #d9e1e8; - padding-top: 0; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); -} -.nav_top_active { - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - background: #e0e6eb !important; - border-left: solid 1px #cad4de !important; - border-right: solid 1px #cad4de !important; -} -.manage_hover:hover .header_btn { - background: #f3f5f7; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.1); - border-left: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - padding-top: 0px; -} -.manage_hover:active .header_btn { - background: #d9e1e8; - padding-top: 0px; - -webkit-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 6px rgba(55, 72, 88, 0.2); -} -.manage_dropdown { - position: absolute; - top: 49px; - left: 0; - font-size: 13px; - z-index: 999; -} -.manage_dropdown li { - width: 120px; -} -.manage_dropdown > span { - position: absolute; - top: -11px; - left: 25px; -} -.header_top_dropdown { - background: white; - display: none; - border: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - border-bottom: solid 1px #bac7d4; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - font-size: 13px; -} -.header_top_dropdown > ul { - margin: 0; - padding: 0; -} -.header_top_dropdown > ul li { - list-style-type: none; -} -.header_top_dropdown > ul { - padding: 12px 0 12px 0; -} -.header_top_dropdown > ul > li { - display: block; - text-align: left; - cursor: pointer; -} -.header_top_dropdown > ul > li > a { - padding: 8px 0 8px 12px; - display: block; -} -.header_top_dropdown > ul > li:hover { - background: #ecf0f3; -} -.bread_arrow { - font-size: 11px; -} -.options_top { - float: right; - margin: 10px 0 0 10px; - position: relative; -} -.options_top > ul { - margin: 0; - padding: 0; -} -.options_top > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.options_top > ul > li { - width: 40px; - height: 50px; - margin-right: 15px; - display: block; - float: left; - font-size: 10px; - position: relative; -} -.options_top > ul > li:first-child > span { - margin-left: 10px; -} -.signout_wrap { - position: relative; - display: block; - width: 40px; - height: 32px; -} -.notes_count { - padding: 2px 2px 1px 2px; - line-height: 10px; - color: white; - background: #22a6ee; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - position: absolute; - text-align: right; - left: 20px; - top: 0px; -} -.avatar { - border-radius: 50%; - width: 28px; - height: 28px; - background: #cad4de; - margin-top: -3px; - float: left; - -webkit-box-shadow: 0px 1px 2px rgba(55, 72, 88, 0.6); - -moz-box-shadow: 0px 1px 2px rgba(55, 72, 88, 0.6); - box-shadow: 0px 1px 2px rgba(55, 72, 88, 0.6); -} -.avatar span { - display: block; - float: none; -} -.avatar img { - border-radius: 50%; - width: 28px; - height: 28px; - position: absolute; -} -.avatar .avatar-img { - margin: 3px 0 0 4px; -} -.avatar .arrow_down_s-img { - position: absolute; - top: 12px; - right: 2px; -} -.dropdown_button { - cursor: pointer; -} -.search_dropdown { - width: 250px; - height: 51px; - padding: 10px; - position: absolute; - top: 39px; - left: -111px; - z-index: 999; -} -.search_dropdown > span { - position: absolute; - top: -11px; - left: 114px; -} -.search_dropdown input { - height: 30px; - width: 100%; - font-size: 14px; - color: #4b6277; - padding-left: 4px; - display: block; - margin: auto; - border: solid 1px #bac7d4; -} -.search_dropdown button { - position: absolute; - top: 10px; - right: 10px; - padding: 7px; - height: 30px; -} -.bell_dropdown { - position: absolute; - top: 39px; - left: -166px; - font-size: 12px; - line-height: 1.4; - z-index: 99; - max-height: 530px; - overflow-y: auto; - overflow-x: hidden; -} -.bell_dropdown > span { - position: absolute; - top: -11px; - left: 169px; -} -.bell_dropdown li { - width: 250px; - padding: 8px 0 8px 8px; -} -.bell_dropdown li span { - color: #69bfee; - font-weight: bold; -} -.bell_dropdown li article { - width: 200px; - display: inline-block; - margin-left: 10px; -} -.bell_dropdown li p { - color: #9baec0; - margin: 5px 0; -} -.bell_dropdown li:last-child { - text-align: center; - margin: 14px 0 -12px 0 !important; - background: #d9e1e8; -} -.profile_dropdown { - position: absolute; - top: 39px; - left: -70px; - font-size: 13px; - z-index: 999; - width: 120px; -} -.profile_dropdown > span { - position: absolute; - top: -11px; - left: 77px; -} -.profile_dropdown ul > li { - padding-left: 10px; -} -.profile_dropdown ul > li a { - width: 100%; -} -.med_blue_btn { - padding: 8px 17px 8px 17px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - color: white; - opacity: 1; - background: #3277b8; - font-size: 16px; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - -o-transition: all 0.1s linear; - transition: all 0.1s linear; - -webkit-backface-visibility: hidden; -} -.med_blue_btn:hover, -.med_blue_btn:focus { - background: #2a6398; - -ms-filter: none; - filter: none; - outline: 0; - color: white; - text-decoration: none; -} -.med_blue_btn:active { - background: #245684; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.4); - -moz-box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.4); - box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.4); -} -.orange_btn { - padding: 4px 17px 5px 17px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - color: #ffffff; - opacity: 1; - background: #e37900; - font-size: 20px; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - -o-transition: all 0.1s linear; - transition: all 0.1s linear; - -webkit-backface-visibility: hidden; -} -.upgrade_box { - position: relative; - background: #ffffff; - display: inline-block; - vertical-align: middle; - margin-right: 6px; -} -.upgrade_btn { - color: white; - background: #ff8617; - border: 0; - opacity: 1; - position: absolute; - top: 44px; - right: 40px; - border-radius: 3px; - color: white !important; - text-decoration: none; - padding: 3px 16px; - font-weight: bold; - height: 22px; - margin-top: 3px; - font-size: 14px; - display: block; -} -.upgrade_btn:hover { - background: #ffa14a; - outline: 0; -} -.upgrade_btn:active { - background: #ff8617; - outline: 0; - -webkit-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.3); - box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.3); -} -.upgrade_box:after { - left: 100%; - top: 50%; - border: solid rgba(0, 0, 0, 0); - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(213, 213, 213, 0); - border-left-color: #ffffff; - border-width: 4px; - margin-top: -5px; -} -.filterbox_wrap { - position: relative; - float: left; - min-width: 100px; - width: auto; -} -.filterbox_wrap .filter_btn { - border-left: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - border-top: solid 1px #bac7d4; -} -.filterbox_task_wrap { - position: relative; - float: left; - min-width: 150px; -} -.filterbox_task_wrap .filter_btn { - border-left: solid 1px #bac7d4; - border-right: solid 1px #bac7d4; - border-top: solid 1px #bac7d4; -} -.filter_box_dropdown { - width: auto; - min-width: 100px; - padding: 10px 0; - float: left; - border: solid 1px #cad4de; - background: white; - font-size: 12px; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.2); -} -.filter_box_dropdown > ul { - margin: 0; - padding: 0; -} -.filter_box_dropdown li { - list-style-type: none; - padding: 8px 8px 8px 8px; - cursor: pointer; -} -.filter_box_dropdown li:hover { - background: #ecf0f3; -} -.notebook_notification { - font-size: 16px; - margin: 40px auto; - width: 390px; - padding: 20px; - background: #ffffff; - -webkit-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - -moz-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); -} -/********************* -* overwrite jqueryUI * -*********************/ -.ui-datepicker { - -webkit-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); -} -.ui-corner-all, -.ui-corner-bottom, -.ui-corner-right, -.ui-corner-br { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} -.ui-widget-header { - border: 0 /*{borderColorHeader}*/; - background: #d9e1e8; - color: #4b6277; - /*{fcHeader}*/ - font-weight: normal; -} -.ui-datepicker .ui-datepicker-prev, -.ui-datepicker .ui-datepicker-next { - border: 0; - position: absolute; - top: 0; - width: 1.8em; - height: 100%; -} -.ui-datepicker .ui-datepicker-prev:hover, -.ui-datepicker .ui-datepicker-next:hover { - border: 0; - background: #bac7d4; -} -.ui-datepicker th { - padding: .7em .3em; - text-align: center; - font-weight: normal; - color: #4b6277; - border: 0; -} -.ui-widget-content { - border: 1px solid #9baec0; - background: #ecf0f3; - color: #4b6277; -} -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - border: 1px solid #cad4de; - background: white; - font-weight: normal /*{fwDefault}*/; -} -.ui-state-hover, -.ui-widget-content .ui-state-hover, -.ui-widget-header .ui-state-hover, -.ui-state-focus, -.ui-widget-content .ui-state-focus, -.ui-widget-header .ui-state-focus { - border: 1px solid #bac7d4 /*{borderColorHover}*/; - background: #e4eef7; - font-weight: normal /*{fwDefault}*/; - color: #4b6277; - /*{fcHover}*/ -} -.ui-state-default, -.ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { - color: #4b6277; -} -.ui-state-hover .ui-icon, -.ui-state-focus .ui-icon { - background-image: none; -} -.ui-widget-header .ui-icon { - background-image: none; -} -.ui-icon { - overflow: visible !important; -} -.ui-icon-circle-triangle-w { - position: relative; - background: white; - display: inline-block; - height: 0; - width: 0; -} -.ui-icon-circle-triangle-w:after { - right: 100%; - top: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-right-color: #4b6277; - border-width: 8px; - margin-top: -7px; -} -.ui-icon-circle-triangle-e { - position: relative; - background: white; - display: inline-block; - height: 0; - width: 0; -} -.ui-icon-circle-triangle-e:after { - left: 100%; - top: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-left-color: #4b6277; - border-width: 8px; - margin-top: -7px; -} -.ui-datepicker .ui-datepicker-prev span, -.ui-datepicker .ui-datepicker-next span { - display: block; - position: absolute; - left: 50%; - margin-left: -2px; - top: 50%; - margin-top: 0px; -} -.ui-tooltip { - padding: 5px 10px; - background: #374858; - -webkit-box-shadow: 0 2px 3px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 3px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 3px rgba(55, 72, 88, 0.3); - font: normal 14px; - color: white; - border: 0; - z-index: 11; -} -.ui-tooltip:after { - bottom: 100%; - left: 13px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: transparent; - border-bottom-color: #374858; - border-width: 7px; - margin-left: -7px; -} -/**************** -* media queries * -****************/ -@media (max-width: 1750px) { - .headerbar_top > header { - width: 30%; - } -} -@media (max-width: 1160px) { - .group_content_block { - width: 100%; - } - .headerbar_top > header { - width: 30%; - margin: 19px 0 0 20px; - } - .eln_main_content_box, - .project_list { - padding: 20px 20px 20px 20px; - width: auto; - } - #messages_content, - #task_content, - #comments_content { - padding: 0 10px 0 10px; - } -} -@media (max-width: 1100px) { - .author_firstname, - .author_lastname { - width: 100px; - } -} -@media (max-width: 970px) { - .nav_top { - margin: 0 30px 0 10px; - } - .headerbar_top > header { - width: 200px; - } - .page_title { - margin-top: 2px; - font-size: 12px; - } - .author_firstname, - .author_lastname { - width: 66px; - } - .group_content_box { - padding: 20px; - } - .profile_block { - max-width: 550px; - width: calc(100% - 25px); - } -} -@media (max-height: 600px) { - .popup_dialog { - top: 50%; - } -} - diff --git a/unittests/example_labfolder_data/static/css/export-entry-footer.css b/unittests/example_labfolder_data/static/css/export-entry-footer.css deleted file mode 100644 index 22800c8c..00000000 --- a/unittests/example_labfolder_data/static/css/export-entry-footer.css +++ /dev/null @@ -1,43 +0,0 @@ -.entry_footer { - background: #cad4de; - margin-left: 30px; - margin-right: 45px; - padding-top: 2px; - padding-bottom: 2px; - min-width: 696px; - height: auto; - font-size: 0.6em; -} - -.entry_footer > span { - color: #748dad; - font-weight: 900; - padding: 8px 8px 6px 8px; -} - -.entry_footer_line { - margin-top: 2px; - height: auto; - display: flex; - flex-direction: column; - position: relative; - padding: 5px 5px 5px 22px; - background: #f2f5f7; - border-left: solid 1px #aabbca; - border-right: solid 1px #aabbca; -} - -.entry_footer_signature > img { - position: absolute; - right: 10px; - margin-top: -2px; - height: 30px; -} - -.width_80_percent { - width: 80%; -} - -.min_height_35 { - min-height: 35px; -} diff --git a/unittests/example_labfolder_data/static/css/export-table-element.css b/unittests/example_labfolder_data/static/css/export-table-element.css deleted file mode 100644 index b1032434..00000000 --- a/unittests/example_labfolder_data/static/css/export-table-element.css +++ /dev/null @@ -1,35 +0,0 @@ -.table-el-container, .well-plate-el-container { - padding: 100px 10px; - min-height: calc(100% - 10px) !important; - height: 243px; - background: white; - text-align: center; -} - -.table-el-info, .well-plate-el-info { - color: #bababa; -} - -.table-el-download, .well-plate-el-download { - margin-top: 8px; -} - -.table-el-download > a, .well-plate-el-download > a { - color: #6cc0ec; -} - -.table-el-icon, .well-plate-el-icon { - width: 16px; - height: 16px; - vertical-align: middle; - margin-right: 0.2em; - fill: #6cc0ec;; - flex-shrink: 0; -} - -.table-el-filename, .well-plate-el-filename { - display: inline-block; - vertical-align: middle; - font-size: 16px; - word-break: break-all -} diff --git a/unittests/example_labfolder_data/static/css/jquery-ui.css b/unittests/example_labfolder_data/static/css/jquery-ui.css deleted file mode 100644 index 3f4d674f..00000000 --- a/unittests/example_labfolder_data/static/css/jquery-ui.css +++ /dev/null @@ -1,474 +0,0 @@ -/*! jQuery UI - v1.9.2 - 2012-11-23 -* http://jqueryui.com -* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css -* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */ - -/* Layout helpers -----------------------------------*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } -.ui-helper-clearfix:after { clear: both; } -.ui-helper-clearfix { zoom: 1; } -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } - -.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; } -.ui-accordion .ui-accordion-icons { padding-left: 2.2em; } -.ui-accordion .ui-accordion-noicons { padding-left: .7em; } -.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; } -.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } -.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; } - -.ui-autocomplete { - position: absolute; - top: 0; - left: 0; - cursor: default; -} - -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; } -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } - -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } - -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } - -/* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ - -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } - -/* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -} -.ui-dialog { position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } - -.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; } -.ui-menu .ui-menu { margin-top: -3px; position: absolute; } -.ui-menu .ui-menu-item { margin: 0; padding: 0; zoom: 1; width: 100%; } -.ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; } -.ui-menu .ui-menu-item a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; } -.ui-menu .ui-menu-item a.ui-state-focus, -.ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; } - -.ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; } -.ui-menu .ui-state-disabled a { cursor: default; } - -/* icon support */ -.ui-menu-icons { position: relative; } -.ui-menu-icons .ui-menu-item a { position: relative; padding-left: 2em; } - -/* left-aligned */ -.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; } - -/* right-aligned */ -.ui-menu .ui-menu-icon { position: static; float: right; } - -.ui-progressbar { height:2em; text-align: left; overflow: hidden; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } - -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; } -.ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; } -.ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; } -.ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; } -.ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */ -.ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */ -.ui-spinner-up { top: 0; } -.ui-spinner-down { bottom: 0; } - -/* TR overrides */ -.ui-spinner .ui-icon-triangle-1-s { - /* need to fix icons sprite */ - background-position:-65px -16px; -} - -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } - -.ui-tooltip { - padding: 8px; - position: absolute; - z-index: 9999; -/* max-width: 300px; labfolder hack*/ - -webkit-box-shadow: 0 0 5px #aaa; - box-shadow: 0 0 5px #aaa; -} -/* Fades and background-images don't work well together in IE6, drop the image */ -* html .ui-tooltip { - background-image: none; -} -body .ui-tooltip { border-width: 2px; } - -/* Component containers -----------------------------------*/ -.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } -.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } -.ui-widget-content a { color: #222222/*{fcContent}*/; } -.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } -.ui-widget-header a { color: #222222/*{fcHeader}*/; } - -/* Interaction states -----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; } -.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #212121/*{fcHover}*/; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } -.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } -.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } -.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } -.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } -.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } -.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */ - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } -.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } -.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } -.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } -.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } -.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } - -/* positioning */ -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } -.ui-icon-triangle-1-n { background-position: 0 -16px; } -.ui-icon-triangle-1-ne { background-position: -16px -16px; } -.ui-icon-triangle-1-e { background-position: -32px -16px; } -.ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } -.ui-icon-triangle-1-sw { background-position: -80px -16px; } -.ui-icon-triangle-1-w { background-position: -96px -16px; } -.ui-icon-triangle-1-nw { background-position: -112px -16px; } -.ui-icon-triangle-2-n-s { background-position: -128px -16px; } -.ui-icon-triangle-2-e-w { background-position: -144px -16px; } -.ui-icon-arrow-1-n { background-position: 0 -32px; } -.ui-icon-arrow-1-ne { background-position: -16px -32px; } -.ui-icon-arrow-1-e { background-position: -32px -32px; } -.ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } -.ui-icon-arrow-1-sw { background-position: -80px -32px; } -.ui-icon-arrow-1-w { background-position: -96px -32px; } -.ui-icon-arrow-1-nw { background-position: -112px -32px; } -.ui-icon-arrow-2-n-s { background-position: -128px -32px; } -.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } -.ui-icon-arrow-2-e-w { background-position: -160px -32px; } -.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } -.ui-icon-arrowstop-1-n { background-position: -192px -32px; } -.ui-icon-arrowstop-1-e { background-position: -208px -32px; } -.ui-icon-arrowstop-1-s { background-position: -224px -32px; } -.ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } -.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } -.ui-icon-arrowthick-1-e { background-position: -32px -48px; } -.ui-icon-arrowthick-1-se { background-position: -48px -48px; } -.ui-icon-arrowthick-1-s { background-position: -64px -48px; } -.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } -.ui-icon-arrowthick-1-w { background-position: -96px -48px; } -.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } -.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } -.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } -.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } -.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } -.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } -.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } -.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } -.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } -.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } -.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } -.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } -.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } -.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } -.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } -.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } -.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } -.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } -.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } -.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } -.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } -.ui-icon-arrow-4 { background-position: 0 -80px; } -.ui-icon-arrow-4-diag { background-position: -16px -80px; } -.ui-icon-extlink { background-position: -32px -80px; } -.ui-icon-newwin { background-position: -48px -80px; } -.ui-icon-refresh { background-position: -64px -80px; } -.ui-icon-shuffle { background-position: -80px -80px; } -.ui-icon-transfer-e-w { background-position: -96px -80px; } -.ui-icon-transferthick-e-w { background-position: -112px -80px; } -.ui-icon-folder-collapsed { background-position: 0 -96px; } -.ui-icon-folder-open { background-position: -16px -96px; } -.ui-icon-document { background-position: -32px -96px; } -.ui-icon-document-b { background-position: -48px -96px; } -.ui-icon-note { background-position: -64px -96px; } -.ui-icon-mail-closed { background-position: -80px -96px; } -.ui-icon-mail-open { background-position: -96px -96px; } -.ui-icon-suitcase { background-position: -112px -96px; } -.ui-icon-comment { background-position: -128px -96px; } -.ui-icon-person { background-position: -144px -96px; } -.ui-icon-print { background-position: -160px -96px; } -.ui-icon-trash { background-position: -176px -96px; } -.ui-icon-locked { background-position: -192px -96px; } -.ui-icon-unlocked { background-position: -208px -96px; } -.ui-icon-bookmark { background-position: -224px -96px; } -.ui-icon-tag { background-position: -240px -96px; } -.ui-icon-home { background-position: 0 -112px; } -.ui-icon-flag { background-position: -16px -112px; } -.ui-icon-calendar { background-position: -32px -112px; } -.ui-icon-cart { background-position: -48px -112px; } -.ui-icon-pencil { background-position: -64px -112px; } -.ui-icon-clock { background-position: -80px -112px; } -.ui-icon-disk { background-position: -96px -112px; } -.ui-icon-calculator { background-position: -112px -112px; } -.ui-icon-zoomin { background-position: -128px -112px; } -.ui-icon-zoomout { background-position: -144px -112px; } -.ui-icon-search { background-position: -160px -112px; } -.ui-icon-wrench { background-position: -176px -112px; } -.ui-icon-gear { background-position: -192px -112px; } -.ui-icon-heart { background-position: -208px -112px; } -.ui-icon-star { background-position: -224px -112px; } -.ui-icon-link { background-position: -240px -112px; } -.ui-icon-cancel { background-position: 0 -128px; } -.ui-icon-plus { background-position: -16px -128px; } -.ui-icon-plusthick { background-position: -32px -128px; } -.ui-icon-minus { background-position: -48px -128px; } -.ui-icon-minusthick { background-position: -64px -128px; } -.ui-icon-close { background-position: -80px -128px; } -.ui-icon-closethick { background-position: -96px -128px; } -.ui-icon-key { background-position: -112px -128px; } -.ui-icon-lightbulb { background-position: -128px -128px; } -.ui-icon-scissors { background-position: -144px -128px; } -.ui-icon-clipboard { background-position: -160px -128px; } -.ui-icon-copy { background-position: -176px -128px; } -.ui-icon-contact { background-position: -192px -128px; } -.ui-icon-image { background-position: -208px -128px; } -.ui-icon-video { background-position: -224px -128px; } -.ui-icon-script { background-position: -240px -128px; } -.ui-icon-alert { background-position: 0 -144px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-notice { background-position: -32px -144px; } -.ui-icon-help { background-position: -48px -144px; } -.ui-icon-check { background-position: -64px -144px; } -.ui-icon-bullet { background-position: -80px -144px; } -.ui-icon-radio-on { background-position: -96px -144px; } -.ui-icon-radio-off { background-position: -112px -144px; } -.ui-icon-pin-w { background-position: -128px -144px; } -.ui-icon-pin-s { background-position: -144px -144px; } -.ui-icon-play { background-position: 0 -160px; } -.ui-icon-pause { background-position: -16px -160px; } -.ui-icon-seek-next { background-position: -32px -160px; } -.ui-icon-seek-prev { background-position: -48px -160px; } -.ui-icon-seek-end { background-position: -64px -160px; } -.ui-icon-seek-start { background-position: -80px -160px; } -/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ -.ui-icon-seek-first { background-position: -80px -160px; } -.ui-icon-stop { background-position: -96px -160px; } -.ui-icon-eject { background-position: -112px -160px; } -.ui-icon-volume-off { background-position: -128px -160px; } -.ui-icon-volume-on { background-position: -144px -160px; } -.ui-icon-power { background-position: 0 -176px; } -.ui-icon-signal-diag { background-position: -16px -176px; } -.ui-icon-signal { background-position: -32px -176px; } -.ui-icon-battery-0 { background-position: -48px -176px; } -.ui-icon-battery-1 { background-position: -64px -176px; } -.ui-icon-battery-2 { background-position: -80px -176px; } -.ui-icon-battery-3 { background-position: -96px -176px; } -.ui-icon-circle-plus { background-position: 0 -192px; } -.ui-icon-circle-minus { background-position: -16px -192px; } -.ui-icon-circle-close { background-position: -32px -192px; } -.ui-icon-circle-triangle-e { background-position: -48px -192px; } -.ui-icon-circle-triangle-s { background-position: -64px -192px; } -.ui-icon-circle-triangle-w { background-position: -80px -192px; } -.ui-icon-circle-triangle-n { background-position: -96px -192px; } -.ui-icon-circle-arrow-e { background-position: -112px -192px; } -.ui-icon-circle-arrow-s { background-position: -128px -192px; } -.ui-icon-circle-arrow-w { background-position: -144px -192px; } -.ui-icon-circle-arrow-n { background-position: -160px -192px; } -.ui-icon-circle-zoomin { background-position: -176px -192px; } -.ui-icon-circle-zoomout { background-position: -192px -192px; } -.ui-icon-circle-check { background-position: -208px -192px; } -.ui-icon-circlesmall-plus { background-position: 0 -208px; } -.ui-icon-circlesmall-minus { background-position: -16px -208px; } -.ui-icon-circlesmall-close { background-position: -32px -208px; } -.ui-icon-squaresmall-plus { background-position: -48px -208px; } -.ui-icon-squaresmall-minus { background-position: -64px -208px; } -.ui-icon-squaresmall-close { background-position: -80px -208px; } -.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } -.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } -.ui-icon-grip-solid-vertical { background-position: -32px -224px; } -.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } -.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } -.ui-icon-grip-diagonal-se { background-position: -80px -224px; } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } - -/* Overlays */ -.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } -.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } \ No newline at end of file diff --git a/unittests/example_labfolder_data/static/css/notebook.css b/unittests/example_labfolder_data/static/css/notebook.css deleted file mode 100644 index 75a33689..00000000 --- a/unittests/example_labfolder_data/static/css/notebook.css +++ /dev/null @@ -1,2194 +0,0 @@ -/**************** -* notebook.less * -*****************/ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -#action_buttons { - display: inline-block; - float: right; - height: 250px; - left: 50%; - margin-left: 410px; - position: fixed; - top: 110px; - width: 150px; -} -/**************** -* button + input* -****************/ -button { - border: 0; - font-size: 12px; - padding: 3px 4px; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; -} -button:focus { - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; -} -.search_button { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - border: solid 1px #bac7d4 !important; -} -.btn_on_grey { - color: #415568; - background: #f3f5f7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #f3f5f7)); - background: -ms-linear-gradient(bottom, #e0e6eb, #f3f5f7); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #f3f5f7 100%); - background: -o-linear-gradient(#f3f5f7, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f5f7', endColorstr='#e0e6eb', GradientType=0); - border: 1px solid #7b95ad; - line-height: 1.2; -} -.btn_on_grey:hover { - color: #415568; - background: #f3f5f7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #f3f5f7)); - background: -ms-linear-gradient(bottom, #e0e6eb, #f3f5f7); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #f3f5f7 100%); - background: -o-linear-gradient(#f3f5f7, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f5f7', endColorstr='#e0e6eb', GradientType=0); - outline: 0; - border: 1px solid #5e7b97; - -webkit-box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); - -moz-box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); - box-shadow: 0 0 8px rgba(255, 255, 255, 0.5); -} -.btn_on_grey:active { - color: #4b6277; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #4b6277; - background: #cad4de; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e0e6eb), color-stop(1, #cad4de)); - background: -ms-linear-gradient(bottom, #e0e6eb, #cad4de); - background: -moz-linear-gradient(center bottom, #e0e6eb 0%, #cad4de 100%); - background: -o-linear-gradient(#cad4de, #e0e6eb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cad4de', endColorstr='#e0e6eb', GradientType=0); -} -.btn_on_white { - color: #4b6277; - background: #e6ebef; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #d9e1e8), color-stop(1, #e6ebef)); - background: -ms-linear-gradient(bottom, #d9e1e8, #e6ebef); - background: -moz-linear-gradient(center bottom, #d9e1e8 0%, #e6ebef 100%); - background: -o-linear-gradient(#e6ebef, #d9e1e8); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e6ebef', endColorstr='#d9e1e8', GradientType=0); - border: 1px solid #cad4de; - opacity: 1; - line-height: 13px; -} -.btn_on_white:hover:enabled { - -ms-filter: none; - filter: none; - outline: 0; - border: 1px solid #b4c2d0; -} -.btn_on_white:active { - color: #4b6277; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #c7d2dc; - background: #d9e1e8; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #d9e1e8), color-stop(1, #d0d9e2)); - background: -ms-linear-gradient(bottom, #d9e1e8, #d0d9e2); - background: -moz-linear-gradient(center bottom, #d9e1e8 0%, #d0d9e2 100%); - background: -o-linear-gradient(#d0d9e2, #d9e1e8); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0d9e2', endColorstr='#d9e1e8', GradientType=0); -} -.btn_on_white.disabled { - opacity: 0.6; -} -.btn_on_white.disabled:active { - color: #4b6277; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0); - border: 1px solid #cad4de; - background: #e6ebef; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #d9e1e8), color-stop(1, #e6ebef)); - background: -ms-linear-gradient(bottom, #d9e1e8, #e6ebef); - background: -moz-linear-gradient(center bottom, #d9e1e8 0%, #e6ebef 100%); - background: -o-linear-gradient(#e6ebef, #d9e1e8); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e6ebef', endColorstr='#d9e1e8', GradientType=0); -} -.btn_on_white.disabled:hover { - -ms-filter: none; - filter: none; - outline: 0; - border: 1px solid #cad4de; -} -.filter_btn { - color: #526c84; - background: #ecf0f3; - height: 24px; - padding: 2px 8px; - font-size: 12px; - cursor: pointer; - -webkit-border-radius: 0px; - -moz-border-radius: 0px; - border-radius: 0px; - -webkit-transition: all 0.1s ease; - -moz-transition: all 0.1s ease; - -o-transition: all 0.1s ease; - transition: all 0.1s ease; -} -.filter_btn > span { - height: 4px; - width: 12px; - display: block; - float: left; - margin: 2px 0 0 8px; -} -.filter_btn > p { - margin: 0; - float: left; -} -.filter_btn:hover { - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.1); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.1); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.1); - background: #e0e6eb; - padding-top: 2px; -} -.filter_btn:active { - -webkit-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - background: #cdd7e0; -} -span.close-x { - display: block; - float: left; - margin: 0 0 0 8px; - display: none; -} -.filter_on { - background: #527ca3; - color: white; -} -.filter_on:hover, -.filter_on:active { - background: #527ca3; - color: #e0e6eb; -} -.filter_active { - background: #5b96cd; - color: #ffffff; -} -.filter_active .arrow_down_s-img:after { - border-top-color: white; -} -.filter_active:hover { - background: #5b96cd; - color: #e6ebef; -} -.grey_link { - color: #4b6277; - background: transparent; - font-size: 12px; - padding: 0; - text-decoration: underline; - display: block; - cursor: pointer; -} -.grey_link:hover { - color: #415568; - text-decoration: underline; -} -.grey_link:active { - text-decoration: none; -} -.blue_link { - color: #1995d8; - background: transparent; - font-size: 12px; - padding: 0; - text-decoration: underline; - display: block; - cursor: pointer; -} -.blue_link:hover { - color: #69bfee; - text-decoration: underline; -} -.blue_link:active { - color: #1995d8; - text-decoration: none; -} -.feedback_btn { - color: white; - border: 1px solid #994097; - font-weight: bold; - font-size: 14px; - padding: 5px 0 5px 5px; - position: absolute; - top: 213px; - left: -2px; - z-index: 101; - background: #ab48a9; - cursor: pointer; -} -.feedback_btn > p { - margin: 0; -} -.feedback_btn:hover, -.feedback_btn:focus { - background: #ab48a9; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #bc60ba), color-stop(1, #ab48a9)); - background: -ms-linear-gradient(bottom, #bc60ba, #ab48a9); - background: -moz-linear-gradient(center bottom, #bc60ba 0%, #ab48a9 100%); - background: -o-linear-gradient(#ab48a9, #bc60ba); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ab48a9', endColorstr='#bc60ba', GradientType=0); -} -.feedback_btn:active { - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #873986; - background: #ab48a9; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #c575c3), color-stop(1, #ab48a9)); - background: -ms-linear-gradient(bottom, #c575c3, #ab48a9); - background: -moz-linear-gradient(center bottom, #c575c3 0%, #ab48a9 100%); - background: -o-linear-gradient(#ab48a9, #c575c3); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ab48a9', endColorstr='#c575c3', GradientType=0); -} -.feedback_btn_dialog { - color: white; - font-weight: bold; - font-size: 16px; - padding: 8px 10px; - background: #ab48a9; - cursor: pointer; - border: 0; - display: block; - margin: 90px auto 20px auto; -} -.feedback_btn_dialog > p { - margin: 0; -} -.feedback_btn_dialog:hover { - color: #e5c1e4; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); -} -.feedback_btn_dialog:active { - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); -} -.invite_btn_dialog { - color: white; - font-weight: bold; - font-size: 16px; - padding: 8px 10px; - background: #93ba48; - cursor: pointer; - border: 0; - display: block; - margin: 20px auto; -} -.invite_btn_dialog > p { - margin: 0; -} -.invite_btn_dialog:hover { - color: #e0ebca; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.4); -} -.invite_btn_dialog:active { - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.5); -} -.invite_btn { - border: 1px solid #85a940; - color: white; - font-weight: bold; - font-size: 14px; - padding: 4px 3px 5px 1px; - position: absolute; - top: 296px; - left: -2px; - z-index: 50; - background: #93ba48; - cursor: pointer; -} -.invite_btn > p { - margin: 0; - float: left; -} -.invite_btn > span { - margin: 2px 2px 0 4px; -} -.invite_btn:hover, -.invite_btnfocus { - background: #93ba48; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #a0c25e), color-stop(1, #93ba48)); - background: -ms-linear-gradient(bottom, #a0c25e, #93ba48); - background: -moz-linear-gradient(center bottom, #a0c25e 0%, #93ba48 100%); - background: -o-linear-gradient(#93ba48, #a0c25e); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#93ba48', endColorstr='#a0c25e', GradientType=0); -} -.invite_btn:active { - opacity: 1; - -ms-filter: none; - filter: none; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.2); - border: 1px solid #769639; - background: #93ba48; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #adcb74), color-stop(1, #93ba48)); - background: -ms-linear-gradient(bottom, #adcb74, #93ba48); - background: -moz-linear-gradient(center bottom, #adcb74 0%, #93ba48 100%); - background: -o-linear-gradient(#93ba48, #adcb74); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#93ba48', endColorstr='#adcb74', GradientType=0); -} -.checkbox_filled[type="checkbox"] { - display: none; -} -.checkbox_filled[type="checkbox"]:checked + label:after { - background: #69bfee; - border: 1px solid #5e7b97; -} -.checkbox_filled_bg { - font-size: 12px; - position: relative; - display: inline-block; - padding: 4px 0 4px 25px; - display: block; - width: 110px; - cursor: pointer; -} -.checkbox_filled_bg:hover { - background: #ecf0f3; -} -.checkbox_filled_bg:after { - content: ""; - position: absolute; - display: block; - top: 6px; - left: 5px; - width: 10px; - height: 10px; - border: 1px solid #bac7d4; -} -.checkbox_button_input[type="checkbox"] { - display: none; -} -.checkbox_button_input[type="checkbox"]:checked + label { - background: #e0e6eb; -} -.checkbox_button_input[type="checkbox"]:checked + label:after { - background: #69bfee; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - border: 1px solid #c5e6f8; -} -.empty_folder { - font-size: 12px; - color: #aabbca; -} -.checkbox_button { - font-size: 12px; - position: relative; - padding: 4px 0 4px 1px; - display: inline-block; - width: 100%; - margin: 0; - cursor: pointer; -} -.checkbox_button:hover { - background: #ecf0f3; -} -.checkbox_button b .folder_dn-img, -.checkbox_button b .folder_up-img { - margin-top: -2px; - margin-right: 6px; -} -.checkbox_button:after { - content: ""; - position: absolute; - display: block; - top: 5px; - right: 10px; - width: 10px; - height: 10px; - border: 1px solid #bac7d4; - border-radius: 50%; - -webkit-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 1px 2px rgba(55, 72, 88, 0.2); -} -.own_name { - font-size: 12px; - position: relative; - padding: 4px 0 4px 1px; - display: inline-block; - width: 100%; - margin: 0; - background: #ecf0f3; - padding-left: 10px; - margin-bottom: 14px; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: default; -} -.own_name:after { - content: ""; - position: absolute; - display: block; - top: 5px; - right: 10px; - width: 10px; - height: 10px; - border-radius: 50%; - background: #69bfee; - -webkit-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 1px 1px rgba(55, 72, 88, 0.5); - border: 1px solid #c5e6f8; -} -.label_title { - display: inline-block; - width: calc(80% - 12px); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.input_label_wrap { - position: relative; -} -.input_label_wrap p { - font-size: 12px; - margin: 0 0 4px 4px; -} -.input_label_wrap label { - position: absolute; - bottom: 4px; - left: 4px; - color: #aabbca; -} -/* div.action_button { */ -/* background: #FFF; */ -/* border: 1px solid #CCC; */ -/* border-radius: 5px 5px 5px 5px; */ -/* color: #374858; */ -/* cursor: pointer; */ -/* display: inline-block; */ -/* float: left; */ -/* font-size: 14px; */ -/* height: 25px; */ -/* line-height: 30px; */ -/* margin-right: 10px; */ -/* padding: 0 10px; */ -/* text-align: center; */ -/* top: 0; */ -/* } */ -/* div.action_button:hover { */ -/* color: #69bfee; */ -/* border: 1px solid #69bfee; */ -/* } */ -div.action_button_click_only { - cursor: pointer; -} -div.bigger_button { - font-size: 18px; - margin: 0; - padding: 5px; - width: 250px; - cursor: pointer; - transition: background 0.3s ease; -} -#button_add_entry { - /* margin-right: 10px; */ -} -.action_button { - height: 19px; - width: 24px; -} -.action_button img { - width: 24px; - height: 24px; - display: inline-block; - margin: auto; -} -.action_button p { - display: inline-block; - margin: 0; - margin-left: 5px; - text-align: left; -} -.file_upload_button { - width: auto; - height: 30px; -} -#saved_entry { - display: none; - background-color: #BDCA70; - border-radius: 5px; - color: white; - font-size: 18px; - left: 50%; - margin-left: -60px; - padding: 10px; - position: absolute; - text-align: center; - top: 0; - width: 100px; -} -div.dragging_entry { - background: #69bfee; - border-radius: 2px; - color: #FFF; - cursor: move; - font-size: 18px; - margin-top: -10px; - margin-left: -30px; - opacity: 0.5; - padding: 10px; - text-align: left; - width: 80px !important; - z-index: 100; -} -div.dd_entry_table { - display: table; - table-layout: fixed; - width: 100%; -} -div.dd_entry_row { - display: table-row; -} -div.dd_entry_cell { - border: 1px solid transparent; - display: table-cell; - vertical-align: top; -} -div.dd_entry_cell:hover { - border: 1px solid #CCC; -} -div.dd_entry_cell_wrapper { - position: relative; -} -div.dd_entry_cell_content { - position: relative; - display: block; - min-height: 66px; - vertical-align: top; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - overflow: hidden; - /* For tables */ -} -.handsontable { - overflow: scroll; -} -div.dd_entry_cell_content img { - -webkit-user-select: none; - /* Chrome all / Safari all */ - -moz-user-select: none; - /* Firefox all */ - -ms-user-select: none; - /* IE 10+ */ -} -div.dd_entry_cell_content .imageLayer { - left: 0; - margin-left: auto; - margin-right: auto; - position: absolute; - right: 0; - top: 0; -} -.file_placeholder { - text-align: center; - background-color: #d9e1e8; - border: 1px solid rgba(0, 0, 0, 0); - padding-top: 5px; - transition: background 0.3s ease; -} -.file_placeholder button { - cursor: pointer; - margin: 5px; - padding: 5px; -} -div.dd_entry_cell_file_download { - font-size: 16px; - padding: 15px 10px; - text-align: center; - overflow: hidde; - word-break: break-word; -} -div.dd_entry_cell_file_download span.icon-file { - font-size: 36px; -} -div.file_icon { - vertical-align: bottom; - display: inline-block; -} -div.file_extension { - position: absolute; - background-color: #374858; - color: #FFF; - font-size: 12px; - line-height: 12px; - margin: 12px 0 0 -16px; - padding: 2px; - -webkit-box-sizing: border-box; - /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; - /* Firefox, other Gecko */ - box-sizing: border-box; - /* Opera/IE 8+ */ - border: 1px solid #FFF; - width: 32px; -} -div.file_details { - display: inline-block; - text-align: left; - vertical-align: top; - line-height: 20px; -} -div.file_name { - display: block; - font-size: 18px; -} -div.file_size_link { - display: block; -} -div.file_size_link a { - margin-left: 10px; -} -div.dd_image_entry .dd_entry_cell_content { - text-align: center; - overflow: hidden; -} -.entry_button { - background-color: #e6ebef; - cursor: pointer; - display: none; - height: 30px; - margin: 0; - padding: 5px 0 0; - position: relative; - float: left; - text-align: center; - width: 35px; - z-index: 2; - font-size: 18px; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; - -o-transition: all 0.2s ease; - transition: all 0.2s ease; -} -.entry_button:hover { - background-color: #d9e1e8; -} -.entry_button:active { - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); -} -div.zoom_button, -div.settings_button { - /* border-bottom: 1px solid #CCC; */ - /* border-left: 1px solid #CCC; */ - border-right: 0; - border-top: 0; - border-radius: 0; - right: 0; -} -div.cancel_button, -div.drag_button { - /* right: 35px; */ -} -div.save_button, -div.edit_button { - /* border-right: 1px solid #CCCCCC; */ - /* right: 70px; */ -} -div.zoom_button { - /* border-right: 1px solid #CCCCCC; */ - /* right: 105px; */ -} -div.zoom_button span { - font-size: 14px; - margin: 10px; - line-height: 1.6; - color: #4b6277; -} -div.drag_button { - cursor: move; -} -div.cancel_button, -div.save_button { - display: none; -} -div.zoom_button:hover, -div.cancel_button:hover, -.save_button:hover, -.settings_button:hover, -.drag_button:hover, -.edit_button:hover { - /* color: #69bfee; */ -} -div.zoom_button:hover, -div.settings_button:hover { - margin: 0; -} -div.dd_entry_cell:hover div.zoom_button, -div.dd_entry_cell:hover div.settings_button, -div.dd_entry_cell:hover div.drag_button, -div.dd_entry_cell:hover div.edit_button { - display: block; -} -/* we need !important to override inline css set in labfolder-project.js when showing or hiding buttons for redactor enabled/disabled */ -div.epb_entry.readOnly div.cancel_button, -div.epb_entry.readOnly div.drag_button, -div.epb_entry.readOnly div.settings_button, -div.epb_entry.readOnly div.save_button, -div.epb_entry.readOnly div.edit_button, -div.epb_entry.readOnly div.zoom_button, -div.epb_entry.readOnly button.file_upload_button, -div.epb_entry.readOnly div.more_options_item_remove_block_element { - display: none !important; -} -div.disabled_button { - display: none !important; -} -/*TODO nest better hdrop*/ -.hdrop { - height: 15px; - display: table; - table-layout: fixed; - width: 100%; - transition: background 0.3s ease; -} -.hdrop:only-child { - box-sizing: border-box; - height: 100px; - padding: 40px; -} -.hdrop:only-child:before { - content: "This entry is empty. You can add a TEXT, a SKETCH, a TABLE or attach a FILE by clicking or dragging the buttons in the toolbar above."; - font-size: 13px; - background: #ffffff; - padding: 2px 4px; -} -.hdrop.drop_active:only-child:before { - content: "Drag it here."; -} -.hdrop.drop_hover:only-child:before { - content: "Now drop it."; -} -.hdrop:last-child { - /* border-radius: 0 0 10px 10px; */ -} -.vdrop { - width: 20px; - display: table-cell; - transition: background 0.3s ease; -} -#button_add_entry.drop_active, -.drop_active { - background-color: #aea; -} -.file_placeholder.drop_active { - background-color: #97d3f3; -} -#button_add_entry.drop_hover, -.drop_hover { - background: #69bfee; -} -.file_placeholder.drop_hover { - background-color: #69bfee; -} -.dragBar { - cursor: col-resize; - display: table-cell; - text-align: center; - vertical-align: middle; - width: 10px; -} -.dragBar img { - height: 10px; - width: 2px; -} -.dragBar:hover { - background-color: #DDD; -} -div.epb_entry.readOnly .dragBar { - cursor: default; -} -div.epb_entry.readOnly .dragBar img { - display: none; -} -div.epb_entry.readOnly .dragBar:hover { - background-color: initial; -} -.hidden_entry { - visibility: hidden; -} -.button_wrapper_sticky { - position: fixed !important; - top: 131px !important; - right: inherit !important; - z-index: 20; -} -.dd_entry_cell.ui-state-disabled, -.dd_entry_cell.ui-widget-content .ui-state-disabled, -.dd_entry_cell.ui-widget-header .ui-state-disabled { - background-image: none !important; - opacity: 1 !important; -} -#paste_hidden_input { - opacity: 0; - position: absolute; - right: 10000px; - top: -10000px; -} -/************* -* action bar * -**************/ -.action_bar { - width: 100%; - height: 36px; - min-width: 800px; - padding-top: 10px; - background: white; - border-bottom: solid 2px #a1b3c4; - -webkit-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.2); - -moz-box-shadow: 0 3px 4px rgba(55, 72, 88, 0.2); - box-shadow: 0 3px 4px rgba(55, 72, 88, 0.2); -} -.plus_btn { - width: 64px; - height: 22px; - color: white; - background: #38abf7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0b89dd), color-stop(1, #38abf7)); - background: -ms-linear-gradient(bottom, #0b89dd, #38abf7); - background: -moz-linear-gradient(center bottom, #0b89dd 0%, #38abf7 100%); - background: -o-linear-gradient(#38abf7, #0b89dd); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#38abf7', endColorstr='#0b89dd', GradientType=0); - text-align: left; - font-size: 27px; - font-family: Arial !important; - line-height: 0.6; - padding: 2px 9px; - position: relative; -} -.plus_btn:hover { - outline: 0; - color: #dcf0fb; -} -.plus_btn:active { - -webkit-box-shadow: inset 0 3px 2px rgba(55, 72, 88, 0.5); - -moz-box-shadow: inset 0 3px 2px rgba(55, 72, 88, 0.5); - box-shadow: inset 0 3px 2px rgba(55, 72, 88, 0.5); -} -.plus_btn:after { - content: "Add"; - font-size: 13px; - position: absolute; - right: 10px; - top: 12px; - font-weight: bold; - line-height: 0; -} -.plus_btn_wrap { - width: 200px; - float: left; - margin-top: -3px; -} -.plus_btn_hover { - height: 23px; - margin: 0 0 0 55px; -} -.add_dropdown { - display: none; - position: absolute; - top: 85px; - left: 0; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - z-index: 999; -} -.add_dropdown .default_button { - border: 0; - background: none; -} -.add_dropdown .default_button:active { - background: #4fb9f3; - -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0); - -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0); - box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0); -} -.add_dropdown > ul { - width: 180px; - font-size: 14px; - color: white; - margin: 0; - padding: 12px 0 12px 0; - background: #18a2ed; -} -.add_dropdown > ul li { - list-style-type: none; - padding: 8px 10px 8px 50px; - cursor: pointer; -} -.add_dropdown > ul li:hover { - background: #4fb9f3; -} -.add_link { - padding: 0 0 0 50px !important; - height: 32px; -} -.add_link a { - width: auto; - padding: 8px 0 8px 0; - color: white; - text-decoration: none; - display: block; -} -.add_link a:hover { - text-decoration: none; -} -.action_menu_wrap { - float: left; - margin-top: -1px; -} -.filter_wrap > ul > li { - position: relative; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - border-left: solid 1px #bac7d4; - border-top: solid 1px #bac7d4; - height: 25px; -} -.filter_wrap > ul > li:last-child { - padding: 6px 3px 0 10px; - border-left: solid 1px #bac7d4; - border-top: 0; -} -.filter_wrap > ul > li:first-child { - background: none; - border: none; - color: #7b95ad; - font-size: 12px; - padding: 6px 10px 0 0; - margin-left: 18px; -} -.more_filters { - /* display: none; */ -} -.filter_dropdown_wrap { - width: 190px; - height: auto; - position: absolute; - left: -1px; - top: 25px; - z-index: 999; - display: none; - color: #4b6277; -} -.filter_dropdown_wrap .folder_dn-img { - margin-top: 2px; -} -.filter_dropdown_wrap .folder_up-img { - margin-top: 0; -} -.filter_dropdown_wrap header { - font-size: 11px; - color: #d9e1e8; - background: #4b6277; - padding: 3px 6px 2px 6px; - float: left; -} -.filter_dropdown_wrap header > p { - margin: 0; - float: left; -} -.filter_dropdown_wrap header > span { - float: right; - padding: 0px 0 3px 8px; - color: white; - cursor: pointer; -} -.filter_dropdown { - overflow-y: auto; - overflow-x: hidden; - min-width: 190px; - max-height: 600px; - width: auto; - padding-bottom: 20px; - float: left; - border: solid 1px #bac7d4; - background: white; - -webkit-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 8px rgba(55, 72, 88, 0.3); -} -.filter_dropdown .list_vertical { - padding-top: 10px; -} -.filter_dropdown ul { - padding-left: 20px; -} -.filter_dropdown > ul { - margin: 0; - padding: 0; - width: 230px; -} -.filter_dropdown li { - list-style-type: none; -} -.filter_dropdown nav { - display: block; - height: 30px; - padding-top: 10px; -} -.filter_dropdown nav button { - float: left; - margin-right: 20px; -} -.filterOverlay.active { - opacity: 0.5; -} -.filter_project_dropdown > ul { - margin: 0; - padding: 0; - width: 270px; -} -.invalid_tag { - font-size: 12px; - color: #e66873; -} -.project_filter { - min-width: 255px !important; - padding: 0 6px 10px 4px; -} -.project_filter .tree_button { - display: none !important; -} -.project_filter .updateTS { - display: none !important; -} -.project_filter .treeline, -.project_filter .treeline_children_empty { - font-size: 12px; -} -.root_folder { - padding: 4px 0 4px 2px !important; - width: calc(100% - 29px); -} -.not_possible_project { - display: none; -} -.not_possible_author { - display: none; -} -.folder_label { - padding: 4px 0 4px 2px !important; - width: calc(100% - 29px); -} -.root_folder_wrap { - overflow: auto; - width: 100%; -} -.filter_date_header { - width: 190px; -} -.dropdown_padding { - padding: 10px; -} -.author_filter { - min-width: 255px !important; - padding: 0 6px 0 4px; -} -.tags_input { - margin-top: 10px; - border: solid 1px #bac7d4; - cursor: text; - padding: 2px; - min-height: 50px; - width: 100%; - overflow: auto; -} -.tags_input > span { - font-size: 11px; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; - height: 18px; - margin: 2px; - cursor: pointer; - display: inline-block; -} -.tags_input > span.selected_token { - border: 1px solid #4bb1d7; -} -.tags_input > span.invalid { - border: 1px solid #E66873; - color: #E66873; -} -.token_input { - border: none; - outline: none; - resize: none; - white-space: pre; - font-size: 11px; - line-height: 11px; - vertical-align: top; - font-family: arial, sans-serif; - padding: 5px 0 0 2px; - margin: 0px; - width: auto; - overflow: auto; -} -.token_input_width { - position: absolute; - height: 11px; - display: inline-block; - padding: 0px 10px; - visibility: hidden; -} -.tag_name { - display: inline-block; - margin-right: 5px; - max-width: 250px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.delete_tag { - color: #9baec0; - cursor: pointer; - display: inline-block; - padding: 1px 3px 1px 0px; - vertical-align: top; -} -.delete_tag:after { - content: "\00d7"; -} -.tag_data_wrap { - margin-top: 10px; -} -.tag_data_wrap > ul { - margin: 0; - padding: 0; -} -.tag_data_wrap > ul li { - list-style-type: none; -} -.tag_index { - padding-right: 5px; - text-align: center; - font-size: 10px; - font-weight: bold; - border-right: solid 1px #bac7d4; - float: left; -} -.tag_index > ul { - margin: 0; - padding: 0; -} -.tag_index > ul li { - list-style-type: none; -} -.tag_index li { - width: 15px; - padding: 3px 0 3px 0; - margin-bottom: 1px; - display: block; - cursor: pointer; -} -.tag_index li:hover { - background: #ecf0f3; -} -.existing_tag { - cursor: pointer; -} -.existing_tag.disabled { - color: white; - background: #7b95ad; - border: 1px solid #7b95ad; -} -li.index_selected { - background: #d9e1e8; -} -li.index_selected:hover { - background: #d9e1e8; -} -.all_tags_head { - font-size: 12px; - margin: 10px 0 5px 0; -} -.all_tags { - font-size: 12px; - margin: 40px 0 5px 0; -} -.tag_register { - overflow: auto; - max-height: 300px; - width: 100%; - float: left; - margin-left: 10px; - font-size: 11px; -} -.tag_register ul { - margin: 0; - padding: 0; -} -.tag_register ul li { - list-style-type: none; -} -.tag_register > ul > li { - margin-bottom: 15px; -} -.tag { - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; - display: inline-block; -} -.my_tags li { - margin-bottom: 5px; -} -.my_tags span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.my_tags .selected_tag { - background: #38abf7; - background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0b89dd), color-stop(1, #38abf7)); - background: -ms-linear-gradient(bottom, #0b89dd, #38abf7); - background: -moz-linear-gradient(center bottom, #0b89dd 0%, #38abf7 100%); - background: -o-linear-gradient(#38abf7, #0b89dd); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#38abf7', endColorstr='#0b89dd', GradientType=0); - color: #ffffff; -} -.my_tags .selected_tag.disabled.selected_tag { - background: #f3f5f7; - border: 1px solid #E66873; - color: #E66873; -} -.group_tags li { - margin-bottom: 7px; -} -.group_tags span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.managed_tags li { - margin-bottom: 7px; -} -.managed_tags span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.custom_selectbox { - min-width: 100px; -} -.filter_date_input { - background: white; - border: solid 1px #bac7d4; - width: 120px; - height: 26px; - padding: 2px; - color: #4b6277; -} -.datepicker_wrap { - margin-top: 20px; -} -.datepicker_wrap > div:first-child { - margin-bottom: 15px; -} -.input_label_wrap label.hidden { - display: none; -} -.filter_date_icon { - display: block; - position: absolute; - right: 24px; - top: 20px; - font-size: 20px; - cursor: pointer; -} -.empty_filter_message { - font-size: 12px; - margin: 0 0 10px 10px; -} -/******* -* entry * -********/ -#epb_container { - position: relative; - width: 100%; -} -.epb_entry { - width: 100%; - margin: 19px 0 15px 0; - display: inline-block; -} -.readOnly .entry_toolbar_btns { - display: none; -} -.entry_loading { - background: rgba(255, 255, 255, 0.7); - position: fixed; - top: 85px; - bottom: 0; - left: 0; - z-index: 99; - right: 0; -} -.entry_loading span { - padding: 25px; - background: #fff; - opacity: 1; - border-radius: 10px; - border: 1px solid #9baec0; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - color: #5e7b97; - font-size: 24px; - top: 300px; - width: 250px; - margin-left: -125px; - left: 50%; - text-align: center; - position: absolute; -} -.entry_container { - min-width: 726px; - margin-right: 45px; -} -.entry_header { - width: 100%; - height: 33px; - font-size: 12px; - background: #cdd7e0; -} -.entry_author { - color: #374858; - float: left; -} -.entry_author > ul { - margin: 0; - padding: 0; -} -.entry_author > ul li { - list-style-type: none; -} -.entry_author figure { - background: #ecf0f3; - border: solid 1px #7b95ad; - margin: 2px; - width: 29px; - height: 29px; - float: left; - position: relative; -} -.entry_author figure img { - width: 27px; - height: 27px; - position: absolute; - top: 0; - left: 0; -} -.entry_author figure > span { - margin-left: 4px; -} -.author_name { - float: left; - padding: 2px; - line-height: 1.3; - width: 196px; -} -.author_firstname, -.author_lastname { - white-space: nowrap; - text-overflow: ellipsis; - display: block; - overflow: hidden; - padding: 0; - margin-left: 0; -} -.entry_title_wrap { - float: left; - position: relative; - padding: 2px 4px 3px 4px; - line-height: 1.3; - border-left: 1px solid #ffffff; -} -.entry_name_menu { - float: left; - height: 30px; - overflow: hidden; -} -.entry_name_menu > ul { - margin: 0; - padding: 0; -} -.entry_name_menu > ul li { - list-style-type: none; -} -.entry_name_menu p { - margin: 0; - display: inline-block; -} -.entry_name_menu li { - max-width: 800px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} -.entry_name_menu li:first-child { - float: left; - color: #4f677e; - margin-right: 10px; - font-size: 11px; - line-height: 1.4; -} -.entry_name_menu li:last-child { - float: left; -} -.entry_menu_list { - float: left; - width: 164px; - height: 30px; - overflow: hidden; -} -.entry_menu_list > ul { - margin: 0; - padding: 0; -} -.entry_menu_list > ul li { - list-style-type: none; -} -.entry_menu_list p { - margin: 0; - display: inline-block; -} -.entry_menu_list li { - width: 100%; - display: block; - clear: both; -} -.entry_menu_list li span:first-child { - min-width: 45px; - max-width: 92px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - float: left; - margin-right: 10px; - color: #4f677e; - font-size: 11px; -} -.entry_menu_list li span:last-child { - float: left; - color: #374858; -} -.entry_menus { - height: 100%; - float: right; - position: relative; -} -.entry_menus > ul { - margin: 0; - padding: 0; -} -.entry_menus > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.entry_menus > ul { - height: 100%; -} -.entry_menus > ul > li { - width: 200px; - border-right: solid 1px white; - padding: 2px 4px 3px 4px; - height: 33px; - line-height: 1.3; - background: #cdd7e0; - position: relative; -} -.entry_menus > ul > li:first-child { - border-left: solid 1px white; -} -.entry_menus > ul > li:last-child { - border-right: none; - width: 90px; -} -.entry_menu_more { - min-height: 33px; - height: auto !important; - overflow: visible; - border-bottom: solid 1px #ffffff; - border-left: solid 1px #ffffff; - -webkit-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - -moz-box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - box-shadow: 0 1px 2px rgba(55, 72, 88, 0.5); - z-index: 10; -} -.entry_menu_more .entry_menu_options span:last-child { - position: absolute; - bottom: 6px; -} -.show_list_more { - height: auto; -} -.readOnly .drop_edit_menu { - display: none; -} -.entry_menu_less { - /* overflow: hidden; */ -} -.entry_menu_show { - overflow: visible; -} -.entry_menu_edit .entry_dropdown { - display: block; -} -.entry_menu_options { - float: right; - margin-left: 10px; - padding-left: 4px; - height: 100%; - width: 15px; -} -.entry_menu_options > span { - display: block; - margin-right: 0; - cursor: pointer; -} -.entry_menu_options .arrow_menu_dn-img { - height: 10px !important; - margin-top: 7px; -} -.entry_options { - padding-top: 5px; - float: right; -} -.entry_options > ul { - margin: 0; - padding: 0; -} -.entry_options > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.entry_options > ul > li { - margin-left: 6px; -} -.entry_options > span { - cursor: pointer; -} -.epb_comments_count { - color: #ffffff; - width: 17px; - display: block; - text-align: center; - margin-top: 1px; - font-size: 9px; - height: 12px; - line-height: 12px; -} -@-moz-document url-prefix() { - .epb_comments_count { - line-height: 11px; - } -} -.entry_toolbar { - height: 25px; - margin-left: 31px; - position: relative; - padding: 5px; - background: #cdd7e0; - border-top: solid 1px white; - -webkit-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); - box-shadow: 0 2px 2px rgba(55, 72, 88, 0.3); -} -.entry_toolbar > ul { - margin: 0; - padding: 0; -} -.entry_toolbar > ul > li { - list-style-type: none; - float: left; - position: relative; -} -.entry_toolbar > ul > li { - margin-right: 12px; - cursor: pointer; -} -.entry_toolbar > ul > li:first-child { - margin-left: 6px; -} -.entry_toolbar_btns { - /*display: none;*/ -} -.entry_content { - min-height: 300px; - background: #f9fafb; - border: solid 1px #cad4de; -} -.entry_footer { - margin-left: 30px; - height: 25px; - background: #cad4de; -} -.tag { - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; -} -.entry_tags { - float: left; - height: 100%; - overflow: hidden; - max-width: 138px; -} -.entry_tags > span { - display: inline-block; - padding: 1px 3px; - background: #f3f5f7; - border-radius: 3px; - border: solid 1px #cad4de; - float: left; - line-height: 1; - padding: 0px 3px; - border: solid 1px #aabbca; - margin-right: 2px; -} -.entry_dropdown { - width: 101%; - min-width: 260px; - height: auto; - padding: 10px; - background: #cdd7e0; - border-left: solid 1px white; - border-right: solid 1px white; - border-bottom: solid 1px white; - position: absolute; - top: 0; - right: -1px; - z-index: 14; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - display: none; -} -.entry_dropdown > ul { - margin: 0; - padding: 0; -} -.entry_dropdown > ul li { - list-style-type: none; -} -.entry_dropdown input { - border: none; - height: 28px; - font-size: 12px; - padding-left: 6px; - width: 100%; - color: #4b6277; -} -.entry_dropdown label { - font-size: 11px; - display: block; - margin-bottom: 4px; -} -.entry_dropdown > nav { - width: 100%; - height: 18px; -} -.entry_name { - right: auto !important; - left: -1px !important; -} -.entry_name select { - width: 60%; -} -.entry_name > ul > li { - margin: 4px 0 12px 0; -} -.entry_name > ul > li:first-child { - margin-top: -8px; -} -.project_tree { - width: 100%; - height: 140px; - overflow: auto; - background: white; -} -.close_entry_menu { - height: 18px; - width: 100%; - margin-top: -5px; -} -.close_entry_menu span { - float: right; -} -.save_entry_menu { - height: 20px; - float: right; - margin-top: 10px; -} -.save_entry_menu .grey_link { - display: block; - float: left; - padding: 4px 20px 0 0; -} -.select_entry_menu { - width: 100%; - height: 25px; - float: left; - margin-top: 20px; -} -.select_entry_menu span, -.select_entry_menu button { - float: left; - margin-right: 15px; -} -.select_entry_menu .blue_link { - color: #3b97ed; -} -.entry_tag_index li:hover { - background: #d9e1e8; -} -.entry_tag_index li.index_selected { - background: #e6ebef; -} -.entry_tag_index li.index_selected:hover { - background: #e6ebef; -} -.entry_tags_input { - margin: 0; - background: white; - border: none; -} -.entry_dates { - width: 100%; -} -.entry_dates > li { - display: block; - width: 100%; - clear: both; - overflow: auto; - margin-bottom: 15px; -} -.entry_dates > li > span { - margin: 5px 0 0 6px; - cursor: pointer; -} -.entry_dates > li > span:active { - margin: 6px 0 0 6px; -} -.entry_dates input { - height: 25px; - background: #e9edf1; -} -.entry_dates input:focus { - background: white; -} -.entry_dates > li:last-child { - margin-bottom: 5px; -} -.entry_dates > li:last-child input { - background: white; -} -.entry_dates > li:first-child { - margin-bottom: 0; -} -.drag_handle { - background: #d9e1e8; - width: 9px; - height: 25px; - padding: 5px 3px; - float: left; - cursor: move; -} -.drag_handle span { - width: 3px; - height: 3px; - display: block; - background: #bac7d4; - margin: 1px 0 2px 0; -} -.date_key { - width: 120px; - float: left; - margin-right: 10px; - position: relative; -} -.date_key:after { - content: ":"; - position: absolute; - left: 123px; - top: 4px; - font-size: 12px; - font-weight: bold; -} -.date_value { - width: 80px; - float: left; - position: relative; -} -.entry_settings { - width: 150px; - background: white; - line-height: 1.0; - position: absolute !important; - top: 24px; - right: -13px; - z-index: 30; - display: none; - margin-right: 0 !important; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.8); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.8); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.8); -} -.entry_settings > ul { - margin: 0; - padding: 0; -} -.entry_settings > ul li { - list-style-type: none; -} -.entry_settings .trash_dark-img { - right: 4px; -} -.entry_settings ul { - padding: 10px 0 10px 0; -} -.entry_settings li { - font-size: 12px; - padding: 8px 10px; - display: block; - cursor: pointer; -} -.entry_settings li:hover { - background: #e0e6eb; -} -.entry_settings_arrow { - position: relative; - background: #f9fafb; -} -.entry_settings_arrow:after { - top: -11px; - right: 19px; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(136, 183, 213, 0); - border-bottom-color: #f9fafb; - border-width: 7px; - margin-left: -3px; -} -.epb_content_wrap { - display: table; - min-width: 696px; - margin-left: 30px; - margin-right: 45px; - min-height: 100px; - background: #f3f5f7; - border: solid 1px #aabbca; -} -.handsontable th { - background: #d9e1e8; - font-size: 12px; - color: #4b6277; -} -.handsontable th, -.handsontable td { - border-right: 1px solid #cad4de; - border-bottom: 1px solid #cad4de; -} -.handsontable tr:first-child th, -.handsontable tr:first-child td { - border-top: 1px solid #cad4de; -} -.handsontable th:first-child, -.handsontable td:first-child, -.handsontable .htNoFrame + th, -.handsontable .htNoFrame + td { - border-left: 1px solid #cad4de; -} -div.dd_entry_cell { - border: 1px solid #d9e1e8; - -webkit-transition: border 0.2s ease; - -moz-transition: border 0.2s ease; - -o-transition: border 0.2s ease; - transition: border 0.2s ease; -} -div.dd_entry_cell:hover { - border: 1px solid #3babe9; -} -div.dd_entry_cell:hover .button_wrapper { - display: block; -} -#button_add_entry.drop_active, -.drop_active { - background-color: #d8f1ff; -} -#button_add_entry.drop_hover, -.drop_hover { - background: #69bfee; -} -.settings_button span { - margin-top: 10px; - display: block; -} -.edit_button span { - margin: 5px 0 0 12px; -} -.drag_button span { - margin: 3px 0 0 10px; -} -.drag_button:active { - -webkit-box-shadow: inset 0 0 0 rgba(55, 72, 88, 0) !important; - -moz-box-shadow: inset 0 0 0 rgba(55, 72, 88, 0) !important; - box-shadow: inset 0 0 0 rgba(55, 72, 88, 0) !important; -} -.cancel_button span { - margin: 5px 0 0 12px; -} -.save_button span { - margin: 2px 0 0 10px; -} -.button_wrapper { - position: absolute; - right: -1px; - top: -1px; - display: none; - border: solid 1px #cad4de; - z-index: 8; - -webkit-box-shadow: -2px 1px 1px rgba(55, 72, 88, 0.1) !important; - -moz-box-shadow: -2px 1px 1px rgba(55, 72, 88, 0.1) !important; - box-shadow: -2px 1px 1px rgba(55, 72, 88, 0.1) !important; -} -.button_wrapper .more_options_panel { - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4) !important; - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4) !important; - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4) !important; - border: 0; -} -.button_wrapper .more_options_item { - min-width: 140px; -} -.more_options_panel.in_block { - right: -1px; - top: 36px; - padding: 10px 0 10px 0; - background-color: #e6ebef; -} -.more_options_item_remove_block_element span { - float: left; -} -.more_options_item { - padding: 6px; -} -.more_options_item:hover { - background: #f9fafb; -} -/********* -* tables * -**********/ -.htContextMenu table.htCore { - outline: 1px solid #d9e1e8; - line-height: 1.0; - -webkit-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4); - -moz-box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4); - box-shadow: 0 2px 4px rgba(55, 72, 88, 0.4); -} -.htContextMenu table tbody tr td { - font-size: 12px; - color: #4b6277; - background: #e9edf1; -} -.htContextMenu table tbody tr td:hover { - background: #f9fafb; -} -.htContextMenu table tbody tr td.current { - background: #f9fafb; -} -.htContextMenu table tbody tr td.htSeparator { - border-top: 1px solid #cad4de; -} -/**************** -* media queries * -****************/ -@media (max-height: 750px) { - .filter_dropdown { - max-height: 460px; - } -} -@media (max-width: 1750px) { - .entry_name_menu li { - max-width: 400px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } -} -@media (max-width: 1380px) { - .entry_name_menu li { - max-width: 190px; - } - .entry_menus > ul > li { - width: 174px; - } - .entry_menu_list { - width: 138px; - } -} -@media (max-width: 1100px) { - .author_name { - width: auto; - margin-right: 20px; - } - .author_firstname, - .author_lastname { - width: 100px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } -} -@media (max-width: 970px) { - .page_title { - margin-top: 2px; - font-size: 12px; - } - .plus_btn_wrap { - width: 130px; - } - .author_firstname, - .author_lastname { - width: 66px; - } - .entry_menus > ul > li { - width: 120px; - } - .entry_menu_list { - width: 84px; - } - .entry_menu_list li span:first-child { - display: block; - float: none; - } - .entry_tags { - width: 84px; - } - .entry_tags > span { - max-width: 84px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} -@media (max-width: 870px) { - .entry_name_menu li { - max-width: 90px; - } -} - diff --git a/unittests/example_labfolder_data/static/css/pixel_icon.css b/unittests/example_labfolder_data/static/css/pixel_icon.css deleted file mode 100644 index 50aed1d7..00000000 --- a/unittests/example_labfolder_data/static/css/pixel_icon.css +++ /dev/null @@ -1,570 +0,0 @@ -/************** -* basic.css * -**************/ -/********** -* colors * -***********/ -/********** -* helper * -***********/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -/********* -* icons * -**********/ -.icon_source { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; -} -.logo-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -6px -10px; - width: 130px; - height: 30px; - margin: 16px 0 0 22px; -} -.author_only-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -140px -3px; - width: 15px; - height: 15px; -} -.add_text-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -161px -3px; - width: 22px; - height: 15px; -} -.add_text-img:hover { - background-position: -161px -31px; -} -.add_text-img:active { - margin-top: 1px; -} -.add_sketch-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -190px -3px; - width: 22px; - height: 15px; -} -.add_sketch-img:hover { - background-position: -190px -31px; -} -.add_sketch-img:active { - margin-top: 1px; -} -.add_table-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -218px -3px; - width: 23px; - height: 15px; -} -.add_table-img:hover { - background-position: -218px -31px; -} -.add_table-img:active { - margin-top: 1px; -} -.add_upload-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -942px -3px; - width: 18px; - height: 15px; -} -.add_upload-img:hover { - background-position: -942px -31px; -} -.add_upload-img:active { - margin-top: 1px; -} -.add_import-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -246px -3px; - width: 23px; - height: 15px; -} -.add_import-img:hover { - background-position: -246px -31px; -} -.add_import-img:active { - margin-top: 1px; -} -.wheel-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -282px -3px; - width: 15px; - height: 15px; -} -.wheel-img:hover { - background-position: -282px -31px; -} -.arrow_down-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -303px -3px; - width: 15px; - height: 15px; - cursor: pointer; -} -.arrow_down-img:hover { - background-position: -303px -31px; -} -.arrow_up-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -327px -3px; - width: 15px; - height: 15px; - cursor: pointer; -} -.arrow_up-img:hover { - background-position: -327px -31px; -} -.comment-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -348px -3px; - width: 19px; - height: 19px; -} -.comment-img:hover { - background-position: -348px -31px; -} -.todo-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1085px -4px; - width: 14px; - height: 13px; -} -.project-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -375px -3px; - width: 16px; - height: 16px; - margin-top: 6px !important; -} -/* .project-img:hover{ */ -/* background-position: -375px -31px; */ -/* } */ -.manage-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -400px -2px; - width: 20px; - height: 20px; -} -.manage_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1050px -35px; - width: 10px; - height: 10px; - margin-top: 2px; -} -.desk-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -428px -3px; - width: 16px; - height: 16px; - margin-top: 6px !important; -} -.desk_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1067px -35px; - width: 10px; - height: 10px; - margin-top: 3px; -} -.template_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -796px -3px; - width: 10px; - height: 16px; -} -.bell-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -454px -1px; - width: 22px; - height: 22px; -} -.bell-img:hover { - background-position: -454px -29px; -} -.search-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -488px -1px; - width: 26px; - height: 23px; -} -.search-img:hover { - background-position: -488px -29px; -} -.avatar-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -522px 1px; - width: 16px; - height: 22px; -} -.avatar_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -837px -37px; - width: 8px; - height: 10px; - margin-top: 4px; -} -.group-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -853px -35px; - width: 20px; - height: 13px; - margin-top: 3px; -} -.arrow_down_s-img { - position: relative; - background: transparent; -} -.arrow_down_s-img:after { - top: 100%; - left: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(213, 213, 213, 0); - border-top-color: #374858; - border-width: 4px; - margin-left: -4px; -} -.arrow_down_s-img:hover { - background-position: -691px -39px; -} -.close_x-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -895px -8px; - width: 10px; - height: 9px; -} -.feedback-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -912px -2px; - width: 10px; - height: 61px; -} -.invite-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -925px -2px; - width: 10px; - height: 52px; -} -.pending-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1011px -9px; - width: 17px; - height: 10px; -} -.single_tag_img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -970px -5px; - width: 12px; - height: 14px; -} -.root_tag_img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -986px -4px; - width: 19px; - height: 15px; -} -.menu_arrow-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -853px -7px; - width: 14px; - height: 11px; -} -.folder_up-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -738px -3px; - width: 24px; - height: 15px; -} -.folder_dn-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -764px -5px; - width: 24px; - height: 13px; -} -.project_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -814px -5px; - width: 12px; - height: 14px; -} -.notebook_s-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -1035px -34px; - width: 10px; - height: 12px; - margin-top: 2px; -} -.edit-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -659px -7px; - width: 11px; - height: 10px; -} -.trash_dark-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -631px -5px; - width: 10px; - height: 13px; -} -.trash-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -646px -4px; - width: 10px; - height: 13px; -} -.trash-img:hover { - background-position: -631px -4px; -} -.edit_light-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -674px -7px; - width: 11px; - height: 10px; -} -.edit_light-img:hover { - background-position: -659px -7px; -} -.edit_light-img:active { - margin-top: 1px; - margin-bottom: -1px; -} -.arrow_menu_dn-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -729px -11px; - width: 9px; - height: 5px; -} -.arrow_menu_dn-img:hover { - background-position: -729px -39px; -} -.arrow_menu_up-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -716px -11px; - width: 9px; - height: 5px; -} -.arrow_menu_up-img:hover { - background-position: -716px -39px; -} -.close_box-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - float: right; - margin: 0; - background-position: -546px -5px; - width: 17px; - height: 15px; - cursor: pointer; -} -.close_box-img:hover { - background-position: -546px -33px; -} -.close_box-img:active { - -webkit-box-shadow: 0 0 5px #ffffff; - -moz-box-shadow: 0 0 5px #ffffff; - box-shadow: 0 0 5px #ffffff; - background-position: -546px -5px; -} -.save-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - margin: 0; - background-position: -585px -5px; - width: 15px; - height: 15px; - cursor: pointer; -} -.drag-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - margin: 0; - background-position: -608px -5px; - width: 15px; - height: 15px; - cursor: pointer; -} -.close_dark_x-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -569px -8px; - width: 10px; - height: 9px; -} -.edit_dark-img { - background-image: url("../img/labfolder_icons.png"); - background-repeat: no-repeat; - margin-right: 5px; - float: left; - background-position: -659px -7px; - width: 11px; - height: 10px; -} - diff --git a/unittests/example_labfolder_data/static/css/redactor.css b/unittests/example_labfolder_data/static/css/redactor.css deleted file mode 100644 index fa4e0dd5..00000000 --- a/unittests/example_labfolder_data/static/css/redactor.css +++ /dev/null @@ -1,1112 +0,0 @@ -/* - Icon font -*/ -@font-face { - font-family: 'RedactorFont'; - src: url('../font/redactor-font.eot'); -} -@font-face { - font-family: 'RedactorFont'; - src: url(data:application/x-font-ttf;charset=utf-8;base64,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) format('truetype'), url(data:application/font-woff;charset=utf-8;base64,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) format('woff'); - font-weight: normal; - font-style: normal; -} -/* =Selection ------------------------------------------------------------------------------*/ -.redactor_box ::selection { - background: #ffff9e; -} -.redactor_box ::-moz-selection { - background: #ffff9e; -} -.redactor_box img::selection { - background: transparent; -} -.redactor_box img::-moz-selection { - background: transparent; -} -/* - BOX -*/ -.redactor_box { - position: relative; - overflow: visible; - background: #fff; - z-index: 1 !important; /*Labfolder fix*/ -} -.redactor_box iframe { - display: block; - margin: 0; - padding: 0; - border: 1px solid #eee; -} -.redactor_box textarea { - position: relative; - display: block; - overflow: auto; - margin: 0; - padding: 0; - width: 100%; - outline: none; - border: none; - background-color: #222; - box-shadow: none; - color: #ccc; - font-size: 13px; - font-family: Menlo, Monaco, monospace, sans-serif; - resize: none; -} -.redactor_box textarea:focus { - outline: none; -} -.redactor_box, -.redactor_box textarea { - z-index: auto !important; -} -.redactor_box_fullscreen { - z-index: 99 !important; -} -#redactor_modal_overlay, -#redactor_modal, -.redactor_dropdown { - z-index: 100 !important; -} -/* - AIR - -*/ -body .redactor_air { - position: absolute; - z-index: 502; -} -/* - FULLSCREEN -*/ -body .redactor_box_fullscreen { - position: fixed; - top: 0; - left: 0; - width: 100%; -} -/* - LINK TOOLTIP -*/ -.redactor-link-tooltip { - position: absolute; - z-index: 49999; - padding: 10px; - line-height: 1; - display: inline-block; - background-color: #000; - color: #555 !important; -} -.redactor-link-tooltip, -.redactor-link-tooltip a { - font-size: 12px; - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; -} -.redactor-link-tooltip a { - color: #ccc; - margin: 0 5px; - text-decoration: none; -} -.redactor-link-tooltip a:hover { - color: #fff; -} -/* - IMAGE BOX -*/ -#redactor-image-box img { - width: 100%; -} -.redactor_editor { - position: relative; - overflow: auto; - margin: 0 !important; - padding: 10px 20px; - padding-bottom: 5px; - outline: none; - background: none; - background: #fff; - box-shadow: none !important; - white-space: normal; - border: 1px solid #eee; - vertical-align: baseline !important; - /*labfolder fix, vertical align*/ -} -.redactor_editor:focus { - outline: none; -} -.redactor_editor div, -.redactor_editor p, -/*removed because pre wrap causes double line jump in lists*/ -/*.redactor_editor ul, -.redactor_editor ol,*/ -.redactor_editor table, -.redactor_editor dl, -.redactor_editor blockquote, -.redactor_editor pre, -.redactor_editor h1, -.redactor_editor h2, -.redactor_editor h3, -.redactor_editor h4, -.redactor_editor h5, -.redactor_editor h6 { - overflow-wrap: break-word; /*labfolder fix*/ - word-wrap: break-word; /*labfolder fix*/ - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; -} -.redactor_editor code, -.redactor_editor pre { - font-family: Menlo, Monaco, monospace, sans-serif; -} -.redactor_editor div, -.redactor_editor p, -.redactor_editor ul, -.redactor_editor ol, -.redactor_editor table, -.redactor_editor dl, -.redactor_editor blockquote, -.redactor_editor pre { - font-size: 14px; - line-height: 1.6em; -} -.redactor_editor p { -/* min-height: 22px; labfolder fix */ -} -.redactor_editor a { -/* labfolder fix, removed !important on both */ - color: #15c; - text-decoration: underline; -} -.redactor_editor .redactor_placeholder { - color: #999 !important; - display: block !important; -} -/* - TYPOGRAPHY -*/ -.redactor_editor object, -.redactor_editor embed, -.redactor_editor video, -.redactor_editor img { - max-width: 100%; - width: auto; -} -.redactor_editor video, -.redactor_editor img { - height: auto; -} -.redactor_editor div, -.redactor_editor p, -.redactor_editor ul, -.redactor_editor ol, -.redactor_editor table, -.redactor_editor dl, -.redactor_editor blockquote, -.redactor_editor pre { - margin: 0; - margin-bottom: 10px !important; - border: none; - background: none !important; - box-shadow: none !important; -} -.redactor_editor iframe, -.redactor_editor object, -.redactor_editor hr { - margin-bottom: 15px !important; -} -.redactor_editor blockquote { - margin-left: 1.5em !important; - padding-left: 0 !important; - color: #777; - font-style: italic !important; -} -.redactor_editor ul, -.redactor_editor ol { - padding-left: 2em !important; -} -.redactor_editor ul ul, -.redactor_editor ol ol, -.redactor_editor ul ol, -.redactor_editor ol ul { - margin: 2px !important; - padding: 0 !important; - padding-left: 2em !important; - border: none; -} -.redactor_editor dl dt { - font-weight: bold; -} -.redactor_editor dd { - margin-left: 1em; -} -.redactor_editor table { - border-collapse: collapse; - font-size: 1em !important; -} -.redactor_editor table td { - padding: 5px !important; - border: 1px solid #ddd; - vertical-align: top; -} -.redactor_editor table thead td { - border-bottom: 2px solid #000 !important; - font-weight: bold !important; -} -.redactor_editor code { - background-color: #d8d7d7 !important; -} -.redactor_editor pre { - overflow: auto; - padding: 1em !important; - border: 1px solid #ddd !important; - border-radius: 3px !important; - background: #f8f8f8 !important; - white-space: pre; - font-size: 90% !important; -} -.redactor_editor hr { - display: block; - height: 1px; - border: 0; - border-top: 1px solid #ccc; -} -/* - HEADERS -*/ -.redactor_editor h1, -.redactor_editor h2, -.redactor_editor h3, -.redactor_editor h4, -.redactor_editor h5, -.redactor_editor h6 { - margin-top: 0 !important; - padding: 0 !important; - background: none; - color: #000; - font-weight: bold; -} -.redactor_editor h1 { - font-size: 36px !important; - line-height: 1.111em !important; - margin-bottom: .15em !important; -} -.redactor_editor h2 { - font-size: 30px !important; - line-height: 1.111em !important; - margin-bottom: .25em !important; -} -.redactor_editor h3 { - font-size: 24px !important; - line-height: 1.333em !important; - margin-bottom: .2em !important; -} -.redactor_editor h4 { - font-size: 18px !important; - line-height: 1.5em !important; - margin-bottom: .2em !important; -} -.redactor_editor h5 { - font-size: 1em !important; - line-height: 1.6em !important; - margin-bottom: .25em !important; -} -.redactor_editor h6 { - font-size: .8em !important; - line-height: 1.6em !important; - text-transform: uppercase; - margin-bottom: .3em !important; -} -/* - TOOLBAR -*/ -.redactor_toolbar { - position: relative; - top: 0; - left: 0; - margin: 0 !important; - padding: 0; /*"labfolder hack, was !important*/ - list-style: none !important; - font-size: 14px !important; - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; - line-height: 1 !important; - background: #fff; - border: none; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); - z-index: 3; -} -.redactor_toolbar:after { - content: ""; - display: table; - clear: both; -} -.redactor_toolbar.redactor-toolbar-overflow { - overflow-y: auto; - height: 29px; - white-space: nowrap; -} -.redactor_toolbar.redactor-toolbar-external { - z-index: 999; - box-shadow: none; - border: 1px solid rgba(0, 0, 0, 0.1); -} -body .redactor_air .redactor_toolbar { - padding-right: 2px !important; -} -.redactor_toolbar li { - vertical-align: top; - display: inline-block; - margin: 0 !important; - padding: 0 !important; - outline: none; - list-style: none !important; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; -} -.redactor_toolbar li a { - display: block; - color: #333; - text-align: center; - /*labfolder padding: 9px 10px; */ - padding: 10px 10px; - outline: none; - border: none; - text-decoration: none; - cursor: pointer; - zoom: 1; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; -} -.redactor_toolbar li a:hover { - outline: none; - background-color: #1f78d8; - color: #fff; -} -.redactor_toolbar li a:hover i:before { - color: #fff; -} -.redactor_toolbar li a:active, -.redactor_toolbar li a.redactor_act { - outline: none; - background-color: #ccc; - color: #444; -} -.redactor_toolbar li a.redactor-btn-image { - width: 14px; - height: 14px; - background-position: center center; - background-repeat: no-repeat; -} -.redactor_button_disabled { - filter: alpha(opacity=30); - -moz-opacity: 0.3; - opacity: 0.3; -} -.redactor_button_disabled:hover { - outline: none; - background-color: transparent !important; - cursor: default; -} -.redactor_toolbar li a.fa-redactor-btn { - display: inline-block; - padding: 9px 10px 8px 10px; - line-height: 1; -} -.redactor_toolbar.redactor-toolbar-typewriter { - box-shadow: none; - background: rgba(240, 240, 240, 0.9); -} -.redactor_toolbar.redactor-toolbar-typewriter li a:hover { - outline: none; - background-color: #1f78d8; - color: #fff; -} -.redactor_toolbar.redactor-toolbar-typewriter li a:active, -.redactor_toolbar.redactor-toolbar-typewriter li a.redactor_act { - outline: none; - background-color: #ccc; - color: #444; -} -.re-icon { - font-family: 'RedactorFont'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.re-icon i:before { - position: relative; - font-size: 14px; -} -.re-video:before { - content: "\e600"; -} -.re-unorderedlist:before { - content: "\e601"; -} -.re-undo:before { - content: "\e602"; -} -.re-underline:before { - content: "\e603"; -} -.re-textdirection:before { - content: "\e604"; -} -.re-fontcolor:before { - content: "\e605"; -} -.re-table:before { - content: "\e606"; -} -.re-redo:before { - content: "\e607"; -} -.re-quote:before { - content: "\e608"; -} -.re-outdent:before { - content: "\e609"; -} -.re-orderedlist:before { - content: "\e60a"; -} -.re-link:before { - content: "\e60b"; -} -.re-horizontalrule:before { - content: "\e60c"; -} -.re-italic:before { - content: "\e60d"; -} -.re-indent:before { - content: "\e60e"; -} -.re-image:before { - content: "\e60f"; -} -.re-fullscreen:before { - content: "\e610"; -} -.re-normalscreen:before { - content: "\e611"; -} -.re-formatting:before { - content: "\e612"; -} -.re-fontsize:before { - content: "\e613"; -} -.re-fontfamily:before { - content: "\e614"; -} -.re-deleted:before { - content: "\e615"; -} -.re-html:before { - content: "\e616"; -} -.re-clips:before { - content: "\e617"; -} -.re-bold:before { - content: "\e618"; -} -.re-backcolor:before { - content: "\e619"; -} -.re-file:before { - content: "\e61a"; -} -.re-alignright:before { - content: "\e61b"; -} -.re-alignment:before, -.re-alignleft:before { - content: "\e61c"; -} -.re-alignjustify:before { - content: "\e61d"; -} -.re-aligncenter:before { - content: "\e61e"; -} -.re-gallery:before { - content: "\e61f"; -} -/* - Toolbar classes -*/ -.redactor_format_blockquote { - padding-left: 10px; - color: #666 !important; - font-style: italic; -} -.redactor_format_pre { - font-family: monospace, sans-serif; -} -.redactor_format_h1, -.redactor_format_h2, -.redactor_format_h3, -.redactor_format_h4, -.redactor_format_h5 { - font-weight: bold; -} -.redactor_format_h1 { - font-size: 30px; - line-height: 36px; -} -.redactor_format_h2 { - font-size: 24px; - line-height: 36px; -} -.redactor_format_h3 { - font-size: 20px; - line-height: 30px; -} -.redactor_format_h4 { - font-size: 16px; - line-height: 26px; -} -.redactor_format_h5 { - font-size: 14px; - line-height: 23px; -} -.redactor-toolbar-typewriter .redactor_dropdown .redactor_format_h1, -.redactor-toolbar-typewriter .redactor_dropdown .redactor_format_h2, -.redactor-toolbar-typewriter .redactor_dropdown .redactor_format_h3, -.redactor-toolbar-typewriter .redactor_dropdown .redactor_format_h4, -.redactor-toolbar-typewriter .redactor_dropdown .redactor_format_h5 { - font-size: 1em; - line-height: 1.6em; - text-transform: uppercase; -} -.redactor-toolbar-typewriter .redactor_dropdown .redactor_format_h2 { - font-size: .85em; -} -/* - Typewriter -*/ -.redactor_editor.redactor-editor-typewriter { - background: #f5f5f5 !important; - padding: 25px 50px !important; -} -.redactor_editor.redactor-editor-typewriter div, -.redactor_editor.redactor-editor-typewriter p, -.redactor_editor.redactor-editor-typewriter ul, -.redactor_editor.redactor-editor-typewriter ol, -.redactor_editor.redactor-editor-typewriter table, -.redactor_editor.redactor-editor-typewriter dl, -.redactor_editor.redactor-editor-typewriter blockquote, -.redactor_editor.redactor-editor-typewriter pre, -.redactor_editor.redactor-editor-typewriter h1, -.redactor_editor.redactor-editor-typewriter h2, -.redactor_editor.redactor-editor-typewriter h3, -.redactor_editor.redactor-editor-typewriter h4, -.redactor_editor.redactor-editor-typewriter h5, -.redactor_editor.redactor-editor-typewriter h6 { - font-family: 'Courier New', 'Lucida Console', Consolas, Monaco, monospace, sans-serif; - font-size: 18px !important; - line-height: 1.5em !important; - margin-bottom: 1.5em !important; -} -.redactor_editor.redactor-editor-typewriter h2 { - font-size: 14px !important; -} -.redactor_editor.redactor-editor-typewriter h1, -.redactor_editor.redactor-editor-typewriter h2, -.redactor_editor.redactor-editor-typewriter h3, -.redactor_editor.redactor-editor-typewriter h4, -.redactor_editor.redactor-editor-typewriter h5, -.redactor_editor.redactor-editor-typewriter h6 { - text-transform: uppercase; -} -.redactor_editor.redactor-editor-typewriter a { - color: #000 !important; - text-decoration: underline !important; -} -/* - WYM -*/ -.redactor_editor.redactor_editor_wym { - padding: 10px 7px 0 7px !important; - background: #f6f6f6 !important; -} -.redactor_editor.redactor_editor_wym div, -.redactor_editor.redactor_editor_wym p, -.redactor_editor.redactor_editor_wym ul, -.redactor_editor.redactor_editor_wym ol, -.redactor_editor.redactor_editor_wym table, -.redactor_editor.redactor_editor_wym dl, -.redactor_editor.redactor_editor_wym pre, -.redactor_editor.redactor_editor_wym h1, -.redactor_editor.redactor_editor_wym h2, -.redactor_editor.redactor_editor_wym h3, -.redactor_editor.redactor_editor_wym h4, -.redactor_editor.redactor_editor_wym h5, -.redactor_editor.redactor_editor_wym h6, -.redactor_editor.redactor_editor_wym blockquote { - margin-top: 0; - margin-bottom: 5px !important; - padding: 10px !important; - border: 1px solid #e4e4e4 !important; - background-color: #fff !important; - z-index: 0; -} -.redactor_editor.redactor_editor_wym blockquote:before { - content: ''; -} -.redactor_editor.redactor_editor_wym img { - position: relative; - z-index: 1; -} -.redactor_editor.redactor_editor_wym div { - border: 1px dotted #aaa !important; -} -.redactor_editor.redactor_editor_wym pre { - border: 2px dashed #e4e4e4 !important; - background-color: #f8f8f8 !important; -} -.redactor_editor.redactor_editor_wym ul, -.redactor_editor.redactor_editor_wym ol { - padding-left: 2em !important; -} -.redactor_editor.redactor_editor_wym ul li ul, -.redactor_editor.redactor_editor_wym ol li ul, -.redactor_editor.redactor_editor_wym ul li ol, -.redactor_editor.redactor_editor_wym ol li ol { - border: none !important; -} -/* - DROPDOWN -*/ -.redactor_dropdown { - position: absolute; - top: 28px; - left: 0; - padding: 10px; - width: 200px; - background-color: #fff; - box-shadow: 0 1px 5px #bbb; - font-size: 13px; - font-family: Helvetica, Arial, Verdana, Tahoma, sans-serif; - line-height: 21px; -} -.redactor-toolbar-typewriter .redactor_dropdown { - font-family: 'Courier New', 'Lucida Console', Consolas, Monaco, monospace, sans-serif; - background-color: #f5f5f5; -} -.redactor_separator_drop { - padding: 0 !important; - border-top: 1px solid #ddd; - font-size: 0; - line-height: 0; -} -.redactor_dropdown a { - display: block; - padding: 3px 5px; - color: #000; - text-decoration: none; -} -.redactor_dropdown a:hover { - background-color: #dde4ef; - color: #444 !important; - text-decoration: none; -} -/* - MODAL -*/ -#redactor_modal_overlay { - position: fixed; - top: 0; - left: 0; - margin: auto; - width: 100%; - height: 100%; - background-color: #000 !important; - filter: alpha(opacity=30); - -moz-opacity: 0.3; - opacity: 0.3; -} -#redactor_modal { - position: fixed; - top: 50%; - left: 50%; - padding: 0; - background: #fff; - color: #000; - font-size: 12px !important; - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; - box-shadow: 0 1px 10px rgba(0, 0, 0, 0.5); -} -#redactor_modal header { - padding: 20px 30px 5px 30px; - font-size: 16px; -} -#redactor_modal section { - padding: 20px 30px; -} -#redactor_modal label { - display: block !important; - float: none !important; - margin: 10px 0 3px 0 !important; - padding: 0 !important; - font-size: 12px !important; -} -#redactor_modal footer:after { - content: ""; - display: table; - clear: both; -} -#redactor_modal footer div { - float: left; -} -#redactor_modal input[type="radio"], -#redactor_modal input[type="checkbox"] { - position: relative; - top: -1px; -} -#redactor_modal input[type="text"], -#redactor_modal input[type="password"], -#redactor_modal input[type="email"], -#redactor_modal textarea { - position: relative; - z-index: 2; - margin: 0; - padding: 1px 2px; - height: 23px; - border: 1px solid #ccc; - border-radius: 1px; - background-color: white; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) inset; - color: #333; - font-size: 13px; - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; - line-height: 1; - -moz-transition: border 0.3s ease-in; - transition: border 0.3s ease-in; -} -#redactor_modal textarea { - display: block; - margin-top: 4px; - line-height: 1.4em; -} -#redactor_modal input:focus, -#redactor_modal textarea:focus { - outline: none; - border-color: #5ca9e4; - box-shadow: 0 0 0 2px rgba(70, 161, 231, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2) inset; -} -#redactor_modal_close { - position: absolute; - top: 5px; - right: 3px; - width: 20px; - height: 20px; - color: #999; - font-size: 26px; - cursor: pointer; -} -#redactor_modal_close:hover { - color: #000; -} -.redactor_input { - width: 99%; - font-size: 14px; -} -.redactor_modal_box { - overflow: auto; - margin-bottom: 10px; - height: 350px; -} -#redactor_image_box { - overflow: auto; - margin-bottom: 10px; - height: 270px; -} -#redactor_image_box_select { - display: block; - margin-bottom: 15px !important; - width: 200px; -} -#redactor_image_box img { - margin-right: 10px; - margin-bottom: 10px; - max-width: 100px; - cursor: pointer; -} -#redactor_tabs { - margin-bottom: 18px; -} -#redactor_tabs a { - display: inline-block; - margin-right: 2px; - padding: 4px 14px; - border: 1px solid #d2d2d2; - border-radius: 3px; - background: #fff; - color: #000; - text-decoration: none; - line-height: 1; -} -#redactor_tabs a:hover, -#redactor_tabs a.redactor_tabs_act { - border-color: #eee; - color: #999 !important; - text-decoration: none !important; -} -.redactor_modal_btn_hidden { - display: none; -} -#redactor_modal footer button { - position: relative; - width: 100%; - padding: 10px 16px; - margin: 0; - outline: none; - border: none; - background-color: #ddd; - color: #000; - text-align: center; - text-decoration: none; - font-weight: normal; - font-size: 12px; - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; - line-height: 1; - cursor: pointer; -} -#redactor_modal footer button:hover { - color: #777; - background: none; - background: #bbb; - text-decoration: none; -} -#redactor_modal footer button.redactor_modal_delete_btn { - background: none; - color: #fff; - background-color: #b52525; -} -#redactor_modal footer button.redactor_modal_delete_btn:hover { - color: rgba(255, 255, 255, 0.6); - background-color: #881b1b; -} -#redactor_modal footer button.redactor_modal_action_btn { - background: none; - color: #fff; - background-color: #2461b5; -} -#redactor_modal footer button.redactor_modal_action_btn:hover { - color: rgba(255, 255, 255, 0.6); - background-color: #1a4580; -} -/* Drag and Drop Area */ -.redactor_droparea { - position: relative; - margin: auto; - margin-bottom: 5px; - width: 100%; -} -.redactor_droparea .redactor_dropareabox { - position: relative; - z-index: 1; - padding: 60px 0; - width: 99%; - border: 1px dashed #ddd; - background: #fff; - text-align: center; -} -.redactor_droparea .redactor_dropareabox, -.redactor_dropalternative { - color: #555; - font-size: 12px; -} -.redactor_dropalternative { - margin: 4px 0 2px 0; -} -.redactor_dropareabox.hover { - border-color: #aaa; - background: #efe3b8; -} -.redactor_dropareabox.error { - border-color: #dcc3c3; - background: #f7e5e5; -} -.redactor_dropareabox.drop { - border-color: #e0e5d6; - background: #f4f4ee; -} -/* =ProgressBar ------------------------------------------------------------------------------*/ -#redactor-progress { - position: fixed; - top: 0; - left: 0; - width: 100%; - z-index: 1000000; - height: 10px; -} -#redactor-progress span { - display: block; - width: 100%; - height: 100%; - background-color: #3d58a8; - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent); - -webkit-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; - background-size: 40px 40px; -} -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@-o-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} - -/* CUSTOM labfolder*/ - -.re-orderedlist, -.re-mendeley, -.re-alignjustify, -.re-lf-fontfamily, -.re-link, -.re-deleted, -.re-backcolor, -.re-lf-fontsize, -.re-redo { - border-right: 1px solid #d2d2d2 !important; -} - -a.re-lf-fontsize { - font-family: "Arial"; - width: 35px !important; -} - -.re-lf-fontfamily { - font-size: 14px; - overflow: hidden; - padding: 11px 9px 9px !important; - text-align: left !important; - text-overflow: ellipsis; - white-space: nowrap; - width: 75px !important; -} - -.redactor_arial_font { - font-family: 'Arial'; -} - -.redactor_arial_font:before { - content: "Arial"; -} - -.redactor_times_font { - font-family: 'Times new roman'; -} - -.redactor_times_font:before { - content: "Times New Roman"; -} - -.redactor_dropdown_box_specialChars a{ - display: inline-block; - height: 13px; - line-height: 13px; - margin: 1px; - text-align: center; - width: 13px; - word-break: break-all; -} - -a.char_section { - background: #DDD; - border: 1px solid #FFF; - color: #000; - display: block; - font-weight: bold; - height: 22px; - line-height: 13px; - margin: 0; - text-align: left; - width: 190px; -} - -/*a.char_section:hover { - color: #FFF !important; - background-color: #374858 !important; -}*/ - -.redactor_editor div.redactor_placeholder_container, -.redactor_editor div.redactor_placeholder_container:hover{ - border: 1px solid #AAA; - border-radius: 5px; - color: #374858; - display: inline-block; - margin: 0 !important; - padding: 2px 5px; - text-decoration: none; - background: linear-gradient(to bottom, #f1f1f1 0%,#e2e2e2 100%) !important; - user-select: none; -} - -.redactor_editor div.redactor_placeholder_input{ - background: #FFF !important; - border: 1px solid #DDD; - box-shadow: inset 0 0 2px #000; - color: #374858; - display: block; - min-width: 50px; - padding: 1px 5px; - font-size: 15px; - border-radius: 3px; - line-height: 15px; - margin: 0px 5px !important; - text-align: center; - text-decoration: none; -} - -.redactor_editor div.not_edited{ - color: #888; -} - -.redactor_editor .default_textfield p{ - line-height: 1em; - color: #374858; -} - -.redactor_toolbar li a.redactor_shortcut { - border-color: #b5b5b5; - background-color: #ddd; -} - -.tab:before { - content: "\0009"; -} diff --git a/unittests/example_labfolder_data/static/css/tree.css b/unittests/example_labfolder_data/static/css/tree.css deleted file mode 100644 index 0256223a..00000000 --- a/unittests/example_labfolder_data/static/css/tree.css +++ /dev/null @@ -1,454 +0,0 @@ -/************** -* basic.css * -**************/ -/******************** -* Media variables * -********************/ -/********** -* colors * -***********/ -/*********** -* helpers * -************/ -.list_vertical > ul { - margin: 0; - padding: 0; -} -.list_vertical > ul li { - list-style-type: none; -} -.list_horizontal > ul { - margin: 0; - padding: 0; -} -.list_horizontal > ul > li { - list-style-type: none; - float: left; - position: relative; -} -/************* -* functions * -**************/ -/****** -* css * -******/ -body { - color: #374858; -} -.clearfix:after { - content: " "; - visibility: hidden; - display: block; - height: 0; - clear: both; -} -.treeInPopup .treeline { - background-repeat: no-repeat; - color: #374858; - cursor: pointer; - border: 1px solid transparent; - display: block; - font-size: 14px; - height: 21px; - line-height: 22px; - outline: none; - padding-left: 5px; - text-decoration: none; -} -/* .treeline:hover{ */ -/* background-position: 0 0; */ -/* border: 1px solid #69bfee; */ -/* text-decoration: none; */ -/* } */ -.treeline:hover .icon-arrow_down, -.treeline:hover .icon-arrow_right, -.treeline:hover .icon-folder, -.treeline:hover .icon-notebook, -.treeline:hover .icon-template, -.treeline:hover .name, -.treeline:hover .updateTS { - /* color: #69bfee; */ -} -.treeline.active { - background-color: #ededed; -} -.treeInPopup .treeline.active { - background-color: transparent; -} -.treeline.is_hidden_item > * { - opacity: 0.4; -} -.treeline img { - vertical-align: top; -} -.treeline .icon-arrow_right { - font-size: 33px; - margin-right: -10px; - margin-left: -3px; - vertical-align: -4px; -} -.treeInPopup .icon-arrow_right { - font-size: 23px; - margin-right: -6px; - line-height: 14px; - margin-left: -3px; -} -.treeline { - position: relative; -} -.treeline span { - float: left; - margin-right: 5px; -} -.treeline .icon-template { - float: left; -} -.treeInPopup .name { - font-size: 12px; - overflow: hidden; -} -.treeline .updateTS { - font-size: 15px; - float: right; - margin-right: 15px; -} -.treeline .tree_button { - float: right; - margin-top: 0; - margin-right: 10px; - position: absolute; - right: 0; - top: 1px; - opacity: 0; - transition: opacity 0.3s; - display: block; -} -.treeline:hover .tree_button { - opacity: 1; -} -.treeline_children .tree_button { - right: 116px; -} -.droppable_folder { - background-color: #e4eef7 !important; -} -.hover_droppable_folder { - background-color: #d0e1f1 !important; -} -.treeline:hover .tree_button { - display: inline; -} -.treeline.active .tree_button { - display: inline; -} -.treeline_children { - display: none; - margin-left: 15px; -} -.treeInPopup .treeline_children { - margin-left: 20px; -} -.treeline_children_empty { - font-size: 15px; - font-style: italic; - padding: 10px 0 10px 30px; -} -.treeInPopup .treeline_children_empty { - font-size: 12px; - font-style: italic; - padding: 0 0 0 25px; -} -.treeInPopupContainer { - display: none; - background: white; - box-sizing: border-box; - max-height: 150px; - margin-top: 10px; - overflow-y: auto; - -webkit-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - -moz-box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); - box-shadow: inset 0 2px 1px rgba(55, 72, 88, 0.2); -} -.treeInPopupContainer img { - display: block; - margin: auto; -} -.treeInPopup { - overflow-y: auto; - height: 148px; - padding-top: 10px; - margin-top: 2px; -} -.treeInPopup .treeline.selected { - background-color: #e6ebef; -} -.tree_my_eln_projects, -.tree_my_eln_templates { - max-width: 900px; -} -.tree_my_eln_projects .folder_dn-img, -.tree_my_eln_templates .folder_dn-img, -.tree_my_eln_projects .project_s-img, -.tree_my_eln_templates .project_s-img { - margin-top: 2px; -} -.treeline { - color: #4b6277; - background-repeat: no-repeat; - cursor: pointer; - border: 1px solid transparent; - display: block; - font-size: 14px; - height: 26px; - line-height: 20px; - outline: none; - padding: 2px 8px 2px 4px; - text-decoration: none; - transition: background 0.1s ease; -} -.treeline:hover { - background: #e0e6eb; - text-decoration: none; -} -.treeline .updateTS { - font-size: 13px; - float: right; - margin-right: 15px; -} -.treeline .tree_button { - float: right; - margin: 0 10px; -} -.treeline .tree_button button { - padding: 3px; - background: transparent; - cursor: pointer; -} -.treeline .name { - white-space: nowrap; - text-overflow: ellipsis; - display: block; - overflow: hidden; - padding: 0; - margin-left: 0; - line-height: 1.5; - float: left; -} -.treeline .icon-template { - margin-top: 3px; -} -.settings_panel { - position: absolute; - right: 10px; - background: #fdfdfd; - border: solid 1px #bac7d4; - top: 23px; - right: -58px; - display: none; - z-index: 10; - -webkit-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - -moz-box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - box-shadow: 0 4px 10px rgba(55, 72, 88, 0.3); - border: 1px solid #bac7d4; -} -.show_settings .settings_panel { - display: block; -} -.settings_panel > ul { - margin: 0; - padding: 0; -} -.settings_panel > ul li { - list-style-type: none; -} -.settings_panel .more_options_item { - min-width: 140px; - font-size: 12px; - padding-left: 5px; - cursor: pointer; -} -.settings_panel .menu_arrow-img { - position: absolute; - top: -11px; - left: 60px; -} -.settings_panel > ul > li { - padding: 2px 7px 2px 6px; - display: block; - text-align: left; - cursor: pointer; - line-height: 20px; - position: relative; -} -.settings_panel > ul > li:hover { - background: #ecf0f3; -} -.settings_panel > ul > li > span { - right: 0; - top: 3px; - position: absolute; -} -.settings_panel > ul li:first-child { - margin-top: 8px; -} -.group_more_options { - width: 200px; -} -.treeline .name { - overflow: hidden; - margin-left: 5px; - max-width: 38%; -} -.treeline .details { - color: #39A0E4; - font-size: 13px; - float: right; - margin-right: 40px; -} -@media only screen and (max-width: 1024px) { - .treeline .more_options { - opacity: 1; - right: 0; - } - .treeline .box-last-update { - margin-left: 20px; - } - .treeline .box-last-update label { - display: none; - } - .treeline .updateTS { - display: none; - } - .treeline .name { - max-width: 30%; - } - .treeline .box-owner label { - display: none; - } -} -/* Projects list tree */ -.projects-list .headers, -.templates-list .headers { - padding: 2px 8px 2px 4px; - max-width: 900px; - text-align: right; -} -.projects-list .headers div, -.templates-list .headers div { - text-align: center; - display: inline-block; -} -.projects-list .headers .owner, -.templates-list .headers .owner { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 160px; - text-align: center; - display: inline-block; - margin: 0; - padding: 0 20px; -} -.projects-list .headers .update, -.templates-list .headers .update { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 150px; - text-align: center; - display: inline-block; - margin: 0; - padding: 0 20px; -} -.projects-list .headers .created, -.templates-list .headers .created { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 150px; - text-align: center; - display: inline-block; - margin: 0; - padding: 0 20px; -} -.projects-list .details, -.templates-list .details { - margin: 0; -} -.projects-list .box-owner, -.templates-list .box-owner { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 160px; - text-align: center; - display: inline-block; - margin: 0; - padding: 0 20px; -} -.projects-list .box-owner label, -.templates-list .box-owner label { - display: none; -} -.projects-list .box-last-update, -.templates-list .box-last-update { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 150px; - text-align: center; - display: inline-block; - margin: 0; - padding: 0 20px; -} -.projects-list .box-last-update label, -.templates-list .box-last-update label { - display: none; -} -.projects-list .updateTS, -.templates-list .updateTS { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 150px; - text-align: center; - display: inline-block; - margin: 0; - padding: 0 20px; -} -.projects-list .tree_button, -.templates-list .tree_button { - right: -6px; -} -.projects-list .treeline_children .tree_button, -.templates-list .treeline_children .tree_button { - right: 132px; -} -@media only screen and (max-width: 1024px) { - .projects-list .headers .created, - .templates-list .headers .created { - display: none; - } - .projects-list .box-owner, - .templates-list .box-owner { - margin-right: 0; - } - .projects-list .updateTS, - .templates-list .updateTS { - display: none; - } - .projects-list .tree_button, - .templates-list .tree_button { - right: -10px !important; - } - .projects-list .treeline, - .templates-list .treeline, - .projects-list .headers, - .templates-list .headers { - padding-right: 25px; - } - .projects-list .name, - .templates-list .name { - max-width: 22%; - } -} diff --git a/unittests/example_labfolder_data/static/font/icons11.eot b/unittests/example_labfolder_data/static/font/icons11.eot deleted file mode 100644 index 770bd07fd2bc41d7243ae8510907ae361dc6149f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37880 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 WHWS~#bEjzhoN8Q*>c7d%Rs03~+F&aH diff --git a/unittests/example_labfolder_data/static/font/icons11.svg b/unittests/example_labfolder_data/static/font/icons11.svg deleted file mode 100644 index e0ca1099..00000000 --- a/unittests/example_labfolder_data/static/font/icons11.svg +++ /dev/null @@ -1,114 +0,0 @@ -<?xml version="1.0" standalone="no"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > -<svg xmlns="http://www.w3.org/2000/svg"> -<metadata>Generated by IcoMoon</metadata> -<defs> -<font id="icomoon" horiz-adv-x="512"> -<font-face units-per-em="512" ascent="480" descent="-32" /> -<missing-glyph horiz-adv-x="512" /> -<glyph unicode=" " d="" horiz-adv-x="256" /> -<glyph unicode="" d="M354.080 402.768c-77.872 77.824-204.080 77.824-281.952 0-77.792-77.904-77.792-204.080 0-281.936 67.136-67.216 170.24-76.272 247.28-27.568l104.784-104.784 62.176 62.176-104.72 104.8c48.672 77.024 39.584 180.128-27.568 247.312zM213.136 124.272c-75.92 0.048-137.504 61.616-137.488 137.504 0 75.968 61.536 137.504 137.456 137.472 75.968 0.080 137.568-61.504 137.504-137.504 0-75.92-61.52-137.424-137.456-137.472zM117.392 238.32v46.912h191.424v-46.912h-191.424z" horiz-adv-x="496" /> -<glyph unicode="" d="M354.080 402.768c-77.872 77.824-204.080 77.824-281.952 0-77.792-77.904-77.792-204.080 0-281.904 67.136-67.232 170.24-76.272 247.28-27.568l104.784-104.8 62.176 62.176-104.72 104.8c48.688 77.008 39.6 180.128-27.568 247.296zM213.136 124.288c-75.904 0.032-137.504 61.616-137.488 137.488 0 75.968 61.536 137.504 137.456 137.472 75.968 0.080 137.552-61.504 137.504-137.504-0.016-75.888-61.536-137.408-137.456-137.456zM117.392 238.32v46.912h72.272v72.256h46.912v-72.256h72.24v-46.912h-72.24v-72.272h-46.912v72.272h-72.272z" horiz-adv-x="496" /> -<glyph unicode="" d="M360.192 411.104c2.352-8.736 4.064-17.456 5.216-26.192 0.624-8.736 1.168-18.032 0.624-27.904 0 0-25.056 74.192-81.472 81.456-7.584 2.304-15.168 2.304-22.64 0.56-7.648-1.728-14.592-6.96-21.024-14.56l16.912-7.536-48.336-14.544-19.776 45.968 16.88-8.144c10.448 11.072 22.128 20.944 35.472 29.072 12.816 8.736 26.784 11.648 42.496 10.48 21.552-1.744 37.84-8.72 48.944-19.808 11.6-11.6 20.288-27.872 26.688-48.832v0zM360.192 351.184c32.016 0 57.632-26.192 57.632-58.176 0-31.44-25.616-57.616-57.632-57.616-31.952 0-57.6 26.176-57.6 57.616 0 31.984 25.648 58.176 57.6 58.176v0zM297.328 221.44h125.744c26.704 0 48.288-21.568 48.288-48.32v-146.032h-24.416v120.976h-26.224v-120.976h-119.824v120.976h-26.208v-120.976h-25.632v146.032c0 26.752 21.552 48.32 48.272 48.32v0zM111.152 447.776c32.048 0 57.648-25.6 57.648-57.632 0-32-25.6-57.6-57.648-57.6-31.984 0-57.632 25.6-57.632 57.6 0 32.032 25.648 57.632 57.632 57.632v0zM48.32 318.592h125.696c26.816 0 48.864-22.112 48.864-48.88v-146.048h-25.008v121.632h-26.176v-121.632h-119.904v121.632h-26.16v-121.632h-25.632v146.048c0 26.784 21.552 48.88 48.32 48.88zM66 49.824c-0.976 8.992-1.344 17.888-1.12 26.72 0.848 8.688 1.68 17.968 3.808 27.664 0 0 13.152-77.232 67.76-93.232 7.072-3.504 14.528-4.64 22.304-4.144 7.76 0.56 15.472 4.64 22.928 11.12l-15.456 10.128 49.952 6.8 12.384-48.512-15.408 10.72c-12.080-9.312-25.12-17.264-39.616-23.2-14.016-6.608-28.272-7.312-43.584-3.744-21.008 5.104-36 14.56-45.168 27.232-9.696 13.312-15.792 30.768-18.8 52.448v0z" horiz-adv-x="464" /> -<glyph unicode="" d="M218.928 480c75.712 0 136.448-60.64 136.448-135.776 0-75.072-60.736-136.416-136.448-136.416-75.088 0-135.808 61.344-135.808 136.416 0 75.12 60.72 135.776 135.808 135.776v0zM107.424 218.448c-58.864 0-107.424-48.576-107.424-107.424v-143.024h444.128v143.024c0 58.848-47.904 107.424-107.456 107.424h-28.032c-25.344-19.168-56.816-30.8-91.008-30.8-34.24 0-65.728 11.632-90.352 30.8h-19.856z" /> -<glyph unicode="" d="M198.336 291.984l-89.296 44.896 61.44 123.12c9.904 19.856 37.952 25.952 62.64 13.616v0c24.736-12.336 36.72-38.4 26.8-58.24l-61.584-123.408zM178.336 224.224l20.864-10.432 88.864 178.048-20.896 10.416-88.848-178.032zM0 2.048c5.248 6.096 12.944 14.64 21.744 24.24l-15.888 7.936c-1.984-10.832-3.968-21.68-5.856-32.176zM94.544 104.224l91.264 183.696-69.040 34.464-91.728-183.792c0 0-0.016-0.208-0.016-0.256l69.136-34.496c0.256 0.224 0.384 0.384 0.384 0.384zM23.28 129.056c-2.928-15.92-9.216-49.824-15.776-85.584l20.608-10.304c21.6 23.552 47.472 50.944 59.584 63.712l-64.416 32.176zM115.28 16.352c2.176 12.656 1.504 25.216 0.576 37.92 10.288 1.28 16.48 8.144 23.824 14.592 17.44 15.168-0.080 64.032-24.016 45.216-9.984-7.856-10.928-38-10.736-50.192-8-0.512-9.52 3.44-17.904-0.784 2.224-7.648 11.664-9.968 18.496-9.568 1.008-12.032 1.632-23.424-0.448-35.424-1.296-7.536-2.512-32.56-10.272-38.368-16.496-4.768-20.672 7.552-34.656 6.016 3.184-9.568 14.432-18.224 24.832-18.224 26.752 0 26.752 28.208 30.304 48.8zM115.28 64.672c-0.064 6.688 1.472 42.016 10.48 42.016 22.912 0 6.608-39.328-10.48-42.016zM133.2-21.712c1.2 3.072-0.016 7.392-5.552 9.568h-1.616l-2.528-2.992c-2.688-7.136 1.36-9.296 2.672-9.808l7.024 3.216zM231.408 33.36c-15.424-0.352-32.704 15.584-41.488 27.168 66.064 26.432-1.248 110-35.216 62.304 34.48 9.072 85.072-30.912 25.216-58.144 0.192 17.248-0.032 39.424-0.048 40.688l-10.368-0.112c0.464-30.336-10.352-80.848-0.048-98.976 6.704 16.24 10.16 32.928 10.336 50.048 21.68-16.944 31.376-32.096 61.136-33.376l0.512 10.336c-3.552 0.192-6.88 0.112-10.032 0.064-10.24-0.24 3.152 0.048 0 0zM254.672 36.016l-1.888 7.344-1.824-2.816 1.472 2.912c-0.96 0.48-5.712 3.28-5.728 3.296l-5.232-8.944c4.544-2.656 7.392-4.32 9.536-4.32 1.456 0 2.576 0.768 3.68 2.528zM275.424 143.104l-10.272-1.408c4.544-33.552 5.376-59.856-0.928-93.968-0.672-3.616-1.328-7.168-1.952-10.688l10.208-1.776c6.688 38.128 8.080 69.84 2.944 107.84zM306.752 120.576c17.952 22-4.272 46.8-25.104 51.6-22.256 5.168-28.464-5.808-29.248-7.424l-6.896-16.736 9.584-3.952 6.624 16.16c0.032 0.064 3.52 5.12 17.616 1.856 34.192-7.888 22.24-33.376 1.84-48 67.984-8.208 22.96-48.24-8.656-71.12l6.080-8.4c16.48 11.92 89.92 73.68 28.176 86.016zM357.776 115.088c32.512-38.336 37.136 13.168 46.016 30.544 0.192-0.304 16.48-22 21.44-20.608 4.656 7.232 6.608 14.864 5.84 22.928 11.36-45.888 62.112 21.504 29.2 31.424-24.016 7.296-40.512-14.944-39.552-35.184-12.688 19.104-19.424 12.368-29.808 0.832-2.352 1.872-5.008 2.592-7.968 2.16 15.6-59.6-12.496-7.68-32.48-12.512-5.168-1.2-17.712-45.68-18.96-50.72l10.032-2.608c3.664 11.696 10.64 22.88 16.24 33.744zM431.52 156.96c-0.784 9.264 18.752 14.608 25.76 12.48 5.728-1.728-1.856-45.072-18.528-9.2l-7.232-3.28zM434.816 54.752c26.016 0 65.104 126.64 83.024 150.016-0.912-6.352-1.504-16.016 0.288-22.592l10.016 2.704c-2.384 8.672 4.848 31.024-10.336 31.152-15.664-0.704-12.48-34.32-23.552-41.2 9.36 68.176-60.432-7.216-14.544-11.68-7.488-8.896-16.56-15.584-20.144-24.688v0c-0.592-6.704-61.52-83.712-24.752-83.712v0zM460.4 115.216c0.128-19.024-8.608-39.424-25.072-49.76-11.296 11.232 16.496 43.376 25.072 49.76 0.016-2.976-1.52-1.136 0 0zM476.816 174.224c-0.8 9.568-3.232 11.808 2.576 17.92 5.168-5.488 6.512-11.824 4.016-19.008-2.192 0.208-4.368 0.576-6.512 1.088-0.048 0-0.064 0-0.080 0zM548.928 201.248c7.232-7.632-16.864-18.544-11.968-18.304 5.856 0.288 23.472 12.080 25.296 16.624 2.912 7.264-3.344 13.648-9.12 11.424-21.584-8.336-7.232 20.624-6.176 22.16-6.352-9.296-19.392-12.048-14.224-28.384z" /> -<glyph unicode="" d="M257.952 353.008c-82-14.352-146.592-62.288-195.424-136.128l-68.112 51.056 43.296-183.776 193.968 63.2-79.296 26.416c43.152 66.72 76.432 86.064 138.448 103.28 32.976 9.152 80.768 4.576 127.888-20.736 39.472-21.28 58.704-50.64 83.392-112.16 6.080 4.56 12.128 4.56 16.848 2-6.080 52.448-26.416 104.736-69.872 149.632-43.936 45.376-117.008 70.208-191.152 57.232z" /> -<glyph unicode="" d="M0.24-36.752l-0.24 516.752 257.44-257.424z" /> -<glyph unicode="" d="M443.376 480l-443.376-256 443.376-256z" /> -<glyph unicode="" d="M0 478.816l516.752 0.24-257.424-257.44z" /> -<glyph unicode="" d="M256 424.576c110.592 0 200.592-89.984 200.592-200.56 0-110.608-90.016-200.592-200.592-200.592-110.608 0-200.56 90-200.56 200.592 0 110.592 89.952 200.56 200.56 200.56zM256 480c-141.376 0-256-114.608-256-255.984 0-141.408 114.624-256.016 256-256.016 141.392 0 256 114.608 256 256.016 0 141.376-114.608 255.984-256 255.984v0zM97.664 224.016h158.352v158.336c-87.456 0-158.352-70.896-158.352-158.336z" /> -<glyph unicode="" d="M466.112 482.208l5.696-120.752-14.416 0.016c-2.8 21.248-6.576 36.448-11.392 45.536-7.84 14.672-18.272 25.52-31.312 32.464s-30.176 10.432-51.44 10.432h-72.528v-393.36c0-31.632 3.424-51.36 10.256-59.216 9.616-10.64 24.416-15.952 44.416-15.952h17.84v-14.016h-218.288v14.016h18.224c21.776 0 37.216 6.608 46.32 19.76 5.568 8.096 8.368 26.576 8.368 55.408v393.36h-61.888c-24.048 0-41.12-1.776-51.264-5.328-13.136-4.768-24.416-14.048-33.792-27.696-9.376-13.648-14.912-32.144-16.688-55.44h-14.416l6.080 120.752h420.24z" /> -<glyph unicode="" d="M45.664 436.128v-83.616l83.632 83.616h-83.632zM45.664 265.488v-253.616h308.48v424.256h-205.984v-104.304l-102.816 0.544 0.32-66.896zM0-32v512h399.856v-512h-399.856zM306.416 319.552v-38.592h-110.048v38.592h110.048zM327.376 340.528h-151.968v-80.512h151.968v80.512zM99.28 264.512v59.008l-14.96-13.008v14.432l14.96 12.992h13.504v-73.424h-13.504zM306.416 211.152v-38.576h-110.048v38.576h110.048zM327.376 232.128h-151.968v-80.512h151.968v80.512zM79.792 156.112v12.064l27.424 31.872c1.376 1.584 2.352 3.024 2.944 4.336 0.592 1.296 0.88 2.816 0.88 4.528 0 2.752-0.752 4.976-2.272 6.656-1.504 1.68-3.712 2.528-6.592 2.528-1.088 0-2.176-0.144-3.248-0.464-1.072-0.304-2.032-0.816-2.88-1.552-0.864-0.72-1.552-1.68-2.064-2.896-0.512-1.2-0.768-2.688-0.768-4.48h-13.408c0 3.376 0.592 6.384 1.744 9.024 1.168 2.64 2.752 4.896 4.736 6.752 2 1.856 4.352 3.264 7.072 4.24 2.704 0.96 5.648 1.44 8.816 1.44 3.232 0 6.224-0.496 8.992-1.488 2.768-1.008 5.136-2.416 7.104-4.224 1.968-1.824 3.52-4.064 4.624-6.704 1.12-2.656 1.664-5.616 1.664-8.928 0-1.792-0.176-3.392-0.528-4.784-0.336-1.408-0.848-2.768-1.488-4.064-0.656-1.312-1.472-2.608-2.48-3.872-0.992-1.28-2.112-2.624-3.344-4.080l-20.528-23.824h28.352v-12.064h-44.752zM306.416 93.296v-38.576h-110.048v38.576h110.048zM327.376 114.256h-151.968v-80.512h151.968v80.512zM124.784 59.488c0-3.632-0.624-6.832-1.856-9.584-1.248-2.752-2.912-5.056-5.056-6.864-2.128-1.84-4.608-3.184-7.44-4.080-2.832-0.896-5.84-1.344-8.992-1.344-2.96 0-5.84 0.416-8.672 1.232-2.816 0.832-5.312 2.128-7.472 3.872-2.176 1.76-3.904 3.984-5.216 6.704-1.312 2.736-2 6-2.064 9.856h13.408c0.064-1.664 0.368-3.088 0.928-4.288 0.56-1.184 1.264-2.208 2.16-2.992 0.896-0.784 1.952-1.376 3.152-1.744 1.2-0.384 2.464-0.576 3.776-0.576 2.88 0 5.248 0.88 7.12 2.624 1.856 1.76 2.784 4.288 2.784 7.584 0 3.088-0.896 5.536-2.688 7.376-1.792 1.808-4.336 2.736-7.632 2.736h-1.952v11.648h1.952c3.312 0 5.664 0.88 7.12 2.624 1.44 1.744 2.16 3.936 2.16 6.544 0 3.088-0.896 5.424-2.688 7.008-1.792 1.584-3.888 2.368-6.288 2.368-2.544 0-4.672-0.784-6.352-2.32-1.696-1.552-2.608-3.728-2.736-6.544h-13.408c0.064 3.312 0.704 6.24 1.904 8.816 1.2 2.576 2.8 4.768 4.8 6.56 2 1.776 4.352 3.168 7.056 4.128 2.72 0.96 5.616 1.44 8.72 1.44 3.232 0 6.224-0.512 8.992-1.552 2.752-1.024 5.136-2.464 7.152-4.32 2-1.872 3.552-4.080 4.672-6.656 1.104-2.576 1.664-5.408 1.664-8.512 0-3.984-0.816-7.168-2.448-9.536-1.632-2.384-3.648-4.208-6.064-5.52 2.608-1.376 4.832-3.392 6.704-6.032 1.856-2.656 2.784-6.208 2.784-10.672z" /> -<glyph unicode="" d="M718.384 16.192c0-26.624-21.552-48.192-48.176-48.192h-512.352c-26.624 0-48.192 21.568-48.192 48.192v127.808l-109.68 79.984 109.68 80v127.808c0 26.592 21.568 48.192 48.192 48.192h512.336c26.624 0 48.176-21.584 48.176-48.192v-415.632z" horiz-adv-x="720" /> -<glyph unicode="" d="M664.704 16.16c0-26.608-21.584-48.16-48.192-48.16h-424.976c-26.608 0-48.192 21.568-48.192 48.16v77.2c0 0-1.488 6.128-2.544 8.304-1.072 2.208-5.232 7.376-5.232 7.376l-117.936 91.744c0 0-17.456 13.776-17.632 23.2-0.192 9.728 17.632 24.992 17.632 24.992l117.952 98.832c0 0 4.16 5.536 5.232 7.824 1.008 2.16 2.544 8.272 2.544 8.272v67.888c-0.016 26.64 21.568 48.208 48.176 48.208h424.976c26.624 0 48.192-21.568 48.192-48.208v-415.632z" horiz-adv-x="672" /> -<glyph unicode="" d="M151.248 321.552v-43.296c0-9.424-6.736-16.944-16.032-19.168l9.056-1.008c0.032-0.464 2.272-24.704 12.384-50.656 6.112 5.024 10.128 12.672 10.128 21.552v93.264l-15.552-0.704zM139.984 451.088h-113.2c-14.688 0-26.784-12.976-26.784-28.512v-193.584c0-15.552 12.096-27.664 26.784-27.664h71.936c0.224 7.248 0.656 14.48 1.456 21.632h-37.936v14.688h40.512c1.344 6.672 2.96 13.584 5.040 20.736h-70.624c-12.080 0-21.584 8.64-21.584 19.872v138.272c0 10.352 9.504 19.888 21.584 19.888h92.48c1.856 0 3.616-0.288 5.328-0.704 6.912-1.68 12.4-6.48 14.848-12.416l16.992-14.192v13.472c0 15.552-12.096 28.512-26.816 28.512zM472.848 60.464v186.208h-118.016c-1.168-5.008-2.48-10.096-4.112-15.328l-35.44 4c-0.016 0.192-0.432 4.592-1.552 11.328h-56.048v-77.104l17.712 0.784v52.416h179.76v-137.056h-123.328l-23.728-24.384 52.288-0.272v-13.36h-60.976v-9.792h129.056v9.792h-57.408v13.296l101.792-0.528zM477.888 27.84h-222.512l-27.6-30.24 275.008-0.688zM239.36 150.544l18.224-14.368c-10.128-7.28-20.192-11.488-30.016-11.28-9.632 0.192-18.848 2.528-27.344 7.664-66.368 26.128-74.064 124.064-74.064 124.064-3.696-11.84-5.888-23.328-7.824-34.144-1.28-10.96-1.856-22.096-1.68-33.44 1.312-27.44 6.912-49.888 17.456-67.6 10.096-16.864 27.76-30.352 53.424-39.088 18.752-6.24 36.624-6.976 54.864-0.304 18.768 5.808 35.984 14.208 52.064 24.464l18.048-15.072-9.936 61.936-63.216-2.832zM272.032 411.024c-18.768 6.224-36.624 6.992-54.88 0.304-18.752-5.808-35.968-14.208-52.064-24.48l-18.032 15.072 9.936-61.936 63.216 2.832-18.224 14.368c10.128 7.28 20.208 11.504 30.016 11.264 9.648-0.192 18.848-2.512 27.344-7.648 66.368-26.144 74.064-124.064 74.064-124.064 3.696 11.84 5.872 23.312 7.808 34.128 1.28 10.96 1.856 22.112 1.696 33.44-1.328 27.456-6.896 49.904-17.456 67.616-10.096 16.864-27.76 30.336-53.424 39.088z" /> -<glyph unicode="" d="M562.208 267.856c0-117.136-112.592-192.816-281.104-212.112-83.056-56.272-184.16-87.712-251.6-87.712 82.224 60.336 105.248 115.968 94.432 123.952-8.432 4.288-16.56 8.928-24.304 13.872-60.928 38.896-99.632 97.040-99.632 162 0 117.184 125.856 212.144 281.12 212.144s281.088-94.96 281.088-212.144z" horiz-adv-x="560" /> -<glyph unicode="" d="M449.296 234.64c-0.192 6.592-0.448 14-0.448 16.496l0.048 0.544v48.192l-1.12 4.128c-10.336 39.024-40.080 42.048-48.944 42.048-1.36 0-2.784-0.064-4.192-0.176-1.072-0.032-2.192-0.096-3.264-0.192-7.552 17.968-25.696 30-48.016 30-8.64 0-16.752-1.68-23.952-4.672-10.032 10.464-25.008 16.992-41.984 16.992-2.736 0-5.392-0.176-8-0.496v22.032c0 20.288 0 74.176-51.264 74.176l-2.224-0.032h-1.584c-30.88 0-55.072-21.584-55.072-49.12l0.736-121.92c-10.448 7.888-22.256 11.872-35.328 11.872-7.84 0-14.944-1.36-22.736-2.976-14.096-2.96-25.984-12.272-32.544-25.584-6.944-14.048-7.232-30.992-0.88-45.728l40.832-120.128 2.448-3.6 65.68-97.968 15.344-43.248 7.84-22.048 199.584 1.408 6.16 24.784 42.16 170.048 0.176 0.944c2.144 11.552 1.872 34.064 0.56 74.208zM416.4 166.464l-41.92-169.136-150.656-1.040-16.736 47.12-67.952 101.376-39.952 117.504c-5.344 11.088-1.008 24.88 9.52 27.072 6.032 1.28 11.232 2.288 16 2.288 7.456 0 13.936-2.464 21.024-10.384l31.232-68.624c1.040-2.336 3.968-3.456 7.056-3.456 4.432 0 9.248 2.336 9.456 6.848l-1.328 218.56c0 9.008 9.888 16.224 22.176 16.224 1.312 0 2.56 0.048 3.808 0.048 10.48 0 18.384-2.080 18.384-41.28v-145.76c0.080-3.328 4.704-4.848 9.344-4.848 4.656 0 9.328 1.568 9.328 4.448v75.536c0 8.992 9.92 16.24 22.224 16.24 12.288 0 22.208-7.248 22.208-16.24v-68.512c-0.272-5.008 4.944-7.12 10.288-7.12 6.064 0 12.336 2.72 11.152 7.088v56.272c0 8.976 9.92 16.224 22.224 16.224h0.096c12.32 0 18.896-7.248 18.896-16.224v-72.96c-0.384-4.512 3.568-6.48 7.6-6.48 4.512 0 9.152 2.448 8.016 6.464v41.984c0 8.992 6.32 17.456 18.608 17.456 0.816 0.096 1.6 0.144 2.368 0.144 9.248 0 14.352-6.864 17.2-17.584v-42.56c-0.544-5.776 3.072-71.872 0.32-86.608z" /> -<glyph unicode="" d="M400.528 147.184c53.024 83.856 43.12 196.128-30.016 269.264-84.8 84.736-222.176 84.736-306.976 0-84.72-84.816-84.72-222.208 0-306.96 73.072-73.184 185.36-83.056 269.216-30.016l114.096-114.112 67.696 67.712-114.016 114.112zM322.928 157.072c-58.496-58.432-153.312-58.432-211.712 0-58.496 58.496-58.496 153.232 0 211.68 58.4 58.544 153.232 58.544 211.712 0 58.416-58.432 58.416-153.184 0-211.68z" /> -<glyph unicode="" d="M26 442.752h396.4l-11.904 5.328 64.864-72.064-4.112 10.736v-396.384l16.048 16.048h-461.264l16.048-16.048-0.016 468.448-16.048-16.048zM26-25.664h477.312v418.592l-4.112 4.576-69.664 77.344h-419.584v-500.512l16.048 0.016zM100.448 202.528h314.704l-16.048 16.048v-225.76l16.048 16.048h-314.704l16.048-16.048v225.76l-16.048-16.048zM100.448-23.232h330.752v257.856h-346.8v-257.856h16.048zM153.328 272.208h222.656v195.456h-238.704v-195.456h16.048zM153.328 435.568h206.608l-16.048 16.048v-163.36l16.048 16.048h-206.608l16.048-16.048v163.36l-16.048-16.048zM158.176 458.8h112.848v-175.36h-112.848z" /> -<glyph unicode="" d="M488.272 480h-488.272v-428.192l4.208-4.688 71.264-79.12h429.2v512.016h-16.4zM395.68 246.576h-289.12v198.112h289.12v-198.112zM32.816 64.416v382.768h40.928v-233.44h354.768v233.424h43.344v-446.368h-97.44v174.464h-244.16v-174.464h-40.176l-57.248 63.6zM163.072 142.464h74.528v-134.272h-74.528v134.272z" /> -<glyph unicode="" d="M378.736 393.824h28.288v-339.632h-28.288zM322.144 139.088h141.504v-28.32h-141.504zM407.040 54.192h28.32v-28.32h-28.32zM435.344 25.872h56.592v-28.288h-56.592zM350.432 54.192h28.304v-28.32h-28.304zM293.824 25.872h56.608v-28.288h-56.608zM293.824 450.416h56.608v-28.288h-56.608zM435.344 450.416h56.592v-28.288h-56.592zM407.040 422.128h28.32v-28.32h-28.32zM350.432 422.128h28.304v-28.32h-28.304zM1.968 333.024c13.792 2.304 31.84 4.272 54.816 4.272 28.224 0 48.912-6.56 62.032-18.384 12.144-10.496 19.36-26.592 19.36-46.288 0-20.032-5.904-35.776-17.072-47.264-15.104-16.080-39.712-24.288-67.616-24.288-8.528 0-16.416 0.32-22.976 1.968v-88.624h-28.56v218.608zM30.528 226.336c6.24-1.648 14.112-2.304 23.632-2.304 34.464 0 55.472 16.736 55.472 47.264 0 29.216-20.672 43.328-52.192 43.328-12.48 0-22-0.992-26.912-2.304v-86zM170.368 223.712c0 18.704-0.336 34.8-1.312 49.568h25.28l0.992-31.184h1.312c7.216 21.328 24.624 34.8 43.984 34.8 3.28 0 5.584-0.32 8.208-0.992v-27.248c-2.96 0.656-5.904 0.992-9.856 0.992-20.352 0-34.8-15.424-38.736-37.088-0.656-3.936-1.312-8.544-1.312-13.456v-84.688h-28.56v109.296z" /> -<glyph unicode="" d="M0.928 439.424h369.28v-38.16h-369.28zM118.112 480.864h134.912v-28.624h-134.912zM125.504 388.304v-419.568h45.376v419.632c-13.552 0.096-28 0.096-45.376-0.064zM200.304 387.968v-419.232h45.36v418.464c-17.312 0.272-31.744 0.576-45.36 0.768zM17.744 386.144l21.296-374.832c0-23.52 19.040-42.576 42.544-42.576h14.512v419.168c-21.248-0.384-46.576-0.912-78.352-1.76zM275.072 386.736v-418.016h14.48c23.52 0 42.56 19.056 42.56 42.576l21.296 374.832c-31.856 0.144-57.152 0.368-78.336 0.608z" /> -<glyph unicode="" d="M254.128 353.008c81.984-14.352 146.592-62.288 195.44-136.128l68.096 51.072-43.28-183.792-193.968 63.2 79.296 26.416c-43.136 66.72-76.432 86.064-138.448 103.296-32.976 9.152-80.768 4.576-127.872-20.736-39.504-21.28-58.736-50.64-83.424-112.16-6.064 4.56-12.128 4.56-16.848 2 6.080 52.448 26.416 104.736 69.888 149.632 43.904 45.36 116.96 70.176 191.136 57.2z" /> -<glyph unicode="" d="M509.376-29.184h-505.808v505.808h505.808v-505.808zM35.168 2.432h442.592v442.592h-442.592v-442.592z" /> -<glyph unicode="" d="M447.984 480h-383.984c-35.344 0-64-28.656-64-64v-383.984c0-35.36 28.656-64 64-64h383.984c35.344 0 64 28.656 64 64v383.984c0 35.344-28.656 64-64 64zM158.736 12.544h-111.312v47.504h111.312v-47.504zM158.736 100.64h-111.312v47.504h111.312v-47.504zM158.736 188.752h-111.312v47.504h111.312v-47.504zM158.736 276.848h-111.312v47.504h111.312v-47.504zM311.648 12.544h-111.312v47.504h111.312v-47.504zM311.648 100.64h-111.312v47.504h111.312v-47.504zM311.648 188.752h-111.312v47.504h111.312v-47.504zM311.648 276.848h-111.312v47.504h111.312v-47.504zM464.56 12.544h-111.312v47.504h111.312v-47.504zM464.56 100.64h-111.312v47.504h111.312v-47.504zM464.56 188.752h-111.312v47.504h111.312v-47.504zM464.56 276.848h-111.312v47.504h111.312v-47.504z" /> -<glyph unicode="" d="M696.992 479.984c-88.96 0-163.52-85.44-182.4-199.456l16.8-16.8c13.472 111.792 82.48 197.28 165.616 197.28 92.72 0 168.224-106.336 168.224-237.008s-75.52-237.008-168.224-237.008c-78.4 0-144.24 76.096-162.8 178.544l-16.192-16.336c23.456-104.768 94.832-181.184 178.976-181.184 103.168 0 187.136 114.832 187.136 255.984-0.016 141.152-83.984 256-187.136 255.984v0zM768.784 223.984c0-139.648-37.872-237.008-71.792-237.008-34.016 0-71.792 97.376-71.792 237.008 0 139.712 37.776 237.008 71.792 237.008 33.92 0 71.792-97.312 71.792-237.008zM696.992 479.984c-58.976 0-90.784-131.888-90.784-256 0-124.096 31.808-255.984 90.784-255.984 58.928 0 90.8 131.888 90.8 255.984-0.016 124.112-31.888 256-90.8 256zM696.992 479.984c-103.104 0-191.92-61.392-232.432-149.424l14.176-14.192c36.096 84.928 120.336 144.624 218.272 144.624 130.736 0 237.040-106.336 237.040-237.008s-106.32-237.008-237.040-237.008c-92.112 0-171.872 52.912-211.12 129.792l-14.144-14.256c43.296-80.016 128-134.512 225.232-134.512 141.168 0 255.984 114.832 255.984 255.984 0 141.152-114.8 256-255.968 256v0zM940.96 225.84h-371.68l12.448-12.448-6.496-6.544h365.728v18.992zM484.416 353.776h425.136v-18.976h-425.136v18.976zM484.416 97.808h425.136v-18.96h-425.136v18.96zM345.072 429.168v-59.072l39.936 39.968 4.592-4.608v66.448h-389.6v-498.88h389.6v46.656l-4.208-4.272-40.32 39.984v-39.632h-300.576v247.136l-0.32 65.184h99.712v101.088h201.184zM44.496 429.168h81.488l-81.488-81.472v81.472zM285.808 114.208h-114.896v-77.072h148.080v44.192l-33.184 32.88zM298.56 57.184h-107.232v36.976h107.232v-36.976zM294.944 165.52h-103.616v36.976h107.232v-33.312l20.432 20.592v32.816h-148.080v-77.12h104.128l19.024 19.2 0.88 0.848zM280.944 273.888h-89.632v36.96h94.512l20.064 20.048h-134.992v-77.088h130.128l-20.080 20.080zM141.824 66.544c0-4.576-0.8-8.544-2.384-11.888-1.584-3.344-3.728-6.128-6.384-8.304-2.672-2.24-5.744-3.872-9.248-4.992-3.504-1.104-7.184-1.664-11.024-1.664-3.6 0-7.136 0.48-10.608 1.536-3.456 1.008-6.576 2.592-9.312 4.768-2.736 2.176-4.944 5.008-6.624 8.448-1.664 3.488-2.512 7.664-2.512 12.56h20.096c0-3.088 0.848-5.408 2.576-6.928 1.712-1.504 3.824-2.24 6.368-2.24 2.608 0 4.752 0.752 6.432 2.304 1.664 1.584 2.512 3.888 2.512 7.008 0 2.608-0.864 4.8-2.624 6.56-1.776 1.728-3.984 2.624-6.672 2.624h-2.816v17.424h2.816c3.024 0 5.152 0.896 6.432 2.64 1.264 1.728 1.888 3.632 1.888 5.584 0 2.752-0.784 4.864-2.384 6.24s-3.456 2.096-5.584 2.096c-2.112 0-3.984-0.72-5.584-2.16-1.584-1.408-2.384-3.44-2.384-6.064h-20.080c0 4.080 0.736 7.76 2.192 11.024 1.472 3.264 3.472 6.048 6 8.336 2.528 2.272 5.504 4.016 8.88 5.184 3.392 1.2 7.056 1.792 10.976 1.792 4.080 0 7.808-0.624 11.216-1.904 3.392-1.264 6.352-3.040 8.88-5.312 2.528-2.32 4.496-5.040 5.888-8.224 1.376-3.184 2.080-6.64 2.080-10.416 0-2.368-0.272-4.464-0.8-6.336-0.528-1.824-1.216-3.424-2.096-4.784-0.848-1.344-1.808-2.496-2.864-3.424-1.056-0.944-2.176-1.792-3.296-2.528 1.216-0.816 2.432-1.776 3.6-2.864 1.184-1.104 2.256-2.432 3.2-3.952 0.928-1.504 1.728-3.264 2.336-5.264s0.912-4.272 0.912-6.88v0zM85.568 146.448v18.144l27.088 21.184c2.848 2.224 5.056 4.176 6.608 5.936s2.336 3.584 2.336 5.456c0 2.272-0.688 4.096-2.080 5.456-1.392 1.376-3.312 2.032-5.76 2.032-0.896 0-1.824-0.128-2.8-0.368-0.992-0.256-1.872-0.704-2.656-1.36-0.768-0.656-1.392-1.52-1.872-2.544-0.496-1.072-0.736-2.464-0.736-4.192h-20.112c0 4.336 0.768 8.16 2.256 11.408 1.536 3.28 3.568 6.064 6.144 8.336 2.576 2.304 5.568 4.016 9.008 5.152 3.424 1.152 7.024 1.712 10.768 1.712 3.92 0 7.584-0.576 10.976-1.712 3.392-1.136 6.352-2.784 8.88-4.96 2.528-2.16 4.512-4.8 5.936-7.904 1.424-3.104 2.144-6.624 2.144-10.56 0-2.432-0.416-4.736-1.296-6.864-0.848-2.112-2.064-4.176-3.68-6.176-1.6-2-3.488-3.984-5.696-5.936-2.192-1.968-4.64-3.984-7.36-6l-10.544-8.080h29.776v-18.144l-57.328-0.016zM105.44 248.56v51.728l-18.64-16.176v21.456l18.64 16.176h20.080v-73.168l-20.080-0.016zM323.76 289.904l76.896-76.912-77.056-77.664 61.552-61.024 137.824 138.992-137.936 137.92-61.28-61.312z" horiz-adv-x="960" /> -<glyph unicode="" d="M367.056 26.912l-12.896 12.784v-27.824h-308.48v253.632l-0.336 66.88h102.832l-0.496 103.744h206.48v-16.736l12.512 12.528 33.184-33.2v81.28h-399.856v-512h399.856v91.984l-2.72-2.768-30.080-30.304zM45.664 436.144h83.632l-83.632-83.616v83.616zM301.152 92.288l-20.784 20.592h-104.96v-79.136h151.968v32.528l-20.976 20.8v-32.704h-110.064v37.936h104.8zM175.424 224.080v-79.152h72.608l-4.8 4.768 15.728 15.84h-62.608v37.952h100.224l20.448 20.608h-141.6zM196.352 276.768v37.92h53.168l20.592 20.608h-94.688v-79.136h120.464l-20.624 20.624h-78.912zM115.76 55.040c-2.608 0-4.8 0.768-6.544 2.32-1.76 1.584-2.64 3.936-2.64 7.12h-20.64c0-5.024 0.864-9.312 2.576-12.896 1.728-3.552 4-6.448 6.816-8.656 2.8-2.256 6-3.856 9.536-4.912 3.552-1.072 7.2-1.584 10.88-1.584 3.936 0 7.696 0.56 11.312 1.696 3.6 1.136 6.768 2.832 9.488 5.104 2.736 2.256 4.928 5.104 6.576 8.528 1.616 3.44 2.448 7.52 2.448 12.192 0 2.688-0.32 5.072-0.928 7.104-0.624 2.064-1.424 3.856-2.384 5.408-0.976 1.552-2.064 2.912-3.28 4.048-1.216 1.104-2.448 2.096-3.712 2.944 1.168 0.768 2.304 1.632 3.376 2.576 1.104 0.976 2.064 2.16 2.944 3.536 0.912 1.376 1.616 3.008 2.16 4.896 0.544 1.888 0.816 4.048 0.816 6.48 0 3.856-0.72 7.424-2.144 10.688-1.424 3.28-3.44 6.080-6.048 8.416-2.608 2.368-5.648 4.192-9.12 5.488-3.488 1.328-7.328 1.968-11.488 1.968-4.032 0-7.792-0.624-11.264-1.84-3.488-1.184-6.544-3.008-9.12-5.328-2.608-2.352-4.64-5.216-6.16-8.56-1.504-3.36-2.256-7.152-2.256-11.312h20.624c0 2.688 0.816 4.768 2.448 6.208 1.648 1.472 3.568 2.224 5.744 2.224 2.176 0 4.080-0.736 5.728-2.16 1.632-1.424 2.448-3.568 2.448-6.4 0-2-0.656-3.936-1.952-5.728s-3.504-2.704-6.608-2.704h-2.896v-17.856h2.896c2.768 0 5.040-0.896 6.864-2.704 1.808-1.776 2.688-4.048 2.688-6.72 0-3.2-0.864-5.584-2.576-7.184-1.728-1.616-3.92-2.4-6.608-2.384v0zM146.688 164.592h-30.56l10.8 8.288c2.784 2.096 5.312 4.16 7.568 6.16 2.256 2.016 4.208 4.048 5.84 6.112 1.648 2.048 2.896 4.176 3.792 6.352 0.88 2.192 1.328 4.56 1.328 7.040 0 4.032-0.736 7.632-2.208 10.816-1.488 3.2-3.504 5.904-6.112 8.112-2.608 2.224-5.648 3.92-9.12 5.088-3.488 1.184-7.248 1.776-11.248 1.776-3.872 0-7.536-0.592-11.056-1.776-3.536-1.168-6.608-2.944-9.232-5.312-2.64-2.32-4.752-5.184-6.32-8.512-1.52-3.344-2.304-7.264-2.304-11.696h20.64c0 1.76 0.256 3.184 0.752 4.288 0.496 1.072 1.136 1.968 1.936 2.624 0.816 0.688 1.712 1.136 2.736 1.408 1.008 0.256 1.968 0.368 2.88 0.368 2.512 0 4.48-0.688 5.904-2.096 1.44-1.376 2.144-3.248 2.144-5.584 0-1.936-0.784-3.808-2.384-5.616-1.6-1.824-3.872-3.84-6.8-6.112l-27.792-21.744v-18.64h58.848v18.656zM128.816 250.784v75.072h-20.608l-19.136-16.576v-22.016l19.136 16.592v-53.088h20.608zM659.008 280.704h45.568c22.4 0 40.528 18.16 40.528 40.528v45.632c0 22.384-18.144 40.48-40.528 40.48h-45.568c-22.368 0-40.576-18.128-40.576-40.48v-45.632c0-22.384 18.224-40.528 40.576-40.528zM502.512 316.4c14.224 0 25.776 11.472 25.776 25.776v29.024c0 14.24-11.584 25.824-25.776 25.824h-29.056c-14.272 0-25.76-11.568-25.76-25.824v-20.288l34.528-34.528h20.304zM530.96 173.008v19.184l-19.008-19.184h19.008zM867.376 313.136h30.176c14.816 0 26.864 12.048 26.864 26.848v30.176c0 14.816-12.032 26.832-26.864 26.832h-30.176c-14.832 0-26.8-12.016-26.8-26.832v-30.176c0-14.8 11.968-26.848 26.8-26.848zM930.176 294.608h-95.472c-20.192 0-36.592-17.296-36.592-38.624v-26.656c-10.096 14.128-26.128 23.296-44.224 23.296h-144.288c-16.128 0-30.416-7.456-40.496-19.072v27.808c0 20.48-15.744 37.104-35.216 37.104h-33.744l36.032-36.032h2.4v-2.4l28.704-28.688c-1.936-2.448-3.664-5.024-5.216-7.776l-0.016-0.016-23.488-23.664v-26.848h15.76v-117.424h44.384v140.448h11.984v-140.448h138.576v140.448h11.904v-140.448h48.032c0 0.128 0 2.56 0 30.656v77.984h18.272v92.896h7.968v-92.896h91.664v92.896h7.92v-92.896h31.744c0 0.048 0 1.664 0 20.288v71.472c0 21.328-16.4 38.608-36.608 38.608zM303.808 308.608l78.928-78.944-79.088-79.728 63.152-62.64 141.456 142.64-141.568 141.568-62.88-62.896z" horiz-adv-x="960" /> -<glyph unicode="" d="M347.344-35.376c32.080 0 61.648 7.504 61.648 42.336v90.912c0 2.544-0.336 4.992-0.64 7.44h47.552c13.264 0 24 10.24 24 22.864v221.152c0 12.656-10.736 22.88-24 22.88h-38.912c-2.304 16-32.416 47.312-32.416 47.312v-47.312h-20.128v84.896c0 12.64-10.256 22.896-22.88 22.896h-203.232c-12.624 0-22.848-10.24-22.848-22.896v-84.896h-22.768l1.584 46.24c0 0-31.664-30.576-31.664-45.856l5.088-0.384h-43.696c-13.28 0-24.016-10.224-24.016-22.88v-221.152c0-12.624 10.752-22.864 24.016-22.864h48.256c-0.656-3.328-0.992-6.288-0.992-8.512v-83.664c0-34.752 18.736-48.496 50.816-48.496h225.248zM364.448 233.152h3.52c15.696 0 28.384-14.32 28.384-31.952v-66.336c-9.088-3.888-20.032-5.872-31.904-6.848v105.152zM133.040 405.392c0 12.608 10.528 22.88 23.568 22.88h166.72c13.008 0 23.6-10.272 23.6-22.88v-33.184h-213.888v33.184zM133.040 233.152h213.888v-105.92c-0.4 0-0.784-0.032-1.2-0.032v67.12c0 15.632-10.256 28.288-22.88 28.288h-165.792c-12.64 0-22.864-12.656-22.864-28.288v-67.12c-0.416 0-0.752 0-1.152 0v105.952zM346.928 105.312v-1.2c0-3.344-0.784-6.528-2.128-9.392 0.544 2.416 0.944 4.944 0.944 7.584v3.008h1.2zM150.416 172.608v10.864h181.008v-10.864h-181.008zM331.44 156.8v-10.864h-181.008v10.864h181.008zM133.040 105.312h1.152v-3.008c0-2.608 0.384-5.072 0.912-7.472-1.296 2.848-2.064 5.968-2.064 9.28v1.2zM111.952 233.152h3.536v-105.2c-6.752 0.816-11.072 2.336-31.92 4.496v68.736c0 17.632 12.672 31.968 28.384 31.968zM58.608 337.136c0 8.128 6.592 14.752 14.736 14.752 8.144 0 14.736-6.608 14.736-14.752 0-8.128-6.592-14.72-14.736-14.72-8.144 0-14.736 6.608-14.736 14.72zM83.568 9.056v96.256h31.92v-82.336c0-12.656 10.224-22.88 22.848-22.88h203.232c12.624 0 22.88 10.224 22.88 22.88v82.336h31.904v-96.256c0-17.632-12.688-31.936-28.384-31.936h-256.016c-15.712 0-28.384 14.304-28.384 31.936z" /> -<glyph unicode="" d="M512 160v-192h-512v192h64v-128h384v128zM96 64c-64-64-32-32 0 0z" /> -<glyph unicode="" d="M74.848 218.352l8.848-8.592 171.968 182.432-8.864 8.608zM227.328 419.024l10.688-10.096-171.92-182.432-10.704 10.096zM275.264 373.504l-10.768 10.112-171.44-182.4 10.224-10.112zM334.368 471.376c-16.784 16.176-43.936 15.328-59.648-1.984l-36.912-39.168 67.168-63.216 36.912 39.184c16.224 16.768 15.312 43.92-1.904 60.144l-5.616 5.056zM122.704 173.472l-10.24 9.664 171.68 182.224 10.224-9.648zM6.192 112.192l106.080 49.952-67.664 63.264zM316.176-40.64c-53.936 0-84.256 28.336-95.168 41.152-0.96 1.072-1.952 2.272-2.992 3.584-17.408-9.712-34.592-17.248-49.248-21.072-64.288-16.832-82.16-18.208-125.2 5.76-43.712 24.352-44.128 80.96-44.304 84.144l2.992 27.424 8.096-2.096 1.76-26.544c0.048-0.656 6.24-47.056 40.72-66.224 35.952-20 48.416-20.464 111.104-4 12.64 3.296 27.568 9.776 42.944 18.224-15.728 24.912-31.232 64.24-12.32 107.168 20.352 46.16 49.36 91.392 110.72 76.976 13.264-3.152 22.64-12.144 27.008-26.048 10.144-32.128-9.12-84.128-32.752-110.656-16.576-18.576-40.288-37.648-64.864-53.232 0.272-0.336 0.608-0.688 0.864-1.056 9.824-11.472 38.4-37.792 90.704-34.064 106.336 7.6 162.352 31.36 172.72 44.528l15.024-11.776c-15.936-20.272-79.696-44.176-186.384-51.792-3.92-0.288-7.712-0.416-11.408-0.416zM283.136 187.488c-29.216 0-50.128-20.704-71.104-68.32-15.584-35.344-2.208-68.592 11.296-89.776 23.504 14.736 46.368 32.976 61.968 50.432 21.968 24.688 35.968 69.472 28.8 92.176-2.368 7.456-6.56 11.664-13.2 13.216-6.224 1.504-12.144 2.272-17.76 2.272z" /> -<glyph unicode="" d="M406.256 480h-311.936c-52.096 0-94.32-42.224-94.32-94.32v-323.344c0-52.096 42.24-94.336 94.32-94.336h311.936c52.096 0 94.32 42.24 94.32 94.336v323.344c0.016 52.096-42.224 94.32-94.32 94.32zM453.44 62.336c0-26-21.136-47.168-47.152-47.168h-311.952c-26.032 0-47.152 21.136-47.152 47.168v323.344c0 26.032 21.168 47.152 47.152 47.152h311.936c26 0 47.152-21.136 47.152-47.152v-323.344zM79.296 369.488h342.016v-17.392h-342.016v17.392zM81.056 314.752h306.88v-17.392h-306.88v17.392zM608.976 325.248h115.632v-17.408h-115.632v17.408zM608.976 270.784h115.632v-17.392h-115.632v17.392zM635.344 196.64h57.824v-17.424h-57.824v17.424zM159.856 205.344h259.712v-17.408h-259.712v17.408zM159.856 150.656h220.816v-17.408h-220.816v17.408zM159.856 95.92h259.712v-17.392h-259.712v17.392zM696.112 480h-58.64c-52.096 0-94.336-42.224-94.336-94.32v-323.344c0-52.096 42.24-94.336 94.336-94.336h58.64c52.096 0 94.32 42.24 94.32 94.336v323.344c0.016 52.096-42.224 94.32-94.32 94.32zM743.296 62.336c0-26-21.168-47.168-47.152-47.168h-58.64c-26 0-47.152 21.136-47.152 47.168v323.344c0 26.032 21.136 47.152 47.152 47.152h58.64c26 0 47.152-21.136 47.152-47.152v-323.344zM608.976 398.64h115.632v-42.4h-115.632v42.4zM86.672 217.616h41.936v-41.936h-41.936v41.936zM86.672 164.704h41.936v-41.936h-41.936v41.936zM86.672 108.192h41.936v-41.936h-41.936v41.936zM635.344 143.728h57.824v-17.424h-57.824v17.424z" horiz-adv-x="784" /> -<glyph unicode="" d="M613.984 229.888v-205.184h-557.296v205.184h-56.688v-261.888h670.672v261.888zM521.312 239.584l-189.392 240.416-182.576-235.92 125.856-1.552v-83.52h119.408v77.6z" horiz-adv-x="672" /> -<glyph unicode="" d="M419.872-31.888v0c21.248 0 39.824 20.032 40.416 45.744v1.216l1.088 416.208c0 25.92-17.76 48.24-40.256 48.72l2.608-0.16-360.928 0.048c-21.136 0-38.944-19.712-40.464-44.416l-0.016-7.136-16.656 0.064c-3.040 0.016-5.552-1.44-5.552-3.248l-0.112-38.32c0.032-1.808 2.512-3.28 5.552-3.28l16.64-0.048-0.112-45.312-16.416 0.048c-3.040-0.016-5.552-1.488-5.552-3.264l-0.112-38.352c0.016-1.776 2.512-3.264 5.552-3.264l16.416-0.032-0.112-45.296-16.208 0.048c-3.056-0.016-5.568-1.456-5.568-3.264l-0.080-38.32c0-1.792 2.496-3.296 5.536-3.28l16.192-0.032-0.112-45.312-15.968 0.032c-3.056 0.016-5.552-1.44-5.536-3.232l-0.112-38.32c0-1.824 2.496-3.296 5.536-3.264l15.968-0.048-0.112-45.328-15.728 0.032c-3.056-0.016-5.552-1.44-5.536-3.232l-0.112-38.352c0-1.824 2.496-3.264 5.552-3.232l15.712-0.048-0.016-6.8c-0.080-26.32 18-47.792 40.368-47.888zM419.552 15.344l-0.016-0.992c-0.176-3.424-1.36-5.552-2.144-6.544l-353.52 0.896c-0.848 1.072-2.080 3.424-2.064 7.216l0.016 6.784 13.632-0.048c3.072-0.032 5.584 1.488 5.584 3.264l0.080 38.336c0.032 1.792-2.48 3.248-5.552 3.312l-13.632 0.032 0.112 45.28 13.408-0.048c3.056 0 5.568 1.456 5.584 3.296l0.096 38.304c0 1.792-2.496 3.28-5.584 3.296l-13.392 0.032 0.112 45.328 13.184-0.032c3.056-0.032 5.584 1.424 5.6 3.232l0.096 38.336c0 1.792-2.496 3.28-5.584 3.28l-13.184 0.032 0.112 45.312 13.008-0.032c3.056-0.032 5.568 1.44 5.6 3.248l0.064 38.336c0.016 1.76-2.48 3.248-5.552 3.28l-12.992 0.032 0.112 45.312 12.784-0.032c3.072-0.016 5.568 1.44 5.6 3.232l0.064 38.32c0.016 1.808-2.496 3.264-5.552 3.28l-12.928 0.032-0.128 3.952v0.272c0 3.664 1.568 6.176 2.368 7.424h353.568c0.848-1.248 2.112-4.56 2.112-8.352l-1.008-416.224zM364.368 272.4c-0.016-5.456-7.888-9.36-17.408-9.328h-218.048c-9.536 0.016-17.376 4.496-17.344 9.984l0.288 116.48c0.016 5.456 7.84 9.888 17.392 9.872h218.048c9.552-0.064 17.392-5.024 17.36-10.512l-0.272-116.496z" /> -<glyph unicode="" d="M76.704 241.92h174.080c-0.176 11.216-0.032 22.304 0.432 33.104h-174.512v-33.104zM359.92 267.584c-4.096-8.688-7.456-17.328-10.192-25.664h10.192v25.664zM278.4 122.112c8.464 5.232 10.336 9.6 3.472 14.384-9.84 2.304-13.264-1.648-16.432-0.224-2.64 6.752-9.024 7.808-12.688 8.704-5.872 1.456-5.872-4.384-10.96-1.456-7.152 4.112-5.584 10.32-17.728 10.224-12.976 0.096-24.544-16.672-8.64-30.784 9.168-5.808 51.328-5.44 62.976-0.848zM283.2 75.392c-22.992-1.392-23.648 22.096-44.96 15.6-13.408-5.84-21.392-34.352-23.664-58.464 58.368 0 116.72 0 175.088 0-6.976 37.12-23.648 85.76-47.312 89.664-42.224 2.928-38.128-32.288-59.152-46.8zM585.872 360.064l-14.256 119.936-34.72-45.216c-28.24 14.224-57.12 24.688-87.008 29.552-29.632 6.656-55.088-0.544-79.2-18.432-32.912-25.040-66.88-78.256-73.312-113.552-5.376-29.072-8.928-78-4.912-123.136h-246.432v56.736c0 25.376 20.64 46.032 46.032 46.032h162.048c1.104 9.904 2.384 19.328 3.904 27.52 1.072 5.92 2.736 12.128 4.816 18.512h-170.768c-50.848 0-92.064-41.216-92.064-92.064v-205.872c0-50.848 41.216-92.080 92.064-92.080h268.72c50.864 0 92.080 41.232 92.080 92.080v205.872c0 0.72-0.096 1.424-0.112 2.144-0.496 22.096-8.784 42.256-22.224 57.856-3.376 3.92-7.024 7.584-11.008 10.88-4.832-2.608-9.92-5.712-15.664-9.872-7.648-6.656-14.32-13.824-20.288-21.264 10.32-5.952 18.048-15.68 21.328-27.376 1.104-3.968 1.904-8.048 1.904-12.368v-56.736h-106c6.176 39.504 24.352 103.088 78.16 149.12 28.144 20.656 68.192 42.416 118.656 8l-26.144-48.624 114.4 42.352zM159.92 14.048h-67.856c-25.392 0-46.032 20.656-46.032 46.032v118.432h113.888v-164.464zM337.76 178.512h69.072v-118.432c0-25.376-20.64-46.032-46.048-46.032h-170.16v164.464h106.032c0.336-1.856 0.576-3.84 0.976-5.664 0 0-0.016 2.080 0.112 5.664h40.016z" horiz-adv-x="592" /> -<glyph unicode="" d="M750.944-32h-316.464c-33.696 0-60.096 24.288-60.096 55.28v220.368c0 26.064 18.656 47.392 44.624 53.52 3.264 17.040 11.44 46.368 42.752 46.368h109.904c32.352 0 40.272-28 42.976-44.592h136.304c33.696 0 60.096-24.288 60.096-55.312v-220.352c-0.016-30.992-26.4-55.28-60.096-55.28zM434.656 261.824c-13.056 0-23.152-8-23.152-18.176v-220.352c0-10.192 10.096-18.16 22.992-18.16h316.448c12.896 0 22.976 7.968 22.976 18.16v220.352c0 10.192-10.080 18.176-22.976 18.176h-166.176l-3.84 13.44c-1.056 3.76-1.616 7.888-2.16 12.256-2.432 18.896-4.704 18.896-7.088 18.896h-109.92c-0.56 0-0.816-0.064-0.816-0.064-3.056-2.16-5.472-16.032-6.288-20.608-0.64-3.744-1.264-7.312-2.176-10.464l-3.824-13.44h-14zM132.336 344.128c39.408 23.376 94.528 46.672 156.048-4.768l-40.384-60.16 154.848 40.704-3.264 158.512-51.136-54.64c-35.072 22.208-71.472 39.584-109.92 49.76-37.84 12.48-72.032 6.336-105.84-13.952-46.176-28.48-97.392-93.648-110.32-138.928-13.744-47.696-28.016-138.256-20.112-208.416 0.016 0 11.856 149.264 130.080 231.888z" horiz-adv-x="816" /> -<glyph unicode="" d="M589.824 360.064l-14.272 119.936-34.704-45.216c-28.256 14.224-57.12 24.704-87.024 29.568-29.632 6.64-55.072-0.56-79.2-18.448-32.896-25.040-66.88-78.256-73.296-113.552-5.376-29.088-8.944-78-4.928-123.152h-250.368v56.736c0 25.392 20.64 46.032 46.032 46.032h165.984c1.12 9.904 2.384 19.328 3.904 27.536 1.072 5.92 2.752 12.128 4.816 18.496h-174.704c-50.832 0.016-92.064-41.2-92.064-92.048v-205.872c0-50.848 41.232-92.080 92.064-92.080h268.736c50.848 0 92.064 41.232 92.064 92.080v205.872c0 0.24-0.032 0.48-0.032 0.704-0.16 21.328-7.6 40.896-19.904 56.416-3.568 4.512-7.568 8.656-11.904 12.416-4.128-2.368-8.432-5.072-13.2-8.512-8.144-7.104-15.264-14.768-21.536-22.736 10.448-6.976 17.744-18.144 19.808-31.072 0.368-2.368 0.736-4.752 0.736-7.232v-56.752h-102.064c6.192 39.504 24.352 103.088 78.16 149.12 28.144 20.656 68.192 42.416 118.672 8l-26.16-48.624 114.384 42.384zM159.936 14.048h-67.872c-25.392 0-46.032 20.64-46.032 46.032v118.432h113.888v-164.464zM341.712 178.512h65.12v-118.432c0-25.392-20.64-46.032-46.032-46.032h-170.176v164.464h109.952c0.352-1.856 0.592-3.84 0.992-5.664 0 0-0.032 2.080 0.096 5.664h40.048z" horiz-adv-x="592" /> -<glyph unicode="" d="M29.568 75.632c0 46.96 35.52 85.152 79.168 85.152h11.408l-16.736-46.864h39.488l-7.152-32.24 114.208-98.032 115.584 97.984-7.168 32.288h39.472l-16.736 46.864h11.392c43.664 0 79.2-38.208 79.2-85.152v-107.632h29.584v107.632c0 63.328-48.672 114.72-108.784 114.72h-283.76c-60.112-0.016-108.736-51.392-108.736-114.72v-107.632h29.568v107.632zM320.288 160.784h29.44l6.16-17.296h-34.4l11.312-50.848-80.848-68.512 68.336 136.656zM151.536 160.784h29.456l69.36-138.048-0.304-0.24-81.616 70.080 11.312 50.912h-34.4l6.192 17.296zM100.368 81.168h29.568v-113.168h-29.568v113.168zM371.328 81.168h29.568v-113.168h-29.568v113.168zM295.488 480h-89.648c-44.016 0-79.792-35.664-79.792-79.68v-89.68c0-44.016 35.76-79.696 79.792-79.696h89.648c44.064 0 79.696 35.68 79.696 79.696v89.68c0.016 44.016-35.632 79.68-79.696 79.68zM250.672 271.024c-39.376 0-67.792 29.376-69.008 30.64l16.032 15.296c0.256-0.224 23.248-23.76 52.976-23.76 28.4 0 52.96 23.76 53.2 24.016l15.536-15.824c-1.28-1.232-31.392-30.368-68.736-30.368z" horiz-adv-x="496" /> -<glyph unicode="" d="M521.84 316.368l13.728-20.48-109.28-73.056-17.632 17.616zM187.504 63.216l-12.88 20.272 103.504 69.424 17.44-17.456zM140 134.768l-13.664 20.448 89.568 59.904 17.744-17.728zM474.336 387.968l13.696-20.464-123.696-82.72-17.744 17.744zM499.424 350.976l11.216-17.344-116.96-78.192-14.864 14.864zM162.624 100.976l-11.2 17.264 96.704 64.672 14.848-14.848zM495.808 402.224l74.688 49.984c32.048 22.256 76.576 13.504 97.808-19.12l7.28-10.336c22-32.784 13.248-77.28-19.312-98.544l-74.736-50.016-85.728 128.032zM104.88 140.976l86.512-128.224-191.392-41.696zM546.96 279.408l13.104-19.488-102.272-68.592-16.928 16.928zM212.816 26.992l-13.088 19.52 110.608 74.192 16.912-16.944zM505.776 342.848l18.064-27.52-111.44-78.624-26.24 26.256zM181.904 74.112l-23.376 36.848 96.864 64.672 29.136-29.136zM60.096 425.52l54.528 54.512 457.408-457.536-54.528-54.512-457.408 457.536z" horiz-adv-x="688" /> -<glyph unicode="" d="M16.912 481.536l495.056-495.072-18.176-18.176-495.056 495.072z" /> -<glyph unicode="" d="M662.384 159.024c0 51.184-41.68 93.44-93.488 93.44h-24.368c-22.048-16.672-49.44-26.784-79.184-26.784-29.776 0-57.168 10.112-78.592 26.784h-17.28c-33.152 0-62.496-17.792-79.12-44.192h93.040l-0.272-173.696h279.232l0.016 124.448zM466.496 243.2c65.84 0 118.656 53.376 118.656 118.688 0 65.344-52.816 118.096-118.656 118.096-65.312 0-118.144-52.768-118.144-118.096 0-65.312 52.832-118.688 118.144-118.688zM349.136 178.976h-344.576l165.184-108.752 179.392 108.752zM0 142.576v-174.592h353.712v174.592l-184.768-110.976-168.944 110.976z" horiz-adv-x="656" /> -<glyph unicode="" d="M237.072 193.152h163.536l31.6 58.384h-197.776l1.584-56.768c0.32-0.48 0.72-1.088 1.056-1.616zM312.16 79.008h82.544l-0.16 2.4-73.344 40.464 10.56 19.2h-60.352c16.48-25.024 33.2-50.432 39.744-60.496 0.336-0.512 0.688-1.056 0.992-1.568zM176.272 480v-152.544l67.504 0.4-3.744-24.224h194.608v-47.584l36.080 66.64v157.312h-294.464zM434.656 362.032h-223.248v52.096h223.248v-52.096zM205.536 185.152l-2.272 81.36 4.672 30.416-110.848-0.656 0.304-109.792c0 0-82.912-131.552-90.384-145.28-7.472-13.728-24.464-72.096 51.968-72.992 76.432-0.928 191.104 0.928 191.104 0.928s42.256-2.96 51.568 26.208c9.296 29.152-1.872 46.384-16.24 68.512-14.384 22.128-79.856 121.312-79.856 121.312zM45.36 52.928l75.872 126.752v94.336h60.16l0.464-95.888 76.592-125.2h-213.088zM362.912 133.952l110.336-60.864 7.76 14.080-110.352 60.832zM478.416 22.352c40.032 8.624 91.888 27.408 107.584 67.712 24.384 62.736-49.744 123.056-67.616 136.448l59.408 109.728-49.568 28.128-99.904-184.544 10.624-6.016-12.976-23.664 26.96-15.52 13.088 23.824 11.888-6.736 20.816 38.496c21.648-17.504 60.48-56.672 49.328-85.36-11.888-30.608-80.576-46.224-121.056-48.88l2.144-33.136h-62.672v-38.464h251.072v37.696h-106.352l-32.752 0.32z" /> -<glyph unicode="" d="M256 424.784c110.432 0 200.784-90.352 200.784-200.784s-90.352-200.784-200.784-200.784c-110.432 0-200.784 90.352-200.784 200.784s90.352 200.784 200.784 200.784zM256 480c-142.224 0-256-113.776-256-256s113.776-256 256-256c140.544 0 256 113.776 256 256s-115.456 256-256 256v0zM209.152 101.856c6.688 1.68 11.712 3.344 13.392 5.024 3.344 3.344 5.024 10.032 5.024 18.4v113.776c0 8.368-1.68 13.392-3.344 16.736-3.344 3.344-8.368 5.024-15.056 6.688v10.032h75.296v-147.248c0-8.368 1.68-13.392 3.344-16.736 3.344-1.68 6.688-5.024 15.056-5.024v-10.032h-92.032v8.368zM235.92 352.832c6.688 6.688 13.392 8.368 21.744 8.368s15.056-3.344 21.744-8.368c5.024-6.688 6.688-13.392 6.688-21.744 0-8.368-3.344-15.056-8.368-21.744-6.688-6.688-13.392-8.368-21.744-8.368-8.368 0-15.056 3.344-21.744 8.368-6.688 6.688-8.368 13.392-8.368 21.744 0 8.368 3.344 15.056 10.032 21.744z" /> -<glyph unicode="" d="M613.984 229.888v-205.184h-557.296v205.184h-56.688v-261.888h670.672v261.888zM521.312 399.44l-189.392-240.432-182.576 235.92 125.856 1.552v83.52h119.408v-77.6z" horiz-adv-x="672" /> -<glyph unicode="" d="M462.528 431.136c0 26-17.92 48.368-40.624 48.864l-0.176-0.864-358.736 0.864c-21.2 0-39.056-19.824-40.592-44.592l-0.016-7.184-16.704 0.048c-3.040 0.016-5.568-1.44-5.568-3.248l-0.128-38.448c0.048-1.808 2.528-3.296 5.584-3.28l16.688-0.048-0.112-45.44-16.464 0.048c-3.056-0.016-5.568-1.504-5.568-3.28l-0.128-38.464c0.016-1.792 2.528-3.264 5.584-3.28l16.448-0.048-0.112-45.44-16.256 0.048c-3.056-0.016-5.584-1.472-5.584-3.28l-0.080-38.432c0-1.792 2.512-3.312 5.568-3.296l16.24-0.032-0.112-45.456-16.016 0.032c-3.056 0.016-5.568-1.44-5.552-3.232l-0.128-38.432c0-1.824 2.512-3.312 5.568-3.28l16-0.048-0.112-45.456-15.792 0.032c-3.056-0.016-5.568-1.456-5.552-3.248l-0.128-38.48c0-1.824 2.512-3.28 5.584-3.248l15.744-0.048-0.016-6.816c-0.080-26.384 18.032-47.936 40.48-48.032l0.672-0.032 358.32-0.88c21.84 0 40.112 20.96 40.72 46.752l0.080 0.176-0.080 1.040 1.024 417.456zM420.816 13.952l-0.016-1.008c0-0.048-0.016-0.080-0.016-0.128l0.048 14.88-0.224-16.416c-0.4-2.464-1.312-4.080-1.968-4.896l-354.576 0.896c-0.848 1.072-2.080 3.44-2.080 7.232l0.016 6.8 13.68-0.048c3.088-0.032 5.6 1.488 5.6 3.264l0.080 38.448c0.048 1.792-2.496 3.248-5.568 3.312l-13.68 0.032 0.112 45.424 13.456-0.048c3.056 0 5.584 1.44 5.6 3.296l0.080 38.416c0 1.792-2.496 3.296-5.6 3.312l-13.44 0.032 0.112 45.456 13.232-0.032c3.072-0.048 5.6 1.424 5.616 3.232l0.080 38.448c0 1.808-2.496 3.312-5.6 3.312l-13.216 0.032 0.112 45.44 13.040-0.032c3.072-0.032 5.584 1.44 5.616 3.248l0.048 38.464c0.016 1.776-2.464 3.248-5.568 3.28l-13.040 0.032 0.112 45.456 12.832-0.032c3.072-0.016 5.6 1.456 5.616 3.264l0.064 38.432c0.016 1.808-2.512 3.28-5.568 3.28l-12.832 0.032 0.016 3.952v0.288c0.096 3.68 1.312 5.952 2.112 6.976h354.624c0.864-1.088 2.112-4.336 2.112-8.128l-1.008-417.216zM72.864-34.016l-10.4 0.608h-0.384zM347.984 260.88c9.568-0.032 17.44 3.888 17.456 9.36l0.288 116.832c0.032 5.504-7.824 9.968-17.424 10.048l-218.688 0.496c-9.6 0.016-17.424-4.432-17.456-9.904l-0.288-116.832c-0.016-5.488 7.84-9.984 17.392-10.016h218.688zM239.312 221.664c-11.104 0-20.144-9.008-20.144-20.112v-22.656c0-11.12 9.040-20.128 20.144-20.128h22.64c11.136 0 20.128 9.008 20.128 20.128v22.656c0 11.104-8.992 20.112-20.128 20.112h-22.64zM147.184 216.544c-7.072 0-12.8-5.76-12.8-12.832v-14.416c0-7.088 5.712-12.8 12.8-12.8h14.432c7.056 0 12.8 5.712 12.8 12.8v14.416c0 7.072-5.744 12.832-12.8 12.832h-14.432zM342.784 216.544c-7.376 0-13.328-5.968-13.328-13.328v-14.992c0-7.328 5.952-13.328 13.328-13.328h14.976c7.36 0 13.328 5.984 13.328 13.328v14.992c0 7.36-5.968 13.328-13.328 13.328h-14.976zM373.968 165.696h-47.408c-10.032 0-18.144-8.592-18.144-19.168v-13.328c-5.008 7.056-12.976 11.632-21.968 11.632h-71.648c-7.984 0-15.12-3.6-20.128-9.312v13.648c0 10.176-7.808 18.432-17.472 18.432h-45.6c-9.648 0-17.472-8.256-17.472-18.432v-43.872h14.032v44.4h3.792v-44.4h43.792v44.4h3.792v-44.4h7.84v-58.304h22.032v69.728h5.952v-69.728h68.8v69.728h5.92v-69.728h23.84c0 0.064 0 1.28 0 15.216v38.736h9.056v46.128h3.968v-46.128h45.52v46.128h3.936v-46.128h15.744c0 0 0 0.816 0 10.064v35.504c0 10.576-8.144 19.168-18.176 19.168z" /> -<glyph unicode="" d="M541.616 412.512h-230.224c-5.008 17.504-0.896 67.488-41.024 67.488h-166.256c-35.68 0-36-49.984-41.008-67.488h-0.256c-35.248 0-62.848-24.384-62.848-55.568v-333.376c0-31.152 27.6-55.568 62.848-55.568h478.768c35.216 0 62.848 24.416 62.848 55.568v333.376c-0.016 31.184-27.616 55.568-62.848 55.568zM410.912 288.88c0 10.48 8.48 18.976 18.976 18.976h21.312c10.464 0 18.992-8.496 18.992-18.976v-21.328c0-10.464-8.512-18.976-18.992-18.976h-21.328c-10.496 0-18.976 8.528-18.976 18.976v21.328zM253.84 286.544c0 15.824 12.88 28.64 28.704 28.64h32.24c15.84 0 28.672-12.816 28.672-28.64v-32.272c0-15.824-12.816-28.672-28.672-28.672h-32.24c-15.824 0-28.704 12.848-28.704 28.672v32.272zM133.12 289.6c0 10.080 8.144 18.256 18.224 18.256h20.544c10.048 0 18.24-8.176 18.24-18.256v-20.528c0-10.096-8.176-18.208-18.24-18.208h-20.544c-10.080 0-18.224 8.128-18.224 18.208v20.528zM500.16 157.616c0-13.168 0-14.304 0-14.304l-22.432-0.048v65.68h-5.584v-65.68h-64.832v65.68h-5.648v-65.68h-12.912v-55.136c0-19.84 0-21.584 0-21.68h-33.952v99.312h-8.432v-99.312h-97.968v99.312h-8.48v-99.312h-31.376v83.024h-11.152v63.232h-5.392v-63.232h-62.352v63.232h-5.392v-63.232h-20v62.464c0 14.48 11.136 26.24 24.88 26.24h64.928c13.76 0 24.896-11.76 24.896-26.24v-19.552c7.136 8.176 17.28 13.376 28.672 13.376h102c12.848 0 24.16-6.624 31.28-16.704v19.12c0 15.056 11.6 27.296 25.856 27.296h67.504c14.288 0 25.872-12.24 25.872-27.296l0.016-50.56z" horiz-adv-x="608" /> -<glyph unicode="" d="M277.984 225.616h32.224c15.856 0 28.656 12.848 28.656 28.656v32.256c0 15.808-12.816 28.64-28.656 28.64h-32.224c-15.808 0-28.688-12.832-28.688-28.64v-32.256c0-15.808 12.88-28.656 28.688-28.656zM146.8 250.864h20.544c10.064 0 18.256 8.128 18.256 18.208v20.528c0 10.064-8.176 18.256-18.256 18.256h-20.544c-10.080 0-18.224-8.192-18.224-18.256v-20.528c0-10.080 8.128-18.208 18.224-18.208zM425.328 248.56h21.328c10.48 0 18.992 8.528 18.992 18.992v21.328c0 10.48-8.512 18.992-18.992 18.992h-21.328c-10.48 0-18.976-8.512-18.976-18.992v-21.328c0-10.464 8.496-18.992 18.976-18.992zM469.744 235.472h-67.504c-14.272 0-25.856-12.24-25.856-27.296v-18.896c-7.12 10.016-18.48 16.48-31.264 16.48h-102.032c-11.328 0-21.52-5.072-28.656-13.2v19.376c0 14.464-11.104 26.24-24.896 26.24h-64.928c-13.728 0-24.864-11.776-24.864-26.24v-62.464h20v63.216h5.36v-63.216h62.352v63.216h5.408v-63.216h11.152v-83.040h31.376v99.312h8.464v-99.312h97.984v99.312h8.416v-99.312h33.952c0 0.112 0 1.824 0 21.68v55.136h12.912v65.664h5.648v-65.68h64.832v65.68h5.6v-65.68h22.432c0 0 0 1.184 0 14.336v50.56c-0.016 15.088-11.616 27.328-25.888 27.344v0zM513.376-32h-431.44c-45.952 0-81.936 33.104-81.936 75.376v300.432c0 35.552 25.456 64.624 60.864 72.976 4.448 23.232 15.568 63.216 58.272 63.216h149.84c44.128 0 54.896-38.176 58.592-60.8h185.808c45.952 0 81.952-33.12 81.952-75.392v-300.432c0-42.272-36-75.376-81.952-75.376zM82.192 368.576c-17.808 0-31.584-10.88-31.584-24.784v-300.432c0-13.888 13.744-24.752 31.328-24.752h431.44c17.584 0 31.328 10.864 31.328 24.752v300.432c0 13.904-13.744 24.784-31.328 24.784h-226.544l-5.248 18.336c-1.456 5.12-2.192 10.736-2.944 16.704-3.312 25.76-6.384 25.76-9.664 25.76h-149.84c-0.784 0-1.104-0.096-1.104-0.096-4.192-2.928-7.488-21.84-8.56-28.064-0.896-5.12-1.744-9.984-2.96-14.288l-5.232-18.336-19.088-0.016z" horiz-adv-x="592" /> -<glyph unicode="" d="M366.784 295.552h66.4c32.624 0 59.008 26.416 59.008 58.992v66.448c0 32.576-26.384 59.008-59.008 59.008h-66.4c-32.608 0-59.088-26.416-59.088-59.008v-66.448c0-32.576 26.48-58.992 59.088-58.992zM96.56 347.504h42.32c20.72 0 37.568 16.72 37.568 37.52v42.304c0 20.752-16.832 37.6-37.568 37.6h-42.32c-20.768 0-37.552-16.832-37.552-37.6v-42.304c0-20.784 16.768-37.52 37.552-37.52zM670.272 342.8h43.936c21.584 0 39.136 17.504 39.136 39.088v43.984c0 21.536-17.552 39.056-39.136 39.056h-43.936c-21.584 0-39.024-17.504-39.024-39.056v-43.968c0-21.568 17.44-39.088 39.024-39.088v-0.016zM761.76 315.12h-139.040c-29.392 0-52.848-24.544-52.848-55.552v-38.912c-16.048 20.624-38.496 34.272-64.864 34.272h-210.112c-23.328 0-44.080-10.768-58.128-27.472v39.888c0 29.872-23.824 53.824-52.192 53.824h-133.744c-28.32 0-50.832-23.952-50.832-53.808v-128.784h40.144v130.416h12.032v-130.416h128.416v130.416h10.032v-130.416h24.064v-170.56h64.208v204.688h18.048v-204.688h200.672v204.688h18.048v-204.688h70.24c0 0 0 3.408 0 44.32v114.224h26.080v134.432h12.032v-134.432h132.416v134.432h12.048v-134.432h46.176c0 0 0 1.792 0 28.896v104.176c0 31.008-23.504 55.552-52.928 55.552v-0.048z" horiz-adv-x="816" /> -<glyph unicode="" d="M278.24 265.888h-59.664c-0.56-14.928 2.496-30.48 8.064-46.080h133.184v-205.728h-313.744v205.728h40.912c-6.352 14.656-10.528 30.080-12.48 46.080h-74.512v-297.888h405.904v297.888h-127.664zM263.040 290.752l61.088 105.856-87.728 83.408 2.176-57.088c-30.896-7.12-59.872-17.504-86.048-32.896-27.12-13.824-42.16-35.664-49.296-64.896-9.344-40.352-3.936-76.88 13.696-108.208 18.496-33.088 49.088-65.808 91.392-99.216 17.744-13.376 35.952-25.744 54.496-36.992 18.96-10.128 39.088-20.976 61.312-30.32 0 0-148.368 122.816-129.664 231.312-0.56 15.936 4.144 29.36 12.608 41.184 8.576 11.696 24.416 18.64 44.992 22.096l10.96-54.224z" /> -<glyph unicode="" d="M541.616-31.984h-478.768c-35.248 0-62.848 24.416-62.848 55.568v333.376c0 31.184 27.6 55.6 62.848 55.6h0.272c4.992 17.472 5.328 67.44 41.008 67.44h166.256c40.128 0 36.016-49.984 41.024-67.472h230.208c35.216 0 62.832-24.416 62.832-55.6v-333.376c-0.016-31.136-27.616-55.552-62.832-55.536v0 0z" horiz-adv-x="608" /> -<glyph unicode="" d="M513.376-31.984h-431.44c-45.936 0-81.936 33.104-81.936 75.36v300.416c0 35.552 25.456 64.624 60.864 72.992 4.448 23.232 15.584 63.216 58.272 63.216h149.824c44.128 0 54.896-38.176 58.592-60.8h185.808c45.952 0 81.952-33.12 81.952-75.392v-300.448c0.016-42.256-35.984-75.36-81.936-75.344v0zM82.192 368.592c-17.824 0-31.584-10.88-31.584-24.784v-300.432c0-13.872 13.744-24.752 31.328-24.752h431.44c17.568 0 31.312 10.88 31.312 24.752v300.432c0 13.904-13.744 24.784-31.312 24.784h-226.528l-5.248 18.352c-1.456 5.12-2.192 10.736-2.944 16.672-3.312 25.76-6.384 25.76-9.664 25.76h-149.84c-0.784 0-1.104-0.096-1.104-0.096-4.176-2.944-7.472-21.856-8.56-28.080-0.896-5.12-1.728-9.984-2.96-14.288l-5.232-18.336-19.104 0.016z" horiz-adv-x="592" /> -<glyph unicode="" d="M451.712 380.288l-71.44 71.424c-15.552 15.552-46.288 28.288-68.288 28.288h-240c-22 0-40-18-40-40v-432c0-22 18-40 40-40h368c22 0 40 18 40 40v304c0 22-12.736 52.736-28.288 68.288zM429.088 357.664c1.568-1.568 3.12-3.488 4.64-5.664h-81.728v81.728c2.176-1.52 4.096-3.072 5.664-4.64l71.44-71.424zM448 8c0-4.336-3.664-8-8-8h-368c-4.336 0-8 3.664-8 8v432c0 4.336 3.664 8 8 8h240c2.416 0 5.12-0.304 8-0.848v-127.152h127.152c0.544-2.88 0.848-5.584 0.848-8v-304z" /> -<glyph unicode="" d="M488.896 202.48c-1.376 31.92-6.24 63.984-14.592 96.224-8.864 35.952-21.36 70.032-36.384 101.632-22.928 47.296-45.168 70.784-67.856 69.488-18.272-1.072-29.504-16.64-34.288-47.984-54.544-77.392-155.44-131.136-239.952-167.36-28.736-14.912-42.288-37.28-40.976-67.776 2.848-52.464 18.448-77.968 46.896-76.48 0.848 0.336 2.304 0.384 4.016 1.056 2.32 0.416 3.152 0.704 3.776 0.448 25.52 1.392 45.2-23.072 58.384-73.104 9.952-41.424 20.32-73.856 70.544-71.424 10.992 0.8 15.568 2.992 15.952 7.104-0.72 3.184-73.328 157.36-40.848 158.48 59.184 3.44 158.128 1.84 209.792-29.088 14.576-8.656 24.672-13.184 28.416-12.72 16.56 0.416 27.808 16.080 33.248 45.648 3.52 19.040 4.928 41.232 3.856 65.872zM258.304 148.384c-23.536-0.144-35.728-0.384-37.2-0.432-17.536 2.144-31.648 12.016-41.392 29.936-7.888 14.16-12.432 31.104-13.552 50.848-1.008 23.216 11.76 43.84 39.168 62.16 22.624 15.536 45.456 31.632 68.656 46.896 25.376 18.528 45.216 37.376 59.456 58.080l-2.4-38.8c1.392-39.792 8.944-80.16 22.112-122.304 13.872-45.36 31.472-82.4 53.104-112.016-42.672 17.648-92.128 26.256-147.968 25.616zM78.096 112.992c-18.656 14.016-28.88 35.68-30.432 65.568-1.072 24.704 3.36 42.592 13.312 55.248-28.928-16.944-43.376-25.424-44.24-25.776-12.032-10.976-17.488-26.336-16.64-46.64 0.896-20.304 9.392-34.768 26.224-41.584 10.096-4.528 27.648-6.656 51.776-6.8v0zM647.184 328.832c-4.944 39.888-19.2 73.28-42.384 99.328-23.28 27.504-54.848 44.48-93.488 51.84 32.464-11.68 59.168-37.84 80.976-78.224 17.12-33.296 28.32-70.336 33.568-111.088 5.36-43.712 1.808-83.392-9.936-120.816 27.744 50.896 38 103.968 31.264 158.976v0zM596.944 313.536c-3.712 31.568-14.72 57.824-33.648 79.12-18.688 21.888-43.728 35.92-74.72 41.28 25.68-9.376 47.536-30.544 64.592-62.336 13.648-26.736 23.056-56.608 27.072-89.008 4.4-34.688 1.424-66.832-8.096-96 22.384 40.512 30.528 82.432 24.8 126.944v0zM552.496 298.592c-3.088 24.848-12.16 45.984-27.136 63.376-15.008 17.36-34.976 28.4-59.888 33.184 20.672-7.824 38-24.8 51.328-50.736 11.952-20.96 19.040-44.784 21.904-70.288 3.856-28.048 1.472-53.984-6.256-77.6 17.504 32.736 24.768 66.464 20.032 102.064z" /> -<glyph unicode="" d="M821.568 351.44c-96.128 86.112-216.864 128.56-359.92 128.56-141.968 0-262.688-42.448-359.92-128.56-39.136-35.76-73.808-78.24-101.728-127.456 27.936-50.288 62.608-92.752 101.728-127.424 97.232-86.064 217.952-128.56 359.92-128.56 143.056 0 263.792 42.496 359.92 128.56 40.272 34.672 73.776 77.152 101.728 127.424-27.952 49.216-61.456 91.696-101.728 127.456zM770.16 118.944c-82.736-70.496-185.536-105.088-308.512-105.088-121.872 0-224.704 34.592-308.512 105.088-33.536 29.024-62.608 63.632-87.216 105.040 24.608 40.24 53.664 76.048 87.216 105.088 83.824 70.448 186.64 105.12 308.512 105.12 122.976 0 225.776-34.656 308.512-105.12 34.672-29.040 63.696-64.848 87.168-105.088-23.472-41.408-52.496-76.016-87.168-105.040zM461.648 307.856c-45.808 0-83.84-37.984-83.84-83.872 0-45.808 38.016-83.84 83.84-83.84s83.824 38.048 83.824 83.84c0 45.888-38 83.872-83.824 83.872zM461.648 418.48c-107.296 0-195.6-87.136-195.6-194.496 0-107.296 88.304-195.584 195.6-195.584s195.6 88.304 195.6 195.584c0 107.344-88.272 194.496-195.6 194.496zM461.648 108.864c-63.712 0-115.12 51.408-115.12 115.12 0 63.696 51.408 115.152 115.12 115.152 63.68 0 115.12-51.456 115.12-115.152 0.016-63.712-51.44-115.12-115.12-115.12z" horiz-adv-x="928" /> -<glyph unicode="" d="M130.736 285.056h-126.016c-2.816 0-4.72-1.616-4.72-4.032v-8.448c0-2.416 1.888-4.080 4.72-4.080h13.12v-248.784c0-27.376 22.288-49.92 49.696-49.92 27.36 0 49.648 22.528 49.648 49.92v54.32l-12.736 13.296v-3.52h-73.872v182.128h73.872v-15.568l6.256-6.544 6.48-6.752v31.424h13.568c2.4 0 4.272 1.664 4.272 4.080v8.432c0 2.432-1.872 4.048-4.272 4.048zM126.608 313.536l8.288 1.632c2.384 0.464 3.968 2.848 3.44 5.616l-2.464 12.64 243.792 47.68c26.864 5.264 44.656 31.712 39.408 58.576-5.248 26.864-31.696 44.656-58.56 39.392l-243.808-47.68-2.544 13.072c-0.464 2.352-2.832 3.952-5.216 3.472l-8.288-1.616c-2.368-0.464-3.952-2.832-3.488-5.184l24.176-123.68c0.544-2.752 2.912-4.368 5.28-3.92zM364.224 467.136c6.256 0.496 12.896-0.048 17.76-1.68 5.984-2 10.736-6.592 10.736-6.592l-245.92-109.776-11.52-2.272-14.064 71.904 243.024 48.416zM215.68 4.848l-14.512-14.528-22.4 22.416c2.272-25.6 23.728-45.984 49.856-45.984 27.632 0 50.32 22.72 50.32 50.336v51.056l-63.264-63.296zM250.128 202.368h-58l-0.48 63.792h73.984v-48.288l13.296 13.28v37.008h13.328c2.96 0 4.928 1.984 4.928 4.432v8.416c0 2.432-1.968 4.448-4.928 4.448h-127.28c-2.464 0-4.432-2-4.432-4.448v-8.416c0-2.448 1.968-4.432 4.432-4.432h13.328v-91.968l22.832-22.816 48.992 48.992zM326.896 285.44c-2.464 0-4.432-2-4.432-4.448v-6.304l10.752 10.752h-6.32zM427.536 202.368h-14.368l-72.944-72.96v-112.352c0-27.616 22.672-50.336 50.288-50.336 27.648 0 50.32 22.72 50.32 50.336v212.976l-13.296-13.28v-14.384zM201.136 124.352l-104.976 104.976-52.496-52.464 157.488-157.504 313.52 313.568-52.496 52.464z" /> -<glyph unicode="" d="M213.456 299.792c-2.576 0-4.624-2.080-4.624-4.608v-8.736c0-2.56 2.048-4.592 4.624-4.592h13.84v-86.688l45.008 45.008h-30.656l-0.512 39.616h70.784l20.016 20.016h-118.48zM279.504-31.152c28.672 0 52.24 23.6 52.24 52.272v93.408l-103.456-103.472c4.736-23.936 25.952-42.208 51.216-42.208zM18.8 72.544v-48.496c0-27.072 22.272-49.344 49.376-49.344 13.312 0 25.408 5.424 34.336 14.128l-83.712 83.712zM31.92 207.392v60.32h72.448v-95.632l13.152-13.152v110.752h13.152c2.368 0 4.384 2.016 4.384 4.4v8.352c0 2.4-2 4.384-4.384 4.384h-124.592c-2.784 0-4.8-1.984-4.8-4.384v-8.352c0-2.4 2.016-4.4 4.8-4.4h12.736v-75.392l11.36 11.36 1.76 1.744zM126.592 314.56l8.192 1.6c2.352 0.464 3.936 2.816 3.408 5.552l-2.448 12.496 241.040 47.152c26.576 5.2 44.16 31.344 38.96 57.904-5.184 26.56-31.328 44.16-57.904 38.96l-241.072-47.136-2.528 12.912c-0.448 2.32-2.8 3.904-5.152 3.456l-8.208-1.6c-2.336-0.464-3.904-2.816-3.44-5.152l23.904-122.272c0.544-2.736 2.88-4.32 5.216-3.872zM361.536 466.448c6.208 0.48 12.752-0.064 17.568-1.664 5.904-1.968 10.592-6.512 10.592-6.512l-243.152-108.56-11.392-2.224-13.888 71.088 240.272 47.872zM154.288 81.504l-103.808 103.792-51.904-51.856 155.712-155.744 310 310.080-51.888 51.856z" /> -<glyph unicode="" d="M29.568 102.784v173.424h69.792v-63.072l4.896 4.88 7.76 7.776v52.32h12.672c2.272 0 4.224 1.952 4.224 4.24v8.048c0 2.32-1.952 4.224-4.224 4.224h-120.064c-2.672 0-4.624-1.92-4.624-4.224v-8.048c0-2.32 1.952-4.24 4.624-4.24h12.272v-236.672c0-26.080 21.456-47.552 47.584-47.552 26.048 0 47.552 21.472 47.552 47.552v23.84l-37.504 37.504h-44.96zM120.8 321.36l7.888 1.552c2.272 0.448 3.792 2.72 3.264 5.36l-2.336 12.048 232.288 45.424c25.6 5.024 42.544 30.192 37.552 55.824-5.008 25.616-30.208 42.56-55.792 37.568l-232.336-45.456-2.416 12.448c-0.432 2.224-2.688 3.76-4.944 3.312l-7.904-1.552c-2.256-0.448-3.76-2.688-3.312-4.912l23.056-117.856c0.512-2.608 2.752-4.176 5.024-3.728l-0.032-0.032zM347.168 467.712c5.984 0.464 12.288-0.048 16.944-1.6 5.68-1.888 10.208-6.288 10.208-6.288l-234.32-104.576-10.976-2.176-13.392 68.496 231.536 46.144zM235.904 86.352l-118.32 118.304-59.152-59.104 177.504-177.552 353.408 353.488-59.136 59.12-294.304-294.256z" horiz-adv-x="592" /> -<glyph unicode="" d="M512 480v-192l-69.136 69.136-106-106-53.744 53.744 106 106-69.136 69.136zM122.864 410.864l106-106-53.744-53.744-106 106-69.136-69.136v192h192zM442.864 90.864l69.136 69.136v-192h-192l69.136 69.136-106 106 53.744 53.744zM228.864 143.136l-106-106 69.136-69.136h-192v192l69.136-69.136 106 106z" /> -<glyph unicode="" d="M449.184 11.872h-407.104v296l351.936 0.176 64.416 43.632h-458.432v-383.68h491.28v208.16l-42.096-28.656v-135.632zM227.344 204.512c16.016 9.92 19.536 18.176 6.576 27.28-18.672 4.368-25.136-3.072-31.136-0.416-5.008 12.816-17.104 14.8-24.064 16.528-11.104 2.736-11.104-8.336-20.72-2.784-13.568 7.792-10.592 19.552-33.632 19.392-24.592 0.16-46.464-31.6-16.352-58.32 17.392-11.024 97.28-10.352 119.328-1.68v0zM412.912 124.928l-142.928-28.912c0 0-21.984-4-30.512 8.080-2.672 3.76-3.168 8.048-2.784 12.176-0.096-0.064-0.176-0.144-0.256-0.224-43.52-2.624-44.8 41.84-85.136 29.568-25.408-11.088-40.512-65.104-44.832-110.784 110.56 0 221.12 0 331.68 0-5.44 28.832-14 61.264-25.232 90.096v0zM365.952 239.44l253.888 169.776-9.968 14.944-253.888-169.792 9.968-14.928zM756.688 449.52l-5.312 7.536c-15.488 23.792-47.984 30.192-71.328 13.952l-54.496-36.464 62.56-93.408 54.496 36.48c23.76 15.536 30.16 47.984 14.080 71.904v0zM409.568 175.040l9.552-14.208 253.28 169.904-9.568 14.224-253.264-169.92zM263.84 120.016l139.616 30.4-63.104 93.52-76.512-123.92zM632.816 391.216l-0.544-0.368-4.080 6.304-253.872-169.76 8.144-12.608 1.136 0.768 8.32-13.072-0.672-0.448 9.408-14.784 253.872 169.728-9.2 13.712 0.656 0.464-13.168 20.064z" horiz-adv-x="768" /> -<glyph unicode="" d="M0-32.272l139.104 72.448-93.808 80.864zM426.976 458.72l-7.792 6.48c-23.28 20.72-59.52 18.128-79.568-5.808l-47.216-54.336 93.184-80.896 47.216 54.352c20.688 23.28 18.096 59.504-5.824 80.208zM293.696 376.608l-14.896 12.944-219.92-252.976 14.864-12.944zM138.448 68l14.208-12.304 219.328 252.944-14.224 12.32zM312.592 361.296l-0.48-0.56-6.128 5.488-219.92-252.96 12.272-10.992 0.976 1.136 12.544-11.44-0.592-0.688 14.256-12.96 219.952 252.96-13.696 11.872 0.56 0.672z" /> -<glyph unicode="" d="M521.392 224.224l-99.792 99.824v-72.192h-130.864v130.864h72.72l-99.84 99.792-99.824-99.792h72.176v-130.864h-130.848v72.192l-99.792-99.824 99.792-99.84v72.704h130.848v-130.832h-72.176l99.824-99.808 99.84 99.808h-72.72v130.832h130.864v-72.704z" /> -<glyph unicode="" d="M434.848 321.92c0.064 0.064 0.208 0.16 0.368 0.304l0.208 0.208-0.576-0.512zM0 479.984h107.648c72.96 1.776 98.128-126.624-10.816-129.12h-32.256v-75.312h-64.576v204.432zM64.576 393.92h21.504c32.448 2.192 28.144 42.336 0 43.072h-21.504v-43.072zM182.944 479.984h96.8c124.48-0.96 121.808-205.856 0-204.432h-96.8v204.432zM247.552 436.976v-118.336h10.752c76.368 1.504 75.808 118.704 0 118.336h-10.752zM396.592 479.984h161.456v-43.008h-96.864v-32.24h86.096v-43.104h-86.096v-86.080h-64.592v204.432zM359.792 208.8h-198.656v-77.92h-98.656l197.312-162.944 197.2 162.944h-97.2z" /> -<glyph unicode="" d="M396.944 292.144l-89.216 44.864 61.376 123.024c9.904 19.84 37.92 25.936 62.592 13.616v0c24.704-12.32 36.688-38.368 26.784-58.192l-61.536-123.296zM376.944 224.432l20.848-10.416 88.784 177.888-20.864 10.4-88.768-177.872zM198.768 2.448c5.248 6.096 12.944 14.64 21.728 24.224l-15.888 7.92c-1.968-10.816-3.968-21.664-5.84-32.144zM293.232 104.544l91.184 183.536-68.992 34.432-91.648-183.648c0 0-0.016-0.208-0.032-0.256l69.072-34.464c0.256 0.224 0.384 0.384 0.384 0.384zM222.032 129.36c-2.928-15.888-9.2-49.776-15.76-85.504l20.592-10.304c21.584 23.536 47.424 50.896 59.536 63.664l-64.368 32.144zM313.952 16.752c2.176 12.656 1.504 25.184 0.576 37.888 10.272 1.28 16.464 8.144 23.792 14.576 17.424 15.152-0.080 63.968-24 45.184-9.984-7.84-10.928-37.968-10.736-50.16-8-0.512-9.504 3.44-17.888-0.784 2.224-7.648 11.664-9.952 18.48-9.552 1.008-12.016 1.632-23.392-0.448-35.392-1.296-7.52-2.512-32.528-10.272-38.336-16.496-4.768-20.656 7.552-34.624 6.016 3.184-9.568 14.416-18.208 24.816-18.208 26.736 0 26.736 28.192 30.288 48.768zM313.936 65.024c-0.064 6.688 1.472 41.968 10.48 41.968 22.896 0 6.608-39.296-10.48-41.968zM331.856-21.28c1.2 3.072-0.016 7.376-5.536 9.568h-1.616l-2.528-2.992c-2.672-7.12 1.36-9.28 2.656-9.792l7.024 3.216zM429.968 33.744c-15.408-0.352-32.672 15.584-41.44 27.136 66 26.416-1.264 109.904-35.184 62.256 34.448 9.056 85.008-30.88 25.184-58.096 0.208 17.232-0.032 39.376-0.048 40.656l-10.352-0.112c0.464-30.32-10.336-80.784-0.048-98.896 6.704 16.224 10.144 32.896 10.32 50.016 21.664-16.928 31.36-32.080 61.088-33.344l0.512 10.336c-3.552 0.192-6.88 0.112-10.016 0.048-10.224-0.24 3.136 0.064 0 0zM453.232 36.4l-1.904 7.344-1.824-2.816 1.456 2.912c-0.96 0.48-5.696 3.264-5.712 3.296l-5.232-8.944c4.528-2.656 7.376-4.32 9.52-4.32 1.456 0 2.576 0.752 3.68 2.512zM473.952 143.392l-10.272-1.408c4.528-33.536 5.376-59.808-0.928-93.888-0.672-3.616-1.328-7.168-1.952-10.688l10.208-1.776c6.688 38.096 8.064 69.776 2.944 107.744zM505.264 120.896c17.952 21.968-4.272 46.752-25.088 51.568-22.24 5.152-28.432-5.808-29.232-7.424l-6.896-16.736 9.568-3.936 6.624 16.144c0.032 0.064 3.52 5.12 17.6 1.856 34.176-7.888 22.224-33.36 1.84-47.952 67.936-8.208 22.944-48.192-8.64-71.056l6.064-8.4c16.464 11.904 89.84 73.616 28.144 85.936zM556.24 115.408c32.48-38.304 37.104 13.152 45.984 30.528 0.192-0.304 16.464-21.984 21.424-20.592 4.656 7.232 6.592 14.864 5.824 22.912 11.344-45.856 62.064 21.488 29.184 31.392-23.984 7.296-40.48-14.928-39.52-35.152-12.672 19.088-19.408 12.368-29.776 0.832-2.352 1.856-5.008 2.592-7.968 2.16 15.584-59.552-12.48-7.664-32.464-12.496-5.168-1.216-17.696-45.648-18.944-50.672l10.016-2.608c3.664 11.68 10.64 22.864 16.224 33.712zM629.92 157.232c-0.784 9.264 18.736 14.592 25.744 12.48 5.728-1.728-1.856-45.040-18.512-9.2l-7.232-3.28zM633.216 55.12c25.984 0 65.040 126.528 82.96 149.888-0.912-6.352-1.504-16 0.288-22.576l10 2.704c-2.384 8.656 4.832 30.992-10.336 31.136-15.648-0.704-12.464-34.288-23.536-41.152 9.344 68.112-60.384-7.2-14.528-11.664-7.472-8.88-16.544-15.584-20.128-24.656v0c-0.592-6.704-61.472-83.648-24.72-83.648v0zM658.768 115.536c0.128-19.008-8.608-39.392-25.056-49.712-11.28 11.216 16.48 43.344 25.056 49.712 0.016-2.976-1.52-1.136 0 0zM675.168 174.496c-0.8 9.568-3.232 11.808 2.576 17.904 5.168-5.488 6.512-11.808 4-19.008-2.192 0.224-4.368 0.576-6.512 1.088-0.048 0-0.064 0-0.080 0zM747.216 201.488c7.232-7.616-16.848-18.528-11.968-18.288 5.856 0.288 23.456 12.064 25.28 16.608 2.896 7.264-3.36 13.632-9.104 11.408-21.568-8.336-7.216 20.608-6.176 22.128-6.336-9.296-19.36-12.032-14.208-28.352zM257.888 415.392c9.84 19.68-2.064 45.552-26.608 57.808v0c-24.496 12.24-52.304 6.16-62.128-13.52l-60.96-122.16 88.592-44.576 61.104 122.448zM176.928 225.728l20.704-10.352 88.16 176.656-20.72 10.336-88.144-176.64zM0 5.328c5.216 6.016 12.848 14.528 21.568 24.048l-15.76 7.872c-1.968-10.736-3.952-21.536-5.808-31.92zM93.808 106.688l90.544 182.272-68.496 34.176-91.008-182.352c0 0-0.016-0.208-0.032-0.256l68.592-34.224c0.24 0.224 0.384 0.384 0.384 0.384zM23.104 131.328c-2.912-15.792-9.152-49.408-15.648-84.896l20.448-10.208c21.424 23.344 47.088 50.544 59.104 63.216l-63.904 31.888z" /> -<glyph unicode="" d="M113.76-32l-113.76 112.848 142.432 143.648-142.208 142.208 113.296 113.296 255.072-255.040-254.832-256.96zM397.664-32l-113.76 112.848 142.448 143.648-142.192 142.208 113.296 113.296 255.056-255.040-254.848-256.96z" horiz-adv-x="656" /> -<glyph unicode="" d="M92.128 144.336c15.632 1.184 26.624 3.44 32.992 6.688 10.64 5.664 18.112 16.4 22.4 32.208l77.12 278.496c-40.48 0-67.232-3.056-80.272-9.152-13.040-6.112-28.208-24.608-45.536-55.536l-9.264 1.808 21.888 81.152h281.328l-23.184-86.048-9.28 1.296 1.296 18.288c0 16.144-3.664 28.208-10.992 36.208-7.312 7.984-21.808 11.984-43.488 11.984h-29.44l-73.92-262.528c-1.712-5.664-3.008-10.736-3.856-15.184-1.536-6.704-2.32-12.032-2.32-15.968 0-10.32 3.168-16.704 9.536-19.2 6.336-2.48 18.784-3.984 37.344-4.496v-8.496h-152.352v8.48zM0 82.88v26.032h301.616v-26.032h-301.616zM561.216 208.544l-49.12 49.104-95.712-95.76-95.76 95.76-49.088-49.104 95.76-95.728-95.76-95.712 49.088-49.104 95.76 95.712 95.712-95.712 49.12 49.104-95.744 95.712z" horiz-adv-x="560" /> -<glyph unicode="" d="M373.92 462.080c20.944-18.128 23.216-49.856 5.088-70.224l-41.344-47.616-81.616 70.848 41.344 47.584c17.584 20.96 49.312 23.232 69.696 5.088l6.832-5.68zM244.176 401.488l-192.608-221.536 12.992-11.328 192.64 221.552-13.024 11.312zM75.36 159.568l10.736-9.648 192.64 221.52-10.768 9.648-192.608-221.52zM97.456 140.32l12.464-11.344 192.608 221.504-13.056 11.328-192.016-221.488zM121.248 119.904l192.048 221.536 12.448-10.784-192.048-221.52-12.448 10.768zM121.808 95.552l-121.808-63.44 39.664 134.256 82.144-70.816zM291.024 361.472l-17.28 15.28-192.224-220.832 22.576-20.624zM543.52 208.544l-49.12 49.088-95.712-95.744-95.76 95.744-49.088-49.088 95.76-95.728-95.76-95.728 49.088-49.088 95.76 95.712 95.712-95.712 49.12 49.088-95.744 95.728z" horiz-adv-x="544" /> -<glyph unicode="" d="M416.576 413.36c0 24.896-16.912 45.52-38.368 45.984l-0.16-0.032-22.544 0.064 0.032 15.184c0.016 2.944-1.376 5.344-3.056 5.36l-36.272 0.080c-1.712 0.016-3.104-2.4-3.104-5.328l-0.048-15.2-32.784 0.080 0.032 15.008c0.016 2.944-1.376 5.344-3.056 5.36l-36.32 0.080c-1.712 0.016-3.104-2.4-3.104-5.328l-0.032-15.008-48.032 0.112 0.048 14.784c0.016 2.944-1.376 5.344-3.056 5.36l-36.288 0.080c-1.712 0.016-3.104-2.4-3.104-5.328l-0.032-14.8-38.128 0.096 0.032 14.592c0 2.944-1.376 5.344-3.072 5.36l-36.288 0.080c-1.712 0.016-3.104-2.4-3.104-5.328l-0.032-14.592-27.36 0.064c-20.016 0-36.864-18.976-38.336-42.688l-1.024-402.656c-0.080-25.248 17.056-45.872 38.224-45.968l0.288-0.032 338.656-0.832c20.64 0 37.888 20.064 38.448 44.736l0.096 0.176-0.080 1.008 0.96 399.456zM218.656 375.024h17.088l23.2-48.688 23.072 48.688h17.088v-90.032h-17.344v52.48l-16.96-34.128h-11.728l-17.072 34.128v-52.464h-17.344v90.016zM117.488 375.024h17.088l23.2-48.688 23.072 48.688h17.088v-90.032h-17.344v52.48l-16.976-34.128h-11.68l-17.12 34.128v-52.464h-17.328v90.016zM377.2 14.16l-0.016-0.976c-0.176-3.264-1.28-5.312-2.016-6.272l-334.8 0.864c-0.8 1.024-1.968 3.296-1.952 6.928l0.512 218.32h338.8l-0.528-218.864z" horiz-adv-x="416" /> -<glyph unicode="" d="M694.976 446.432h-224.944c-21.824 0-40.288-18.464-40.288-40.288v-132.624c0-21.824 18.464-40.288 40.288-40.288h224.944c21.824 0 40.288 18.464 40.288 40.288v132.624c0 21.824-18.464 40.288-40.288 40.288zM318.944 179.52h-224.944c-21.824 0-40.288-18.464-40.288-40.288v-132.624c0-21.824 18.464-40.288 40.288-40.288h224.944c21.824 0 40.288 18.464 40.288 40.288v132.624c0 21.824-18.464 40.288-40.288 40.288zM694.976 179.52h-224.944c-21.824 0-40.288-18.464-40.288-40.288v-132.624c0-21.824 18.464-40.288 40.288-40.288h224.944c21.824 0 40.288 18.464 40.288 40.288v132.624c0 21.824-18.464 40.288-40.288 40.288zM0 480h342.448v-45.328h-342.448v45.328zM0 387.664h342.448v-45.328h-342.448v45.328zM0 295.344h342.448v-45.328h-342.448v45.328z" horiz-adv-x="736" /> -<glyph unicode="" d="M512.576 393.12l-86.912 86.88-169.36-169.424-169.456 169.424-86.848-86.88 169.44-169.376-169.44-169.36 86.848-86.88 169.456 169.376 169.36-169.376 86.912 86.88-169.408 169.36z" /> -<glyph unicode="" d="M96.064 147.744h28.448c-1.136 5.376-2.32 11.072-3.52 17.008h-24.928v-17.008zM97.984 103.696h35.872l-3.6 17.008h-32.272v-17.008zM97.984 76.624h239.072v-17.008h-239.072v17.008zM156.704 144.032c19.040 15.872 6.64 9.904 24.208 19.68 0 0-15.088 137.536 125.84 209.024 22.88 8.48 73.52 21.040 136.112-3.824l-37.44-34.384 139.072 11.152 10.976 129.936-36.928-35.808c-37.024 16.768-76.24 29.376-118.384 36.272-41.184 8.816-80.224 2.48-120.24-15.392-54.736-24.832-91.056-57.248-110.272-94.608-20.016-39.232-28.336-86.848-26.464-143.6 1.632-23.328 8.832-56.192 13.552-78.432v0zM633.488 389.392h-54.48l-3.888-46.080h58.368c25.408 0 46.096-20.672 46.096-46.080v-140c0-25.408-20.672-46.080-46.096-46.080h-231.024c-25.408 0-46.080 20.672-46.080 46.080v140c0 0.88 0.256 1.696 0.272 2.56 0.56 32.048 22.848 52.656 22.848 52.656-3.632 0.256-7.264 0.368-10.88 0.368-18.336 0.016-33.2-3.184-44.080-6.56-8.976-14.224-14.24-30.976-14.24-49.024v-4.88h-57.328c-12.608-15.312-21.456-31.088-27.664-46.096h84.992v-81.504h-98.64l1.872-17.008h97.248c0 0.016 0 0.016 0 0.032 0.976-9.536 3.424-18.64 7.072-27.072h-141.232c-0.112-0.096-0.176-0.144-0.272-0.24l-20.096-16.768h171.28c10.384-14.528 24.864-25.856 41.776-32.384-0.032 0.016-0.080 0.016-0.112 0.032v-11.168c0-25.408-20.672-46.080-46.080-46.080h-231.008c-25.408 0-46.080 20.672-46.080 46.080v140.016c0 25.392 20.672 46.064 46.080 46.064h20.176c0.288 16.16 1.504 31.456 3.52 46.096h-23.68c-50.896 0-92.16-41.264-92.16-92.16v-140.016c0-50.912 41.264-92.16 92.16-92.16h231.040c50.896 0 92.16 41.248 92.16 92.16v4.896h218.192c50.896 0 92.16 41.28 92.16 92.16v140c0 50.896-41.264 92.16-92.16 92.16l-0.064-0.016zM322.256 111.936c0.032-0.064 0.080-0.112 0.112-0.16-0.032 0.064-0.080 0.112-0.112 0.16zM377.12 68.656c0 0 0.016 0 0 0 0.016 0 0 0 0 0zM385.168 66.736c0.592-0.128 1.2-0.176 1.808-0.288-0.592 0.096-1.216 0.16-1.808 0.288zM393.6 65.504c2.944-0.304 5.888-0.448 8.896-0.448-3.008 0-5.952 0.144-8.896 0.448zM406.432 261.792h242.896v-17.008h-242.896v17.008zM408.352 217.744h239.072v-17.024h-239.072v17.024zM408.352 173.712h239.072v-17.024h-239.072v17.024z" horiz-adv-x="720" /> -<glyph unicode="" d="M512.016 249.36c0 6.496-5.36 11.792-11.808 11.792h-21.584c-6.528 0-13.376 5.056-15.2 11.264l-29.376 68.624c-3.136 5.6-2.096 13.952 2.464 18.576l14.608 14.576c4.608 4.592 4.608 12.128 0 16.672l-35.12 35.168c-4.576 4.624-12.048 4.624-16.768 0l-15.792-15.872c-4.624-4.592-13.104-5.872-18.8-2.864l-59.728 23.856c-6.224 1.76-11.36 8.56-11.36 15.008v22.16c0 6.448-5.296 11.712-11.728 11.712h-49.856c-6.448 0-11.76-5.264-11.76-11.712v-22.16c0-6.448-5.104-13.312-11.248-15.232l-69.248-29.6c-5.536-3.264-13.808-2.176-18.448 2.4l-15.536 15.536c-4.56 4.56-12.032 4.56-16.656 0l-35.184-35.2c-4.656-4.592-4.656-12.096 0-16.672l16.864-16.992c4.672-4.56 5.92-12.928 2.944-18.72l-23.552-59.152c-1.728-6.304-8.496-11.36-14.992-11.36h-23.504c-6.432 0.016-11.712-5.28-11.712-11.776v-49.76c0-6.512 5.296-11.856 11.728-11.856h23.504c6.496 0 13.28-5.024 15.2-11.232l28.864-68.112c3.328-5.6 2.208-13.888-2.288-18.528l-16.192-16.064c-4.608-4.592-4.608-12.032 0-16.688l35.216-35.184c4.64-4.56 12.144-4.56 16.608 0l17.296 17.2c4.624 4.608 12.912 5.856 18.672 2.736l60.4-24.080c6.144-1.792 11.248-8.56 11.248-15.008v-23.040c0-6.448 5.312-11.76 11.76-11.76h49.856c6.416 0 11.728 5.312 11.728 11.76v23.040c0 6.448 5.088 13.216 11.344 15.136l67.52 28.64c5.6 3.2 13.84 2.064 18.512-2.496l15.232-15.264c4.576-4.56 12.048-4.56 16.672 0l35.216 35.216c4.608 4.56 4.608 12.096 0 16.672l-16.256 16.176c-4.48 4.624-5.76 12.976-2.736 18.736l24.464 60.88c1.728 6.24 8.576 11.264 15.104 11.328h21.584c6.448 0 11.808 5.296 11.808 11.792l-0.048 49.744zM256.048 140.272c-46.304 0-83.728 37.52-83.728 83.728 0 46.272 37.44 83.696 83.728 83.696 46.176 0 83.696-37.44 83.696-83.696 0-46.192-37.536-83.728-83.696-83.728zM976.88 224.016l-173.248-201.168-173.216 201.168z" horiz-adv-x="976" /> -<glyph unicode="" d="M512.048 249.36c0 6.48-5.36 11.776-11.792 11.776h-21.584c-6.528 0-13.36 5.056-15.184 11.28l-29.376 68.592c-3.136 5.616-2.096 13.984 2.48 18.592l14.608 14.576c4.592 4.592 4.592 12.096 0 16.688l-35.152 35.184c-4.576 4.608-12.048 4.608-16.784 0l-15.792-15.872c-4.624-4.608-13.104-5.872-18.816-2.848l-59.728 23.808c-6.24 1.792-11.36 8.56-11.36 15.024v22.16c0 6.48-5.296 11.728-11.712 11.728h-49.84c-6.448 0-11.76-5.264-11.76-11.728v-22.144c0-6.464-5.12-13.296-11.248-15.232l-69.248-29.616c-5.568-3.264-13.84-2.192-18.464 2.384l-15.536 15.552c-4.576 4.576-12.032 4.576-16.656 0l-35.2-35.2c-4.656-4.592-4.656-12.096 0-16.688l16.88-16.976c4.656-4.56 5.952-12.928 2.928-18.72l-23.52-59.152c-1.744-6.304-8.512-11.344-15.008-11.344h-23.488c-6.432 0-11.728-5.296-11.728-11.776v-49.792c0-6.496 5.28-11.84 11.728-11.84h23.488c6.496 0 13.28-5.024 15.2-11.232l28.88-68.080c3.312-5.616 2.208-13.92-2.304-18.528l-16.208-16.096c-4.592-4.608-4.592-12.016 0-16.688l35.216-35.184c4.608-4.576 12.096-4.576 16.608 0l17.296 17.216c4.608 4.576 12.896 5.856 18.672 2.752l60.4-24.096c6.144-1.792 11.248-8.56 11.248-15.008v-23.040c0-6.48 5.296-11.776 11.76-11.776h49.84c6.4 0 11.712 5.296 11.712 11.776v23.040c0 6.448 5.072 13.232 11.36 15.136l67.52 28.64c5.6 3.152 13.84 2.032 18.512-2.496l15.216-15.296c4.576-4.576 12.048-4.576 16.672 0l35.2 35.232c4.592 4.56 4.592 12.064 0 16.656l-16.256 16.176c-4.48 4.608-5.744 12.976-2.736 18.72l24.464 60.88c1.744 6.256 8.576 11.28 15.104 11.328h21.584c6.4 0 11.792 5.296 11.792 11.792v49.792l0.080-0.016zM256.080 140.288c-46.32 0-83.728 37.504-83.728 83.728 0 46.24 37.408 83.68 83.728 83.68 46.176 0 83.712-37.44 83.712-83.68 0-46.224-37.536-83.728-83.712-83.728z" /> -<glyph unicode="" d="M29.952 113.424v295.056h89.184c-43.952-4.544-75.856-18.224-75.856-34.4h215.648c0 16.176-31.92 29.84-75.856 34.384h89.184v-295.056h-55.12v-29.952h62.272c12.592 0 22.816 10.224 22.816 22.816v309.344c0 12.608-10.224 22.8-22.816 22.8h-97.968v14.544c0 14.944-12.112 27.040-27.024 27.040-14.944 0-27.056-12.096-27.056-27.040v-14.544h-104.544c-12.608 0-22.816-10.208-22.816-22.8v-309.328c0-12.592 10.208-22.816 22.816-22.816h61.888v29.952h-54.752zM154.416 466.608c7.664 0 13.856-6.208 13.856-13.856 0-7.664-6.208-13.872-13.856-13.872s-13.872 6.192-13.872 13.856c0 7.648 6.208 13.872 13.872 13.872zM178.144 194.752h-54.48v-140.704l-57.408-0.736 83.28-85.312 86.416 87.392-57.808 1.344z" horiz-adv-x="304" /> -<glyph unicode="" d="M256.576-29.904c-137.728 0-249.808 112.064-249.808 249.808 0 137.728 112.064 249.808 249.808 249.808 137.728 0 249.808-112.064 249.808-249.808 0-137.744-112.064-249.808-249.808-249.808zM256.576 461.888c-133.424 0-242-108.56-242-242s108.56-242 242-242c133.44 0 242 108.544 242 242 0 133.44-108.544 242-242 242zM61.056 255.456l86.016 86.736 109.504-108.576 108.416 108.4 86.368-86.384-194.432-194.432z" /> -<glyph unicode="" d="M256.576-28.368c-139.456 0-252.896 113.456-252.896 252.896s113.456 252.896 252.896 252.896 252.896-113.456 252.896-252.896-113.456-252.896-252.896-252.896zM256.576 445.84c-122.016 0-221.28-99.264-221.28-221.28s99.264-221.28 221.28-221.28 221.28 99.264 221.28 221.28-99.248 221.28-221.28 221.28z" /> -<glyph unicode="" d="M62.256 351.472l36.704-36.72v5.008h180.592l72 72h-324.592v-75.568l7.008 7.008zM378.72 40h-141.296l-50.656-50.704-50.688 50.704h-37.12v37.12l-2.736 2.752-69.264 69.248v-181.12h423.76v285.344l-72-72zM186.736 170.384l-124.48 124.528-62.256-62.256 186.752-186.784 371.872 371.952-62.256 62.176z" horiz-adv-x="560" /> -<glyph unicode="" d="M585.392 480l-365.136-365.12-146.832 146.8-73.424-73.36 220.288-220.32 438.528 438.624-73.424 73.376z" horiz-adv-x="656" /> -<glyph unicode="" d="M435.44 455.104l-10.912-12.592c-6.976-8.032-11.12-11.984-14.384-14.768-0.624-1.040-1.584-2.64-3.056-5.152l-7.36-12.4c84.672-22.4 147.376-99.44 147.376-191.040 0-109.040-88.752-197.76-197.84-197.76-46.48 0-89.2 16.24-123.008 43.168v0l-10.736-32.176-39.472 5.168c45.104-43.040 106.096-69.552 173.2-69.552 138.528 0 251.232 112.672 251.232 251.136 0 108.256-68.816 200.72-165.040 235.968v0zM374.96 228.432v172.992h-53.376v-200.96h5.744l101.952-100.928 37.568 37.952-91.888 90.944zM172 454.912c-38.96-19.184-73.376-56.288-100.544-112.72-19.584-41.28-27.312-81.792-19.536-124.832 5.808-44.032 2.752-36.112 18.8-75.056l-70.72-49.376 193.488-25.36 59.6 178.832-98.304-53.376c-0.88 2.432-1.568 4.72-2.336 7.056-19.68 60.736-0.624 89.488 8.432 112.24 77.776 145.136 218.528 126.4 218.528 126.4 10.528 18.080 4.048 5.312 20.912 24.768-22.624 5.392-56.192 13.616-80.080 15.824-58.208 3.168-107.36-4.448-148.24-24.4z" horiz-adv-x="608" /> -<glyph unicode="" d="M185.408 373.104c-0.816 13.872-3.648 27.648-8.48 41.36-6.816 19.696-10.272 33.264-10.272 40.736 0 10.448 2.48 18.368 7.376 23.824 4.912 5.44 11.056 8.128 18.288 8.128 6.208 0 11.664-2.704 16.304-8.128 4.608-5.456 6.976-13.216 6.976-23.184 0-9.088-2.704-21.712-7.984-37.92-5.424-16.16-8.672-31.136-9.856-44.8 11.088 7.056 21.008 15.568 29.888 25.632 13.696 15.904 23.808 25.776 30.512 29.584 6.576 3.84 13.328 5.696 20.224 5.696 6.544 0 12.16-2.256 16.688-6.768 4.528-4.512 6.848-9.872 6.848-16.128 0-7.44-3.328-14.096-10.016-19.872-6.592-5.872-23.264-11.696-49.776-17.568-15.488-3.392-28.304-7.312-38.608-11.728 10.448-5.424 23.264-9.568 38.368-12.384 24.304-4.384 40.256-9.92 47.792-16.56 7.536-6.672 11.312-13.92 11.312-21.744 0-6.048-2.288-11.264-6.8-15.712s-9.776-6.656-15.776-6.656c-6.048 0-12.784 2.128-20.080 6.384-7.376 4.16-17.296 13.648-29.744 28.352-8.224 9.808-18.528 19.088-30.816 27.712 0.432-11.488 2.768-23.952 6.976-37.424 7.216-23.744 10.88-39.936 10.88-48.576 0-7.984-2.432-14.864-7.264-20.336-4.832-5.568-9.952-8.32-15.392-8.32-7.456 0-14.208 2.912-20.224 8.736-4.224 4.256-6.336 10.944-6.336 20.208 0 9.648 2.352 21.264 6.992 34.896 4.608 13.536 7.488 22.896 8.704 28.064 1.216 5.12 2.352 12.688 3.36 22.72-11.92-7.824-22.256-16.56-31.104-26.24-14.736-16.48-25.712-26.96-33.184-31.392-5.248-3.168-10.688-4.832-16.304-4.832-6.848 0-12.672 2.352-17.504 6.944-4.832 4.672-7.232 9.776-7.232 15.392 0 5.040 2.016 10.272 6.192 15.824 4.096 5.52 10.256 10.096 18.544 13.776 5.392 2.336 17.808 5.584 37.136 9.6 12.48 2.608 24.592 6.432 36.496 11.488-10.928 5.392-23.888 9.648-38.976 12.672-24.688 5.2-39.984 9.952-45.84 14.16-9.040 6.64-13.568 14.704-13.568 24.128 0 5.456 2.304 10.448 6.736 14.944 4.56 4.512 9.84 6.816 15.872 6.816 6.656 0 13.696-2.144 21.12-6.352 7.44-4.256 16.72-12.736 27.744-25.536 11.104-12.72 22.368-22.592 33.84-29.648zM245.6 268.288l-0.8 1.296 0.128-0.8-0.64 0.496 0.752-1.328 29.088-229.92 53.072 61.664 78.944-136.72 22.976 13.312-78.896 136.688 79.888 15.152z" /> -<glyph unicode="" d="M471.664 207.552l-431.344 232.080 232.368-431.248z" /> -<glyph unicode="" d="M489.024 160.384l-100.72-101.552-128.224 127.152-126.96-126.944-101.12 101.136 227.664 227.68z" /> -<glyph unicode="" d="M220.144 54.976l-58.896 58.416 73.728 74.352-73.616 73.616 58.64 58.64 132.032-132.016z" /> -<glyph unicode="" d="M32 286.304l100.72 101.552 128.224-127.152 126.96 126.944 101.12-101.136-227.664-227.68z" /> -<glyph unicode="" d="M30.64 447.184l95.424-177.088 28.912 28.944 298.992-298.864 27.216 27.28-298.944 298.848 25.536 25.568z" /> -<glyph unicode="" d="M616.496 480h-424.96c-26.608 0-48.192-21.584-48.192-48.224v-67.872c0 0-1.536-6.112-2.544-8.288-1.072-2.288-5.232-7.824-5.232-7.824l-117.92-98.832c0 0-17.808-15.264-17.632-24.992 0.176-9.44 17.632-23.2 17.632-23.2l117.952-91.744c0 0 4.144-5.184 5.232-7.36 1.056-2.176 2.528-8.32 2.528-8.32v-77.184c0-26.624 21.568-48.176 48.192-48.176h424.96c26.624 0 48.208 21.552 48.208 48.176v415.6c-0.016 26.64-21.584 48.224-48.208 48.224zM358.336 396.72h76.272v-98.96l-20.080-158.736h-36.592l-19.6 158.736v98.96zM437.2 28.736h-80.912v79.376h80.912v-79.376z" horiz-adv-x="672" /> -<glyph unicode="" d="M442.992 79.28c-80.816 6.896-81.824 88.080-88 168.4-4.448 57.84-36.848 93.728-71.296 119.84-4.096 1.056-9.696 1.936-16.128 2.656 11.44 11.664 18.528 27.6 18.528 45.2 0 35.696-28.944 64.624-64.608 64.624s-64.624-28.928-64.624-64.608c0-17.872 7.248-34.048 18.992-45.744-6.768-0.944-12.512-2.144-16.576-3.648-40.016-25.472-68.896-67.472-72.816-125.92-5.024-74.672-8.416-155.568-86.48-159.28 0-20.224 0-40.448 0-60.672 23.792 0 92.512 0 169.392 0 0-28.784 23.328-52.128 52.112-52.128s52.112 23.344 52.112 52.128c76.88 0 145.6 0 169.392 0-0.016 19.712-0.016 39.424-0.016 59.152zM221.504 439.616c13.36 0 24.224-10.88 24.224-24.224s-10.864-24.224-24.224-24.224-24.224 10.88-24.224 24.224 10.864 24.224 24.224 24.224z" horiz-adv-x="448" /> -<glyph unicode="" d="M875.84 410.288c0 26.048-17.936 47.632-40.656 48.112l-0.176-0.032-23.936 0.064 0.048 15.904c0.016 3.088-1.456 5.616-3.248 5.632l-38.496 0.048c-1.808 0.016-3.264-2.496-3.264-5.584l-0.048-15.904-34.8 0.080 0.048 15.696c0.016 3.088-1.472 5.616-3.248 5.632l-38.496 0.064c-1.808 0.016-3.296-2.496-3.296-5.584l-0.032-15.696-50.928 0.112 0.032 15.472c0.016 3.088-1.44 5.616-3.232 5.632l-38.496 0.048c-1.808 0.016-3.296-2.496-3.296-5.584l-0.032-15.472-40.448 0.096 0.048 15.248c0 3.088-1.472 5.616-3.264 5.632l-38.48 0.064c-1.808 0.016-3.296-2.496-3.312-5.584l-0.048-15.248-28.992 0.064c-21.216 0-39.12-19.856-40.64-44.672l-0.288-106.816h122.080v-86.176h277.696l-0.56-199.776v-1.024c-0.192-3.424-1.36-5.552-2.16-6.56l-355.056 0.896c-0.864 1.088-2.080 3.456-2.080 7.248l0.304 123.376h-40.72l-0.32-123.264c-0.080-26.448 18.064-48.912 40.528-49.024h359.488c21.872 0 41.2 21.008 41.792 46.832v389.968zM643.968 275.952h-18.416v54.896l-17.984-35.712h-12.448l-18.128 35.712v-54.896h-18.384v94.208h18.128l24.592-50.928 24.48 50.928h18.144v-94.208zM751.248 275.952h-18.384v54.896l-17.984-35.712h-12.448l-18.144 35.712v-54.896h-18.368v94.208h18.128l24.592-50.928 24.48 50.928h18.128v-94.208zM628.944 193.072v-47.024c-3.44 3.824-7.168 6.512-11.184 8.032s-8.672 2.288-13.936 2.288c-5.024 0-9.728-0.832-14.144-2.48-4.448-1.664-8.080-3.936-10.992-6.848-2.496-2.512-4.496-5.488-5.952-8.912-1.44-3.44-2.496-7.088-3.152-10.928-0.672-3.824-1.072-7.76-1.184-11.792-0.128-4.032-0.208-7.984-0.208-11.792 0-3.84 0.064-7.808 0.208-11.92 0.112-4.096 0.512-8.064 1.184-11.904 0.64-3.84 1.712-7.44 3.152-10.816 1.456-3.376 3.44-6.384 5.952-9.040 2.912-2.912 6.608-5.2 11.088-6.832 4.48-1.664 9.216-2.496 14.24-2.496 5.536 0 10.272 0.848 14.24 2.496 3.968 1.648 7.728 4.464 11.296 8.432l-0.016-9.712h25.408v141.296h-26zM628.352 91.744c-0.384-3.648-1.2-6.784-2.464-9.424-1.232-2.656-3.024-4.736-5.312-6.256-2.304-1.52-5.328-2.288-9.136-2.288-3.792 0-6.816 0.768-9.12 2.288-2.288 1.52-4.016 3.6-5.2 6.256-1.168 2.624-1.952 5.776-2.352 9.424s-0.592 7.584-0.592 11.808c0 4.224 0.208 8.112 0.592 11.696s1.168 6.688 2.352 9.344c1.168 2.624 2.912 4.704 5.2 6.24 2.304 1.52 5.328 2.288 9.12 2.288 3.808 0 6.832-0.768 9.136-2.288 2.288-1.52 4.048-3.616 5.312-6.24 1.232-2.64 2.048-5.76 2.464-9.344s0.592-7.472 0.592-11.696c0-4.224-0.192-8.176-0.592-11.808zM740.272 146.032c-3.424 3.824-7.168 6.512-11.168 8.032-4.016 1.52-8.672 2.288-13.936 2.288-5.024 0-9.728-0.832-14.16-2.48s-8.064-3.936-10.96-6.848c-2.496-2.512-4.496-5.488-5.952-8.912-1.456-3.44-2.496-7.088-3.168-10.928-0.656-3.824-1.072-7.76-1.184-11.792s-0.192-7.984-0.192-11.792c0-3.84 0.048-7.808 0.192-11.92s0.528-8.064 1.184-11.904 1.712-7.44 3.168-10.816c1.456-3.376 3.44-6.384 5.952-9.040 2.912-2.912 6.608-5.2 11.072-6.832 4.496-1.664 9.232-2.496 14.256-2.496 5.536 0 10.272 0.848 14.24 2.496 3.952 1.648 7.712 4.464 11.296 8.432l-0.016-9.712h25.408v141.296h-26v-47.072zM739.696 91.744c-0.384-3.648-1.2-6.784-2.48-9.424-1.232-2.656-3.024-4.736-5.312-6.256s-5.328-2.288-9.12-2.288-6.832 0.768-9.12 2.288-4.016 3.6-5.2 6.256c-1.168 2.624-1.968 5.776-2.352 9.424-0.384 3.648-0.592 7.584-0.592 11.808 0 4.224 0.208 8.112 0.592 11.696 0.368 3.584 1.168 6.688 2.352 9.344 1.168 2.624 2.912 4.704 5.2 6.24s5.328 2.288 9.12 2.288 6.832-0.768 9.12-2.288 4.048-3.616 5.312-6.24c1.248-2.64 2.064-5.76 2.48-9.344 0.368-3.584 0.576-7.472 0.576-11.696 0-4.224-0.208-8.176-0.576-11.808zM525.456 274.48h-203.408v203.408h-118.656v-203.408h-203.408v-101.696h203.408v-204.736l118.656-0.032v204.784h203.408z" horiz-adv-x="880" /> -<glyph unicode="" d="M782.928 206.864h-24.528c-22.144-16.768-49.712-26.944-79.632-26.944-29.952 0-57.488 10.176-79.040 26.944h-17.376c-2.576 0-5.152-0.176-7.712-0.368v-69.68h-83.024c-2.064-7.664-3.248-15.648-3.248-23.92v-125.168h388.608v125.168c-0.016 51.488-41.888 93.968-94.016 93.968zM679.92 435.728c-65.696 0-118.816-53.056-118.816-118.784 0-10.464 1.488-20.56 4-30.24 2.304-8.736 5.456-17.104 9.568-24.96 19.824-38.064 59.472-64.208 105.296-64.208 66.256 0 119.376 53.696 119.376 119.36 0 65.712-53.12 118.784-119.376 118.784l-0.032 0.032zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256z" horiz-adv-x="880" /> -<glyph unicode="" d="M635.824 98.592c-0.096-0.048-0.4-0.304-0.64-0.464l-0.928-0.928 1.568 1.408zM795.152 413.056c0.144 0.112 0.432 0.336 0.832 0.608l0.432 0.4-1.264-1.008zM843.472 291.248h-280.272v-44.576h280.272v44.576zM411.92 109.856h431.552v-44.576h-431.552v44.576zM411.92 381.92h431.552v-44.592h-431.552v44.592zM843.472 200.528h-280.272v-44.656h280.272v44.656zM411.92 472.608h431.552v-44.592h-431.552v44.592zM411.92 19.168h431.552v-44.64h-431.552v44.64zM308.288 480h-104.512v-203.776h-203.776v-104.448h203.776v-203.76l104.512-0.016v203.792h203.744v104.48h-203.744z" horiz-adv-x="848" /> -<glyph unicode="" d="M772.448 458.704h-296.784c-61.728 0-111.744-50.032-111.744-111.76v-41.856h55.872v41.856c0 30.8 25.072 55.872 55.872 55.872h296.784c30.832 0 55.872-25.072 55.872-55.872v-220.496c0-30.784-25.072-55.872-55.872-55.872h-296.784c-30.832 0-55.872 25.104-55.872 55.872v20.768h-55.872v-20.768c0-61.728 50-111.76 111.744-111.76h296.784c61.712 0 111.744 50.032 111.744 111.76v220.496c0 61.712-50.048 111.76-111.744 111.76zM586.8 250.784h37.248v-229.952h-37.248v229.952zM558.992 278.064h296.784v-37.248h-296.784v37.248zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256zM654.384 219.968c12.096 0.080 10.528-6.080 17.648-10.176 5.040-2.928 5.040 2.912 10.896 1.456 3.664-0.896 9.984-1.936 12.608-8.688 3.168-1.408 6.576 2.512 16.352 0.224 6.832-4.784 4.976-9.12-3.44-14.336-11.584-4.56-53.552-4.912-62.688 0.864-15.792 14.032-4.288 30.72 8.608 30.64v0zM772.112 188.56c23.552-3.904 40.112-52.272 47.104-89.216-58.080 0-116.144 0-174.224 0 2.288 23.984 10.224 52.352 23.552 58.176 21.2 6.464 21.856-16.896 44.736-15.504 20.912 14.432 16.848 49.456 58.848 46.544v0z" horiz-adv-x="880" /> -<glyph unicode="" d="M458.368 462.368v-154.656h48.368l-0.096 26.8h79.6v81.12h249.28v-371.984h-328.544v81.2h-48.624v-127.92h425.856v465.424h-425.84zM506.992 355.952v59.696h59.696l-59.696-59.696zM643.216 56.832h137.328v71.504h-137.328v-71.504zM662.128 109.712h99.488v-34.304h-99.488v34.304zM643.216 157.312h137.328v71.536h-137.328v-71.536zM662.128 210.224h99.488v-34.272h-99.488v34.272zM643.216 257.792h137.328v71.52h-137.328v-71.52zM662.128 310.704h99.488v-34.272h-99.488v34.272zM615.392 90.528c-0.576 1.856-1.28 3.472-2.16 4.896-0.88 1.392-1.856 2.608-2.976 3.632-1.088 1.040-2.208 1.904-3.344 2.672 1.056 0.688 2.064 1.44 3.056 2.336 0.992 0.864 1.872 1.92 2.656 3.2 0.8 1.248 1.44 2.72 1.92 4.416 0.496 1.712 0.736 3.664 0.736 5.872 0 3.488-0.624 6.72-1.904 9.648-1.296 2.96-3.136 5.504-5.456 7.632-2.336 2.096-5.088 3.76-8.224 4.912-3.168 1.168-6.624 1.776-10.4 1.776-3.648 0-7.024-0.56-10.176-1.664-3.168-1.088-5.904-2.704-8.256-4.816-2.352-2.128-4.192-4.72-5.552-7.744-1.36-3.040-2.048-6.448-2.048-10.224h18.64c0 2.432 0.736 4.288 2.224 5.632 1.472 1.312 3.2 1.968 5.168 1.968 1.968 0 3.696-0.64 5.184-1.92 1.472-1.28 2.192-3.216 2.192-5.792 0-1.824-0.592-3.552-1.776-5.184-1.168-1.632-3.184-2.432-5.968-2.432h-2.624v-16.16h2.624c2.48 0 4.576-0.816 6.192-2.432 1.616-1.648 2.448-3.664 2.448-6.080 0-2.88-0.784-5.024-2.352-6.48-1.552-1.408-3.536-2.144-5.968-2.144-2.352 0-4.304 0.688-5.92 2.096-1.584 1.392-2.384 3.536-2.384 6.416h-18.656c0-4.544 0.8-8.432 2.336-11.664 1.552-3.216 3.584-5.856 6.144-7.824 2.512-2.016 5.408-3.488 8.624-4.448 3.216-0.96 6.496-1.424 9.824-1.424 3.568 0 6.976 0.512 10.24 1.552 3.248 1.056 6.128 2.576 8.576 4.608 2.48 2.048 4.448 4.608 5.92 7.728s2.208 6.768 2.208 11.008c0 2.432-0.288 4.576-0.848 6.416l0.032 0.032zM589.872 175.056h27.376v-16.816h-27.376v16.816zM590.208 212.24c2.272 0 4.032-0.64 5.344-1.888 1.28-1.264 1.92-2.928 1.92-5.056 0-1.76-0.736-3.44-2.16-5.056-1.312-1.456-3.168-3.136-5.424-4.928v-20.048l9.552 7.312c2.48 1.872 4.768 3.76 6.816 5.552 2.032 1.824 3.808 3.68 5.28 5.52 1.504 1.872 2.608 3.776 3.408 5.76s1.184 4.096 1.184 6.368c0 3.664-0.688 6.912-1.984 9.792-1.328 2.864-3.168 5.328-5.504 7.36-2.368 1.984-5.104 3.536-8.24 4.592-3.168 1.072-6.56 1.584-10.176 1.584-0.112 0-0.24-0.016-0.336-0.016v-16.816c0.096-0.016 0.224 0.016 0.336 0.016v-0.016zM601.104 320.816h-18.64l-11.296-9.84h18.704v-58.048h11.232v67.872zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256z" horiz-adv-x="880" /> -<glyph unicode="" d="M625.040 449.632c-119.568 0-219.472-55.792-244.768-140.288h186.944v-169.52l-136.176 0.016c9.648-8.864 20.288-17.104 31.904-24.496 6.912-4.432 14.16-8.56 21.68-12.416 9.664-7.136-10.912-56.848-84.352-110.752 60.256 0 150.576 28.096 224.768 78.384 150.576 17.248 251.152 84.832 251.152 189.504 0.016 104.704-112.432 189.552-251.136 189.552zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256z" horiz-adv-x="880" /> -<glyph unicode="" d="M405.008 480v-181.168h45.52l0.16 33.568h102.512l-0.464 103.728h206.448v-424.256h-308.496v137.328h-45.664v-181.2h399.84v511.984h-399.856zM450.672 352.496v83.664h83.616l-83.616-83.664zM308.288 480h-104.496v-203.776h-203.792v-104.432h203.776v-203.76l104.496-0.016v203.776h203.728v104.464h-203.712v203.728z" horiz-adv-x="800" /> -<glyph unicode="" d="M843.664 438.928h-342.64c-22.368 0-40.528-18.128-40.528-40.544v-57.088c0 0-1.28-5.136-2.128-6.96-0.912-1.904-4.416-6.576-4.416-6.576l-32.528-27.264h141.12v-153.696h-134.112l25.52-19.84c0 0 3.488-4.336 4.416-6.192 0.88-1.824 2.128-6.976 2.128-6.976v-64.912c0-22.368 18.144-40.496 40.528-40.496h342.656c22.384 0 40.528 18.112 40.528 40.496v349.52c-0.016 22.4-18.144 40.544-40.544 40.544zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256z" horiz-adv-x="880" /> -<glyph unicode="" d="M884.096 142.032c-9.696 44.736-29.648 132.288-37.472 137.36l-282.256 183.84c-10.512 6.832-24.624 3.84-31.472-6.656l-89.408-137.392h131.792v-151.072l139.648-90.96c2.656-1.696 31.984 3.28 31.984 3.28l12.080 2.512c-0.416-0.336 60.96 14.48 87.616 21.552 8.64 2.304 16.624 4.432 23.2 6.176 12.128 3.344 17.68 15.84 14.288 31.344zM833.664 156.384c-5.536-19.008-25.424-29.952-44.448-24.448-19.008 5.536-29.952 25.424-24.432 44.448s25.424 29.952 44.448 24.432c19.008-5.52 29.936-25.408 24.432-44.416zM802.336 143.904c4.752-8.688 10.704-29.12 10.704-58.592s-5.952-49.936-10.704-58.608c-4.752 8.688-10.688 29.136-10.688 58.608s5.92 49.904 10.688 58.592zM802.336 164.304c-15.296 0-27.712-35.376-27.712-78.992s12.416-79.008 27.712-79.008 27.728 35.376 27.728 79.008c0 43.632-12.432 78.992-27.728 78.992v0zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256z" horiz-adv-x="880" /> -<glyph unicode="" d="M830.656 300.272v0zM372.752 434.896v-128.224h52.144v73.888h407.12v-304.992h-407.104v70.32h-52.176v-124.688h511.44v413.696l-511.44 0.016zM566.272 309.52c17.504 0.128 15.248-8.8 25.536-14.72 7.312-4.224 7.312 4.208 15.744 2.128 5.296-1.312 14.48-2.832 18.272-12.544 4.56-2.048 9.488 3.632 23.68 0.304 9.84-6.912 7.168-13.168-5.008-20.72-16.768-6.608-77.456-7.12-90.672 1.264-22.896 20.288-6.24 44.448 12.448 44.288v0zM736.512 264.096c34.080-5.616 58.048-75.6 68.096-129.056-84 0-167.984 0-251.968 0 3.264 34.688 14.752 75.728 34.048 84.16 30.656 9.328 31.632-24.448 64.688-22.448 30.272 20.88 24.384 71.552 85.136 67.328v0zM638.048 161.712c-0.048-0.032-0.24-0.176-0.352-0.272l-0.528-0.528 0.88 0.8zM652.576 125.376c0 0-0.016-0.016-0.032-0.032-0.32-0.32-0.512-0.496-0.512-0.496l0.544 0.528zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256z" horiz-adv-x="880" /> -<glyph unicode="" d="M788.224 404.528h-152.496c-3.056 18.56-11.872 49.904-48.096 49.904h-122.96c-35.056 0-44.192-32.816-47.824-51.888-29.056-6.848-49.936-30.72-49.936-59.888v-39.52h41.536v39.52c0 11.408 11.296 20.336 25.92 20.336h15.664l4.32 15.040c0.992 3.504 1.712 7.504 2.432 11.696 0.912 5.104 3.6 20.64 7.040 23.056 0 0 0.256 0.064 0.912 0.064h122.96c2.688 0 5.232 0 7.936-21.152 0.64-4.88 1.248-9.488 2.432-13.696l4.304-15.040h185.904c14.416 0 25.696-8.944 25.696-20.336v-246.544c0-11.392-11.296-20.32-25.696-20.32h-354.144c-14.416 0-25.728 8.912-25.728 20.32v49.904h-41.536v-49.888c0-34.672 29.536-61.84 67.248-61.84h354.080c37.696 0 67.264 27.168 67.264 61.84v246.544c0 34.704-29.552 61.888-67.248 61.888v0zM308.272 480h-104.496v-203.776h-203.792v-104.464h203.792v-203.744l104.496-0.032v203.776h203.728v104.496h-203.728z" horiz-adv-x="848" /> -<glyph unicode="" d="M527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256zM842.448 409.616c-66.592 66.608-143.696 40.64-176.608 10.464-26.32-24.112-82.352-76.256-121.472-110.288h17.328v-48.352c34.048 43.952 96.368 99.504 123.824 124.224 6.928 6.24 75.632 59.824 135.088 0.336 59.424-59.392 5.344-116.752-0.912-123.088 0.016 0.016-179.584-184.384-218.432-216.304-31.456-25.856-96.848-58.128-166.672 11.968-25.344 25.424-33.456 46.976-34.624 81.024h-30.944c3.152-51.056 21.712-86.272 41.728-104.608 86.256-78.992 170.496-46.208 208.224-9.92 56.928 54.736 223.44 218.816 223.44 218.816 29.44 29.44 67.344 98.4 0 165.744zM530.864 309.792l83.584 75.952-25.12 29.44-112.752-105.392h25.664zM463.216 139.584h-33.024c3.792-17.024 10.8-39.024 23.776-51.536 41.936-40.416 105.824-46.8 140.864-14.176 48.416 45.072 170.016 169.344 170.016 169.344l-23.568 23.328c0 0-143.072-149.344-168.656-168.768-21.056-15.968-62.064-13.568-92.688 12.784-7.52 6.464-13.328 12-16.72 29.024z" horiz-adv-x="880" /> -<glyph unicode="" d="M772.448 458.704h-296.784c-61.728 0-111.744-50.032-111.744-111.76v-41.856h55.872v41.856c0 30.8 25.072 55.872 55.872 55.872h296.784c30.832 0 55.872-25.072 55.872-55.872v-220.496c0-30.784-25.072-55.872-55.872-55.872h-296.784c-30.832 0-55.872 25.104-55.872 55.872v20.768h-55.872v-20.768c0-61.728 50-111.76 111.744-111.76h296.784c61.712 0 111.744 50.032 111.744 111.76v220.496c0 61.712-50.048 111.76-111.744 111.76zM586.8 250.784h37.248v-229.952h-37.248v229.952zM558.992 278.064h296.784v-37.248h-296.784v37.248zM527.648 275.744h-204.256v204.256h-119.152v-204.256h-204.256v-102.128h204.256v-205.6l119.152-0.032v205.632h204.256z" horiz-adv-x="880" /> -<glyph unicode="" d="M835.2 432c0 25.6-17.6 48-40 48v0h-356.8c-20.8 0-38.4-19.2-40-44.8v-120h40v116.8c0 3.2 1.6 6.4 1.6 6.4l353.6-1.6c1.6-1.6 1.6-3.2 1.6-8l-1.6-416v-1.6c0-3.2-1.6-4.8-1.6-6.4l-352 1.6c-1.6 1.6-1.6 3.2-1.6 8v115.2h-40v-115.2c0-25.6 17.6-48 40-48v0l355.2 1.6c22.4 0 40 20.8 40 46.4v0 1.6l1.6 416zM793.6-11.2v20.8c0 0 0 0 0 0v-20.8zM721.6 396.8h-217.6c-9.6 0-17.6-4.8-17.6-9.6v-72h62.4v-54.4h172.8c9.6 0 17.6 4.8 17.6 9.6v116.8c0 6.4-8 9.6-17.6 9.6zM380.8 384h70.4c3.2 0 4.8 1.6 4.8 3.2v38.4c0 1.6-3.2 3.2-4.8 3.2h-70.4c-3.2 0-4.8-1.6-4.8-3.2v-38.4c-1.6-1.6 1.6-3.2 4.8-3.2zM456 334.4c0 1.6-3.2 3.2-4.8 3.2h-70.4c-3.2 0-4.8-1.6-4.8-3.2v-19.2h81.6l-1.6 19.2zM374.4 116.8c0-1.6 3.2-3.2 4.8-3.2h70.4c3.2 0 4.8 1.6 4.8 3.2v16h-81.6l1.6-16zM451.2 68.8h-70.4c-3.2 0-4.8-1.6-4.8-3.2v-38.4c0-1.6 3.2-3.2 4.8-3.2h70.4c3.2 0 4.8 1.6 4.8 3.2v38.4c0 1.6-1.6 3.2-4.8 3.2zM307.2 478.4h-104v-203.2h-203.2v-102.4h203.2v-203.2h104v203.2h201.6v102.4h-201.6z" horiz-adv-x="835" /> -<glyph unicode="" d="M609.6 308.8l-67.2 33.6 57.6 116.8c9.6 19.2 32 25.6 51.2 17.6v0c19.2-9.6 25.6-32 17.6-51.2l-59.2-116.8zM604.702 237.709l-15.741 7.873 84.45 168.863 15.741-7.873-84.45-168.863zM430.4 30.4c4.8 6.4 11.2 14.4 19.2 24l-12.8 6.4c-3.2-11.2-4.8-20.8-6.4-30.4zM512 129.6l86.4 174.4-52.8 25.6-86.4-174.4c0 0 0 0 0 0l52.8-25.6c0 0 0 0 0 0zM457.6 147.2c-3.2-14.4-11.2-46.4-19.2-78.4l16-8c19.2 22.4 41.6 49.6 52.8 62.4l-49.6 24zM27.2-9.6h492.8v-16h-492.8v16zM49.6 136c17.6-20.8 28.8-44.8 43.2-67.2 11.2-17.6 20.8-40 41.6-46.4 8-1.6 35.2 11.2 17.6 14.4-8 1.6-11.2 11.2-16 17.6-8 11.2-16 22.4-22.4 33.6-11.2 19.2-22.4 38.4-36.8 56-6.4 11.2-33.6 1.6-27.2-8v0zM54.4 38.4c32 33.6 70.4 60.8 92.8 102.4 6.4 12.8-22.4 9.6-27.2 1.6-20.8-38.4-57.6-65.6-88-97.6-12.8-14.4 16-14.4 22.4-6.4v0zM220.8 38.4c41.6 22.4 88 54.4 110.4 96 24 44.8-32 54.4-59.2 28.8-25.6-24-24-67.2-3.2-92.8 28.8-33.6 64 14.4 73.6 38.4 3.2 9.6-9.6 12.8-16 9.6-30.4-11.2-59.2-36.8-48-72 12.8-36.8 60.8-11.2 80 3.2 4.8 3.2 8 9.6 1.6 12.8-3.2 1.6-6.4 3.2-11.2 3.2-9.6 1.6-30.4-12.8-14.4-19.2 24-8 48-9.6 73.6-8 16 1.6 24 20.8 3.2 19.2-20.8-1.6-40 0-59.2 6.4-4.8-6.4-9.6-12.8-14.4-19.2 0 0 0 0 0 0 0 4.8 1.6 9.6 1.6 12.8-40-30.4-43.2 28.8-8 41.6-4.8 3.2-11.2 6.4-16 9.6-6.4-17.6-17.6-40-28.8-12.8-6.4 16-6.4 40 4.8 54.4 12.8-1.6 17.6-6.4 11.2-16-3.2-6.4-6.4-11.2-11.2-16-8-9.6-17.6-17.6-25.6-25.6-17.6-16-38.4-30.4-59.2-41.6-16-6.4 0-19.2 14.4-12.8v0z" horiz-adv-x="688" /> -<glyph unicode="" d="M438.4 308.8l-67.2 33.6 57.6 116.8c9.6 19.2 32 25.6 51.2 17.6v0c19.2-9.6 25.6-32 17.6-51.2l-59.2-116.8zM432.956 237.804l-15.745 7.865 84.375 168.9 15.745-7.865-84.375-168.9zM257.6 30.4c4.8 6.4 11.2 14.4 19.2 24l-12.8 6.4c-1.6-11.2-3.2-20.8-6.4-30.4zM340.8 129.6l86.4 174.4-52.8 25.6-86.4-172.8c0 0 0 0 0 0l52.8-27.2c0 0 0 0 0 0zM286.4 147.2c-3.2-14.4-11.2-46.4-19.2-78.4l16-8c19.2 22.4 41.6 49.6 52.8 62.4l-49.6 24zM27.2-9.6h246.4v-16h-246.4v16zM49.6 38.4c41.6 22.4 88 54.4 110.4 96 24 44.8-32 54.4-59.2 28.8-25.6-24-24-67.2-3.2-92.8 28.8-33.6 64 14.4 73.6 38.4 3.2 9.6-9.6 12.8-16 9.6-30.4-11.2-59.2-36.8-48-72 12.8-36.8 60.8-11.2 80 3.2 4.8 3.2 8 9.6 1.6 12.8-3.2 1.6-6.4 3.2-11.2 3.2-9.6 1.6-30.4-12.8-14.4-19.2 24-8 48-9.6 73.6-8 16 1.6 24 20.8 3.2 19.2-20.8-1.6-40 0-59.2 6.4-4.8-6.4-9.6-12.8-14.4-19.2 0 0 0 0 0 0 0 4.8 1.6 9.6 1.6 12.8-40-30.4-43.2 28.8-8 41.6-4.8 3.2-11.2 6.4-16 9.6-6.4-17.6-17.6-40-28.8-12.8-6.4 16-6.4 40 4.8 54.4 12.8-1.6 17.6-6.4 11.2-16-3.2-6.4-6.4-11.2-11.2-16-8-9.6-17.6-17.6-25.6-25.6-17.6-16-38.4-30.4-59.2-41.6-16-6.4 0-19.2 14.4-12.8v0zM755.2 308.8l-67.2 33.6 57.6 116.8c9.6 19.2 32 25.6 51.2 17.6v0c19.2-9.6 25.6-32 17.6-51.2l-59.2-116.8zM749.559 237.88l-15.749 7.86 84.318 168.938 15.749-7.86-84.318-168.938zM574.4 30.4c4.8 6.4 11.2 14.4 19.2 24l-12.8 6.4c-1.6-11.2-3.2-20.8-6.4-30.4zM657.6 129.6l86.4 174.4-52.8 25.6-86.4-174.4c0 0 0 0 0 0l52.8-25.6c0 0 0 0 0 0zM603.2 147.2c-3.2-14.4-11.2-46.4-19.2-78.4l16-8c19.2 22.4 41.6 49.6 52.8 62.4l-49.6 24zM342.4-9.6h246.4v-16h-246.4v16zM366.4 38.4c41.6 22.4 88 54.4 110.4 96 24 44.8-32 54.4-59.2 28.8-25.6-24-24-67.2-3.2-92.8 28.8-33.6 64 14.4 73.6 38.4 3.2 9.6-9.6 12.8-16 9.6-30.4-11.2-59.2-36.8-48-72 12.8-36.8 60.8-11.2 80 3.2 4.8 3.2 8 9.6 1.6 12.8-3.2 1.6-6.4 3.2-11.2 3.2-9.6 1.6-30.4-12.8-14.4-19.2 24-8 48-9.6 73.6-8 16 1.6 24 20.8 3.2 19.2-20.8-1.6-40 0-59.2 6.4-4.8-6.4-9.6-12.8-14.4-19.2 0 0 0 0 0 0 0 4.8 1.6 9.6 1.6 12.8-40-30.4-43.2 28.8-8 41.6-4.8 3.2-11.2 6.4-16 9.6-6.4-17.6-17.6-40-28.8-12.8-6.4 16-6.4 40 4.8 54.4 12.8-1.6 17.6-6.4 11.2-16-3.2-6.4-6.4-11.2-11.2-16-8-9.6-17.6-17.6-25.6-25.6-17.6-16-38.4-30.4-59.2-41.6-16-6.4 0-19.2 14.4-12.8v0z" horiz-adv-x="834" /> -<glyph unicode="" d="M260.8 342.4c-3.2 1.6-6.4 4.8-9.6 6.4-11.2-9.6-20.8-19.2-28.8-28.8 17.6-1.6 30.4-17.6 30.4-35.2v-246.4c0-19.2-16-35.2-35.2-35.2h-145.6c-19.2 0-35.2 16-35.2 35.2v246.4c0 19.2 16 35.2 35.2 35.2h56c3.2 11.2 8 24 12.8 35.2h-68.8c-40 1.6-72-30.4-72-70.4v-246.4c0-38.4 32-70.4 72-70.4h147.2c40 0 72 32 72 72v244.8c0 11.2-3.2 22.4-8 30.4-6.4 11.2-12.8 20.8-22.4 27.2zM113.6 283.2h60.8v-12.8h-60.8v12.8zM81.6 238.4h128v-12.8h-128v12.8zM81.6 193.6h128v-12.8h-128v12.8zM108.8 56h72v-27.2h-72v27.2zM552 356.8h-64l-9.6-28.8-1.6-6.4h76.8c19.2 0 35.2-16 35.2-35.2v-246.4c0-19.2-16-35.2-35.2-35.2h-147.2c-19.2 0-35.2 16-35.2 35.2v244.8c0 8 3.2 16 8 20.8l-38.4 3.2c-3.2-8-4.8-16-4.8-25.6v-246.4c0-40 32-72 72-72h147.2c40 0 72 32 72 72v248c-3.2 40-35.2 72-75.2 72zM448 283.2h60.8v-12.8h-60.8v12.8zM416 240h128v-12.8h-128v12.8zM416 198.4h128v-12.8h-128v12.8zM416 155.2h128v-12.8h-128v12.8zM416 113.6h128v-12.8h-128v12.8zM443.2 56h72v-27.2h-72v27.2zM379.2 464c-19.2 14.4-40 19.2-64 14.4-32-6.4-75.2-32-92.8-56-17.6-24-44.8-72-56-113.6 0 0 38.4 83.2 123.2 104 27.2 4.8 64 6.4 88-36.8l-35.2-25.6 97.6-9.6 32 91.2-40-20.8c-16 20.8-33.6 38.4-52.8 52.8z" horiz-adv-x="624" /> -<glyph unicode="" d="M204.8 152c0-1.6 0-1.6 0 0 0-1.6 0-1.6 0 0zM92.8 254.4v-19.2h73.6l17.6 19.2zM94.4 345.6h166.4v-17.6h-166.4v17.6zM228.8 299.2h-134.4v-17.6h116.8l3.2 3.2zM137.6 208h-43.2v-17.6h59.2l-16 16zM94.4 161.6v-17.6h105.6l-17.6 17.6zM38.4 84.8v270.4h86.4v86.4l41.6 1.6h132.8v-187.2l38.4-38.4v262.4h-337.6v-432h168l36.8 36.8h-166.4zM38.4 443.2h70.4l-70.4-70.4v70.4zM481.6 206.4l-49.6 49.6-94.4-96-96 96-48-49.6 96-94.4-96-94.4 48-49.6 96 94.4 94.4-94.4 49.6 49.6-94.4 94.4z" horiz-adv-x="482" /> -<glyph unicode="" d="M472 356.8v0 0c-6.4 9.6-9.6 17.6-9.6 30.4 0 14.4 3.2 24 11.2 32 6.4 8 16 11.2 27.2 11.2 12.8 0 22.4-4.8 28.8-12.8s11.2-20.8 9.6-36.8h-54.4c0-6.4 1.6-11.2 4.8-14.4s8-4.8 12.8-4.8c3.2 0 6.4 1.6 8 3.2 1.6 1.6 4.8 4.8 4.8 9.6l22.4-6.4c11.2-3.2 22.4-9.6 32-22.4 1.6 6.4 3.2 14.4 3.2 20.8v35.2c0 43.2-35.2 78.4-78.4 78.4h-416c-43.2 0-78.4-35.2-78.4-78.4v-33.6c0-44.8 35.2-80 78.4-80h368v19.2c0 19.2 11.2 38.4 25.6 49.6zM112 345.6h-19.2v12.8c-3.2-4.8-8-8-12.8-11.2s-9.6-3.2-16-3.2c-4.8 0-11.2 1.6-14.4 3.2-3.2 3.2-4.8 4.8-8 11.2-1.6 4.8-3.2 9.6-3.2 17.6v51.2h22.4v-38.4c0-11.2 0-19.2 1.6-20.8 1.6-3.2 1.6-4.8 4.8-6.4 1.6-1.6 4.8-1.6 8-1.6s6.4 0 9.6 3.2c3.2 3.2 3.2 4.8 4.8 8s1.6 9.6 1.6 22.4v33.6h20.8v-81.6zM204.8 355.2c-6.4-8-14.4-11.2-24-11.2-4.8 0-8 1.6-12.8 3.2-3.2 1.6-8 4.8-11.2 9.6v-41.6h-22.4v112h20.8v-11.2c3.2 4.8 6.4 8 11.2 9.6 4.8 3.2 9.6 3.2 14.4 3.2 9.6 0 17.6-3.2 24-11.2s9.6-17.6 9.6-32c0-11.2-3.2-22.4-9.6-30.4zM307.2 345.6h-20.8v12.8c-3.2-4.8-8-9.6-11.2-11.2-4.8-3.2-9.6-3.2-14.4-3.2-9.6 0-17.6 3.2-24 11.2s-9.6 17.6-9.6 32 3.2 24 9.6 32c6.4 8 14.4 11.2 25.6 11.2 9.6 0 17.6-3.2 24-11.2v40h22.4v-113.6h-1.6zM377.6 345.6c0 1.6-1.6 3.2-1.6 6.4 0 1.6 0 1.6 0 3.2-4.8-3.2-8-6.4-12.8-8s-8-3.2-12.8-3.2c-8 0-14.4 1.6-19.2 6.4-4.8 4.8-8 9.6-8 17.6 0 4.8 1.6 8 3.2 12.8 1.6 3.2 4.8 6.4 9.6 8 3.2 1.6 9.6 3.2 17.6 4.8 9.6 1.6 17.6 3.2 20.8 4.8v3.2c0 4.8-1.6 6.4-3.2 9.6-1.6 1.6-6.4 3.2-11.2 3.2-3.2 0-6.4 0-9.6-1.6-1.6-1.6-3.2-4.8-4.8-8l-19.2 3.2c1.6 8 6.4 14.4 11.2 17.6 4.8 3.2 12.8 6.4 24 6.4 9.6 0 17.6-1.6 22.4-3.2 4.8-1.6 8-4.8 9.6-8s3.2-9.6 3.2-19.2v-25.6c0-8 0-12.8 1.6-16 0-3.2 1.6-6.4 3.2-11.2l-22.4-6.4-1.6 3.2zM428.8 344c-3.2 1.6-4.8 4.8-6.4 6.4-1.6 1.6-3.2 4.8-3.2 8s0 8 0 16v36.8h-9.6v16h9.6v16l22.4 12.8v-28.8h14.4v-17.6h-14.4v-33.6c0-6.4 0-11.2 0-11.2 0-1.6 4.8-9.6 12.8-3.2l1.6-17.6c-4.8-1.6-9.6-4.8-17.6-3.2-4.8 1.6-4.8 0-9.6 3.2zM174.4 412.8c-4.8 0-9.6-1.6-12.8-6.4-3.2-3.2-6.4-9.6-6.4-17.6 0-9.6 1.6-16 4.8-20.8s8-6.4 12.8-6.4 8 1.6 12.8 6.4c4.8 4.8 6.4 9.6 6.4 19.2 0 8-1.6 14.4-4.8 19.2s-8 6.4-12.8 6.4zM267.2 412.8c-4.8 0-9.6-1.6-12.8-6.4s-4.8-9.6-4.8-17.6 1.6-14.4 3.2-19.2c3.2-6.4 8-8 14.4-8 4.8 0 9.6 1.6 12.8 6.4 3.2 4.8 4.8 11.2 4.8 19.2 0 9.6-1.6 16-4.8 20.8-3.2 3.2-8 4.8-12.8 4.8zM348.8 377.6c-3.2-1.6-4.8-4.8-4.8-8s1.6-6.4 3.2-8 4.8-3.2 8-3.2 8 1.6 11.2 3.2 4.8 4.8 4.8 6.4 1.6 4.8 1.6 11.2v6.4c-1.6-1.6-6.4-1.6-12.8-3.2-4.8-1.6-9.6-3.2-11.2-4.8zM513.6 408c-3.2 3.2-6.4 4.8-11.2 4.8s-8-1.6-11.2-4.8c-3.2-3.2-4.8-8-4.8-14.4h32c0 6.4-1.6 11.2-4.8 14.4zM684.8 174.4v0 0 38.4c-8 28.8-28.8 30.4-35.2 30.4-1.6 0-1.6 0-3.2 0h-1.6c-8 12.8-20.8 20.8-36.8 20.8-6.4 0-12.8-1.6-17.6-3.2-8 8-17.6 12.8-30.4 12.8-1.6 0-3.2 0-6.4 0v16c0 14.4 0 52.8-36.8 52.8h-3.2c-22.4 0-40-16-40-35.2v-88c-8 6.4-16 8-25.6 8-6.4 0-11.2-1.6-16-1.6-9.6-1.6-19.2-9.6-24-17.6-4.8-9.6-4.8-22.4 0-33.6l28.8-83.2 3.2-6.4 46.4-70.4 11.2-30.4 6.4-16h142.4l4.8 17.6 30.4 121.6c1.6 8 1.6 24 0 52.8 3.2 8 3.2 12.8 3.2 14.4zM660.8 113.6l-30.4-121.6h-108.8l-12.8 33.6-49.6 73.6-28.8 84.8c-3.2 8 0 17.6 6.4 19.2 4.8 1.6 8 1.6 11.2 1.6 4.8 0 9.6-1.6 14.4-8l22.4-49.6c0-1.6 3.2-3.2 4.8-3.2 3.2 0 6.4 1.6 6.4 4.8l-1.6 156.8c0 6.4 6.4 11.2 16 11.2 1.6 0 1.6 0 3.2 0 8 0 12.8-1.6 12.8-30.4v-104c0-3.2 3.2-3.2 6.4-3.2 3.2 0 6.4 1.6 6.4 3.2v54.4c0 6.4 6.4 11.2 16 11.2s16-4.8 16-11.2v-49.6c0-3.2 3.2-4.8 8-4.8s9.6 1.6 8 4.8v40c0 6.4 6.4 11.2 16 11.2v0c9.6 0 12.8-4.8 12.8-11.2v-51.2c0-3.2 3.2-4.8 4.8-4.8 3.2 0 6.4 1.6 6.4 4.8v30.4c0 6.4 4.8 12.8 12.8 12.8h1.6c6.4 0 9.6-4.8 12.8-12.8v-30.4c6.4-3.2 8-51.2 6.4-62.4z" horiz-adv-x="685" /> -</font></defs></svg> \ No newline at end of file diff --git a/unittests/example_labfolder_data/static/font/icons11.ttf b/unittests/example_labfolder_data/static/font/icons11.ttf deleted file mode 100644 index b956ee714be5bdfde6b4998de03bfc2b085ddeb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37716 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 diff --git a/unittests/example_labfolder_data/static/font/icons11.woff b/unittests/example_labfolder_data/static/font/icons11.woff deleted file mode 100644 index 2f54cb21f8b7434e3ffd4f08f9a41b40e2cf68d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26056 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 Yn^u}ialP9BJhQKGqgC8f|MvI)0Jbdv82|tP diff --git a/unittests/example_labfolder_data/static/font/redactor-font.eot b/unittests/example_labfolder_data/static/font/redactor-font.eot deleted file mode 100644 index be2a55b38dea4c0522f935541adde23cd56b8ed4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6224 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 Fe*y0O8~XqN diff --git a/unittests/example_labfolder_data/static/img/favicon2.ico b/unittests/example_labfolder_data/static/img/favicon2.ico deleted file mode 100644 index e5ae15465d3528a6eaf094b5401d93c3f07469ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmb8tPbj5P7{~GF`j>x;n}thih)JeqF&fJ$Aq$HcN~AG0+bN~g$V@hLH$!St7Q{v@ z>?tzRy*7%nz-*M7p_vttQj+5Pd+&R6Zc=pn+~+yZInU`m?|aN5{Gw6gzrwy`nH8H^ z4Jc7b)d^<I6&0ieWByJOJ(7<O44@7X1aofPV=-LUOT54>_EC$c_D5N}0rfil&*;x( z?Sj{PMgHj-{d&%~Si&CG@t~hta2{f&%k@rNPAo(zzF`?L`14teyD^WC2=?*cD>bdp z!FT*b8PunGCFXF9Bh<ie4|3H|jvdTm5-k|VA0%;zYNYjR94aDCVFkZ1gLY`2uV_OC z()u+}4JFvZD*oXIbS^ia))&@w=XBOQe1@KVI*e<?X1v1(=zRBkk?UP{VGw%vx(}~V zi~_uezV8{Xv5hxyd%Pq+Kmxzf3OA?t8vo($r{XBwniu4|xWpo=;N}!{zfR%zPcYV* zHLqBYF?1pue!uRP-p38J$6qwTU-KaMzK7;?H~TPxMg-q4eruNLi65IKlV;})W>=9= R%q&4Zg!nLqQgJhBb_elY{m%dZ diff --git a/unittests/example_labfolder_data/static/img/labfolder_icons.png b/unittests/example_labfolder_data/static/img/labfolder_icons.png deleted file mode 100644 index 7b42b63bf1e5c1056fa9df766e324f93cb93bae9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17304 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 DrmoRf diff --git a/unittests/example_labfolder_data/static/img/squares.png b/unittests/example_labfolder_data/static/img/squares.png deleted file mode 100644 index 84b9b012c7b9f50be7fe63243bce8ce7f4c83ae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEjKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgf<4jB#|)&Co<oq<9ro-U3d5r^Mi zKgfB&fQQ8~w}6}RdwlG!9a98aEgl@dcl*R=!ATxL{)}mpR*OCL-MiSV-=UF-l}qG@ zF7u4ua`g?L?w9SoD0$04H%{zSs^bEPq(;C3hkT)Yq1i4A4*V}>=DnsI%JgY_6wp2f MPgg&ebxsLQ0PAB(pa1{> diff --git a/unittests/example_labfolder_data/static/js/jquery-1.8.2.min.js b/unittests/example_labfolder_data/static/js/jquery-1.8.2.min.js deleted file mode 100644 index f65cf1dc..00000000 --- a/unittests/example_labfolder_data/static/js/jquery-1.8.2.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v1.8.2 jquery.com | jquery.org/license */ -(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window); \ No newline at end of file diff --git a/unittests/example_labfolder_data/static/js/jquery-ui.js b/unittests/example_labfolder_data/static/js/jquery-ui.js deleted file mode 100644 index 9a7ea59f..00000000 --- a/unittests/example_labfolder_data/static/js/jquery-ui.js +++ /dev/null @@ -1,14912 +0,0 @@ -/*! jQuery UI - v1.9.2 - 2012-11-23 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js -* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */ - -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// prevent duplicate loading -// this is only a problem because we proxy existing functions -// and we don't want to double proxy them -$.ui = $.ui || {}; -if ( $.ui.version ) { - return; -} - -$.extend( $.ui, { - version: "1.9.2", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - _focus: $.fn.focus, - focus: function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - this._focus.apply( this, arguments ); - }, - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,'position')) && (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x')); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,'overflow')+$.css(this,'overflow-y')+$.css(this,'overflow-x')); - }).eq(0); - } - - return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> - value = parseInt( elem.css( "zIndex" ), 31 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().andSelf().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support -$(function() { - var body = document.body, - div = body.appendChild( div = document.createElement( "div" ) ); - - // access offsetHeight before setting the style to prevent a layout bug - // in IE 9 which causes the element to continue to take up space even - // after it is removed from the DOM (#8026) - div.offsetHeight; - - $.extend( div.style, { - minHeight: "100px", - height: "auto", - padding: 0, - borderWidth: 0 - }); - - $.support.minHeight = div.offsetHeight === 100; - $.support.selectstart = "onselectstart" in div; - - // set display to none to avoid a layout bug in IE - // http://dev.jquery.com/ticket/4014 - body.removeChild( div ).style.display = "none"; -}); - -// support: jQuery <1.8 -if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated - -(function() { - var uaMatch = /msie ([\w.]+)/.exec( navigator.userAgent.toLowerCase() ) || []; - $.ui.ie = uaMatch.length ? true : false; - $.ui.ie6 = parseFloat( uaMatch[ 1 ], 10 ) === 6; -})(); - -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use the proxy pattern instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - contains: $.contains, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - }, - - // these are odd functions, fix the API or move into individual plugins - isOverAxis: function( x, reference, size ) { - //Determines when x coordinate is over "b" element axis - return ( x > reference ) && ( x < ( reference + size ) ); - }, - isOver: function( y, x, top, left, height, width ) { - //Determines when x, y coordinates is over "b" element - return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width ); - } -}); - -})( jQuery ); - -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( $.isFunction( value ) ) { - prototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - } - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, prototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - // TODO remove widgetBaseClass, see #8155 - widgetBaseClass: fullName, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "<div>", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - // 1.9 BC for #7810 - // TODO remove dual storage - $.data( element, this.widgetName, this ); - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && ( $.effects.effect[ effectName ] || $.uiBackCompat !== false && $.effects[ effectName ] ) ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -// DEPRECATED -if ( $.uiBackCompat !== false ) { - $.Widget.prototype._getCreateOptions = function() { - return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; - }; -} - -})( jQuery ); - -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function( e ) { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.9.2", - options: { - cancel: 'input,textarea,button,select,option', - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind('mousedown.'+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind('click.'+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + '.preventClickEvent')) { - $.removeData(event.target, that.widgetName + '.preventClickEvent'); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind('.'+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) { - $.removeData(event.target, this.widgetName + '.preventClickEvent'); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && !(document.documentMode >= 9) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + '.preventClickEvent', true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(event) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(event) {}, - _mouseDrag: function(event) {}, - _mouseStop: function(event) {}, - _mouseCapture: function(event) { return true; } -}); - -})(jQuery); - -(function( $, undefined ) { - -$.widget("ui.draggable", $.ui.mouse, { - version: "1.9.2", - widgetEventPrefix: "drag", - options: { - addClasses: true, - appendTo: "parent", - axis: false, - connectToSortable: false, - containment: false, - cursor: "auto", - cursorAt: false, - grid: false, - handle: false, - helper: "original", - iframeFix: false, - opacity: false, - refreshPositions: false, - revert: false, - revertDuration: 500, - scope: "default", - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - snap: false, - snapMode: "both", - snapTolerance: 20, - stack: false, - zIndex: false - }, - _create: function() { - - if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) - this.element[0].style.position = 'relative'; - - (this.options.addClasses && this.element.addClass("ui-draggable")); - (this.options.disabled && this.element.addClass("ui-draggable-disabled")); - - this._mouseInit(); - - }, - - _destroy: function() { - this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); - this._mouseDestroy(); - }, - - _mouseCapture: function(event) { - - var o = this.options; - - // among others, prevent a drag on a resizable-handle - if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) - return false; - - //Quit if we're not on a valid handle - this.handle = this._getHandle(event); - if (!this.handle) - return false; - - $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { - $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>') - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); - - return true; - - }, - - _mouseStart: function(event) { - - var o = this.options; - - //Create and append the visible helper - this.helper = this._createHelper(event); - - this.helper.addClass("ui-draggable-dragging"); - - //Cache the helper size - this._cacheHelperProportions(); - - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Store the helper's css position - this.cssPosition = this.helper.css("position"); - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.positionAbs = this.element.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this.position = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - //Trigger event + callbacks - if(this._trigger("start", event) === false) { - this._clear(); - return false; - } - - //Recache the helper size - this._cacheHelperProportions(); - - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - - this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - - //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) - if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); - - return true; - }, - - _mouseDrag: function(event, noPropagation) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - //Call plugins and callbacks and use the resulting position if something is returned - if (!noPropagation) { - var ui = this._uiHash(); - if(this._trigger('drag', event, ui) === false) { - this._mouseUp({}); - return false; - } - this.position = ui.position; - } - - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - return false; - }, - - _mouseStop: function(event) { - - //If we are using droppables, inform the manager about the drop - var dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) - dropped = $.ui.ddmanager.drop(this, event); - - //if a drop comes from outside (a sortable) - if(this.dropped) { - dropped = this.dropped; - this.dropped = false; - } - - //if the original element is no longer in the DOM don't bother to continue (see #8269) - var element = this.element[0], elementInDom = false; - while ( element && (element = element.parentNode) ) { - if (element == document ) { - elementInDom = true; - } - } - if ( !elementInDom && this.options.helper === "original" ) - return false; - - if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - var that = this; - $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - if(that._trigger("stop", event) !== false) { - that._clear(); - } - }); - } else { - if(this._trigger("stop", event) !== false) { - this._clear(); - } - } - - return false; - }, - - _mouseUp: function(event) { - //Remove frame helpers - $("div.ui-draggable-iframeFix").each(function() { - this.parentNode.removeChild(this); - }); - - //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) - if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); - - return $.ui.mouse.prototype._mouseUp.call(this, event); - }, - - cancel: function() { - - if(this.helper.is(".ui-draggable-dragging")) { - this._mouseUp({}); - } else { - this._clear(); - } - - return this; - - }, - - _getHandle: function(event) { - - var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; - $(this.options.handle, this.element) - .find("*") - .andSelf() - .each(function() { - if(this == event.target) handle = true; - }); - - return handle; - - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); - - if(!helper.parents('body').length) - helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); - - if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) - helper.css("position", "absolute"); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.element.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.element.css("marginLeft"),10) || 0), - top: (parseInt(this.element.css("marginTop"),10) || 0), - right: (parseInt(this.element.css("marginRight"),10) || 0), - bottom: (parseInt(this.element.css("marginBottom"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, - o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, - (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { - var c = $(o.containment); - var ce = c[0]; if(!ce) return; - var co = c.offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), - (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), - (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, - (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom - ]; - this.relative_container = c; - - } else if(o.containment.constructor == Array) { - this.containment = o.containment; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - var containment; - if(this.containment) { - if (this.relative_container){ - var co = this.relative_container.offset(); - containment = [ this.containment[0] + co.left, - this.containment[1] + co.top, - this.containment[2] + co.left, - this.containment[3] + co.top ]; - } - else { - containment = this.containment; - } - - if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; - } - - if(o.grid) { - //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) - var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; - pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; - pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _clear: function() { - this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); - //if($.ui.ddmanager) $.ui.ddmanager.current = null; - this.helper = null; - this.cancelHelperRemoval = false; - }, - - // From now on bulk stuff - mainly helpers - - _trigger: function(type, event, ui) { - ui = ui || this._uiHash(); - $.ui.plugin.call(this, type, [event, ui]); - if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins - return $.Widget.prototype._trigger.call(this, type, event, ui); - }, - - plugins: {}, - - _uiHash: function(event) { - return { - helper: this.helper, - position: this.position, - originalPosition: this.originalPosition, - offset: this.positionAbs - }; - } - -}); - -$.ui.plugin.add("draggable", "connectToSortable", { - start: function(event, ui) { - - var inst = $(this).data("draggable"), o = inst.options, - uiSortable = $.extend({}, ui, { item: inst.element }); - inst.sortables = []; - $(o.connectToSortable).each(function() { - var sortable = $.data(this, 'sortable'); - if (sortable && !sortable.options.disabled) { - inst.sortables.push({ - instance: sortable, - shouldRevert: sortable.options.revert - }); - sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). - sortable._trigger("activate", event, uiSortable); - } - }); - - }, - stop: function(event, ui) { - - //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("draggable"), - uiSortable = $.extend({}, ui, { item: inst.element }); - - $.each(inst.sortables, function() { - if(this.instance.isOver) { - - this.instance.isOver = 0; - - inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' - if(this.shouldRevert) this.instance.options.revert = true; - - //Trigger the stop of the sortable - this.instance._mouseStop(event); - - this.instance.options.helper = this.instance.options._helper; - - //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper == 'original') - this.instance.currentItem.css({ top: 'auto', left: 'auto' }); - - } else { - this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance - this.instance._trigger("deactivate", event, uiSortable); - } - - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"), that = this; - - var checkPos = function(o) { - var dyClick = this.offset.click.top, dxClick = this.offset.click.left; - var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; - var itemHeight = o.height, itemWidth = o.width; - var itemTop = o.top, itemLeft = o.left; - - return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); - }; - - $.each(inst.sortables, function(i) { - - var innermostIntersecting = false; - var thisSortable = this; - //Copy over some variables to allow calling the sortable's native _intersectsWith - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - - if(this.instance._intersectsWith(this.instance.containerCache)) { - innermostIntersecting = true; - $.each(inst.sortables, function () { - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - if (this != thisSortable - && this.instance._intersectsWith(this.instance.containerCache) - && $.ui.contains(thisSortable.instance.element[0], this.instance.element[0])) - innermostIntersecting = false; - return innermostIntersecting; - }); - } - - - if(innermostIntersecting) { - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!this.instance.isOver) { - - this.instance.isOver = 1; - //Now we fake the start of dragging for the sortable instance, - //by cloning the list group item, appending it to the sortable and using it as inst.currentItem - //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(that).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); - this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it - this.instance.options.helper = function() { return ui.helper[0]; }; - - event.target = this.instance.currentItem[0]; - this.instance._mouseCapture(event, true); - this.instance._mouseStart(event, true, true); - - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - this.instance.offset.click.top = inst.offset.click.top; - this.instance.offset.click.left = inst.offset.click.left; - this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; - this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; - - inst._trigger("toSortable", event); - inst.dropped = this.instance.element; //draggable revert needs that - //hack so receive/update callbacks work (mostly) - inst.currentItem = inst.element; - this.instance.fromOutside = inst; - - } - - //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) this.instance._mouseDrag(event); - - } else { - - //If it doesn't intersect with the sortable, and it intersected before, - //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval - if(this.instance.isOver) { - - this.instance.isOver = 0; - this.instance.cancelHelperRemoval = true; - - //Prevent reverting on this forced stop - this.instance.options.revert = false; - - // The out event needs to be triggered independently - this.instance._trigger('out', event, this.instance._uiHash(this.instance)); - - this.instance._mouseStop(event, true); - this.instance.options.helper = this.instance.options._helper; - - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - this.instance.currentItem.remove(); - if(this.instance.placeholder) this.instance.placeholder.remove(); - - inst._trigger("fromSortable", event); - inst.dropped = false; //draggable revert needs that - } - - }; - - }); - - } -}); - -$.ui.plugin.add("draggable", "cursor", { - start: function(event, ui) { - var t = $('body'), o = $(this).data('draggable').options; - if (t.css("cursor")) o._cursor = t.css("cursor"); - t.css("cursor", o.cursor); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if (o._cursor) $('body').css("cursor", o._cursor); - } -}); - -$.ui.plugin.add("draggable", "opacity", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data('draggable').options; - if(t.css("opacity")) o._opacity = t.css("opacity"); - t.css('opacity', o.opacity); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if(o._opacity) $(ui.helper).css('opacity', o._opacity); - } -}); - -$.ui.plugin.add("draggable", "scroll", { - start: function(event, ui) { - var i = $(this).data("draggable"); - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); - }, - drag: function(event, ui) { - - var i = $(this).data("draggable"), o = i.options, scrolled = false; - - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { - - if(!o.axis || o.axis != 'x') { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if(!o.axis || o.axis != 'y') { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(!o.axis || o.axis != 'x') { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(!o.axis || o.axis != 'y') { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(i, event); - - } -}); - -$.ui.plugin.add("draggable", "snap", { - start: function(event, ui) { - - var i = $(this).data("draggable"), o = i.options; - i.snapElements = []; - - $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { - var $t = $(this); var $o = $t.offset(); - if(this != i.element[0]) i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"), o = inst.options; - var d = o.snapTolerance; - - var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, - y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - - for (var i = inst.snapElements.length - 1; i >= 0; i--){ - - var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, - t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; - - //Yes, I know, this is insane ;) - if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { - if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = false; - continue; - } - - if(o.snapMode != 'inner') { - var ts = Math.abs(t - y2) <= d; - var bs = Math.abs(b - y1) <= d; - var ls = Math.abs(l - x2) <= d; - var rs = Math.abs(r - x1) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; - } - - var first = (ts || bs || ls || rs); - - if(o.snapMode != 'outer') { - var ts = Math.abs(t - y1) <= d; - var bs = Math.abs(b - y2) <= d; - var ls = Math.abs(l - x1) <= d; - var rs = Math.abs(r - x2) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; - } - - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) - (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - - }; - - } -}); - -$.ui.plugin.add("draggable", "stack", { - start: function(event, ui) { - - var o = $(this).data("draggable").options; - - var group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); - if (!group.length) { return; } - - var min = parseInt(group[0].style.zIndex) || 0; - $(group).each(function(i) { - this.style.zIndex = min + i; - }); - - this[0].style.zIndex = min + group.length; - - } -}); - -$.ui.plugin.add("draggable", "zIndex", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("draggable").options; - if(t.css("zIndex")) o._zIndex = t.css("zIndex"); - t.css('zIndex', o.zIndex); - }, - stop: function(event, ui) { - var o = $(this).data("draggable").options; - if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); - } -}); - -})(jQuery); - -(function( $, undefined ) { - -$.widget("ui.droppable", { - version: "1.9.2", - widgetEventPrefix: "drop", - options: { - accept: '*', - activeClass: false, - addClasses: true, - greedy: false, - hoverClass: false, - scope: 'default', - tolerance: 'intersect' - }, - _create: function() { - - var o = this.options, accept = o.accept; - this.isover = 0; this.isout = 1; - - this.accept = $.isFunction(accept) ? accept : function(d) { - return d.is(accept); - }; - - //Store the droppable's proportions - this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; - - // Add the reference and positions to the manager - $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; - $.ui.ddmanager.droppables[o.scope].push(this); - - (o.addClasses && this.element.addClass("ui-droppable")); - - }, - - _destroy: function() { - var drop = $.ui.ddmanager.droppables[this.options.scope]; - for ( var i = 0; i < drop.length; i++ ) - if ( drop[i] == this ) - drop.splice(i, 1); - - this.element.removeClass("ui-droppable ui-droppable-disabled"); - }, - - _setOption: function(key, value) { - - if(key == 'accept') { - this.accept = $.isFunction(value) ? value : function(d) { - return d.is(value); - }; - } - $.Widget.prototype._setOption.apply(this, arguments); - }, - - _activate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.addClass(this.options.activeClass); - (draggable && this._trigger('activate', event, this.ui(draggable))); - }, - - _deactivate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - (draggable && this._trigger('deactivate', event, this.ui(draggable))); - }, - - _over: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); - this._trigger('over', event, this.ui(draggable)); - } - - }, - - _out: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('out', event, this.ui(draggable)); - } - - }, - - _drop: function(event,custom) { - - var draggable = custom || $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element - - var childrenIntersection = false; - this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { - var inst = $.data(this, 'droppable'); - if( - inst.options.greedy - && !inst.options.disabled - && inst.options.scope == draggable.options.scope - && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) - && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) - ) { childrenIntersection = true; return false; } - }); - if(childrenIntersection) return false; - - if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.activeClass) this.element.removeClass(this.options.activeClass); - if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); - this._trigger('drop', event, this.ui(draggable)); - return this.element; - } - - return false; - - }, - - ui: function(c) { - return { - draggable: (c.currentItem || c.element), - helper: c.helper, - position: c.position, - offset: c.positionAbs - }; - } - -}); - -$.ui.intersect = function(draggable, droppable, toleranceMode) { - - if (!droppable.offset) return false; - - var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; - var l = droppable.offset.left, r = l + droppable.proportions.width, - t = droppable.offset.top, b = t + droppable.proportions.height; - - switch (toleranceMode) { - case 'fit': - return (l <= x1 && x2 <= r - && t <= y1 && y2 <= b); - break; - case 'intersect': - return (l < x1 + (draggable.helperProportions.width / 2) // Right Half - && x2 - (draggable.helperProportions.width / 2) < r // Left Half - && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half - && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - break; - case 'pointer': - var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), - isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); - return isOver; - break; - case 'touch': - return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - break; - default: - return false; - break; - } - -}; - -/* - This manager tracks offsets of draggables and droppables -*/ -$.ui.ddmanager = { - current: null, - droppables: { 'default': [] }, - prepareOffsets: function(t, event) { - - var m = $.ui.ddmanager.droppables[t.options.scope] || []; - var type = event ? event.type : null; // workaround for #2317 - var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); - - droppablesLoop: for (var i = 0; i < m.length; i++) { - - if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted - for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item - m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue - - if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables - - m[i].offset = m[i].element.offset(); - m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; - - } - - }, - drop: function(draggable, event) { - - var dropped = false; - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(!this.options) return; - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) - dropped = this._drop.call(this, event) || dropped; - - if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - this.isout = 1; this.isover = 0; - this._deactivate.call(this, event); - } - - }); - return dropped; - - }, - dragStart: function( draggable, event ) { - //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) - draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); - }); - }, - drag: function(draggable, event) { - - //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); - - //Run through all droppables and check their positions based on specific tolerance options - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(this.options.disabled || this.greedyChild || !this.visible) return; - var intersects = $.ui.intersect(draggable, this, this.options.tolerance); - - var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); - if(!c) return; - - var parentInstance; - if (this.options.greedy) { - // find droppable parents with same scope - var scope = this.options.scope; - var parent = this.element.parents(':data(droppable)').filter(function () { - return $.data(this, 'droppable').options.scope === scope; - }); - - if (parent.length) { - parentInstance = $.data(parent[0], 'droppable'); - parentInstance.greedyChild = (c == 'isover' ? 1 : 0); - } - } - - // we just moved into a greedy child - if (parentInstance && c == 'isover') { - parentInstance['isover'] = 0; - parentInstance['isout'] = 1; - parentInstance._out.call(parentInstance, event); - } - - this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; - this[c == "isover" ? "_over" : "_out"].call(this, event); - - // we just moved out of a greedy child - if (parentInstance && c == 'isout') { - parentInstance['isout'] = 0; - parentInstance['isover'] = 1; - parentInstance._over.call(parentInstance, event); - } - }); - - }, - dragStop: function( draggable, event ) { - draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); - //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); - } -}; - -})(jQuery); - -(function( $, undefined ) { - -$.widget("ui.resizable", $.ui.mouse, { - version: "1.9.2", - widgetEventPrefix: "resize", - options: { - alsoResize: false, - animate: false, - animateDuration: "slow", - animateEasing: "swing", - aspectRatio: false, - autoHide: false, - containment: false, - ghost: false, - grid: false, - handles: "e,s,se", - helper: false, - maxHeight: null, - maxWidth: null, - minHeight: 10, - minWidth: 10, - zIndex: 1000 - }, - _create: function() { - - var that = this, o = this.options; - this.element.addClass("ui-resizable"); - - $.extend(this, { - _aspectRatio: !!(o.aspectRatio), - aspectRatio: o.aspectRatio, - originalElement: this.element, - _proportionallyResizeElements: [], - _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null - }); - - //Wrap the element if it cannot hold child nodes - if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { - - //Create a wrapper element and set the wrapper to the new current internal element - this.element.wrap( - $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({ - position: this.element.css('position'), - width: this.element.outerWidth(), - height: this.element.outerHeight(), - top: this.element.css('top'), - left: this.element.css('left') - }) - ); - - //Overwrite the original this.element - this.element = this.element.parent().data( - "resizable", this.element.data('resizable') - ); - - this.elementIsWrapper = true; - - //Move margins to the wrapper - this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); - this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); - - //Prevent Safari textarea resize - this.originalResizeStyle = this.originalElement.css('resize'); - this.originalElement.css('resize', 'none'); - - //Push the actual element to our proportionallyResize internal array - this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); - - // avoid IE jump (hard set the margin) - this.originalElement.css({ margin: this.originalElement.css('margin') }); - - // fix handlers offset - this._proportionallyResize(); - - } - - this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); - if(this.handles.constructor == String) { - - if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; - var n = this.handles.split(","); this.handles = {}; - - for(var i = 0; i < n.length; i++) { - - var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; - var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>'); - - // Apply zIndex to all handles - see #7960 - axis.css({ zIndex: o.zIndex }); - - //TODO : What's going on here? - if ('se' == handle) { - axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); - }; - - //Insert into internal handles object and append to element - this.handles[handle] = '.ui-resizable-'+handle; - this.element.append(axis); - } - - } - - this._renderAxis = function(target) { - - target = target || this.element; - - for(var i in this.handles) { - - if(this.handles[i].constructor == String) - this.handles[i] = $(this.handles[i], this.element).show(); - - //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) - if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { - - var axis = $(this.handles[i], this.element), padWrapper = 0; - - //Checking the correct pad and border - padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); - - //The padding type i have to apply... - var padPos = [ 'padding', - /ne|nw|n/.test(i) ? 'Top' : - /se|sw|s/.test(i) ? 'Bottom' : - /^e$/.test(i) ? 'Right' : 'Left' ].join(""); - - target.css(padPos, padWrapper); - - this._proportionallyResize(); - - } - - //TODO: What's that good for? There's not anything to be executed left - if(!$(this.handles[i]).length) - continue; - - } - }; - - //TODO: make renderAxis a prototype function - this._renderAxis(this.element); - - this._handles = $('.ui-resizable-handle', this.element) - .disableSelection(); - - //Matching axis name - this._handles.mouseover(function() { - if (!that.resizing) { - if (this.className) - var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); - //Axis, default = se - that.axis = axis && axis[1] ? axis[1] : 'se'; - } - }); - - //If we want to auto hide the elements - if (o.autoHide) { - this._handles.hide(); - $(this.element) - .addClass("ui-resizable-autohide") - .mouseenter(function() { - if (o.disabled) return; - $(this).removeClass("ui-resizable-autohide"); - that._handles.show(); - }) - .mouseleave(function(){ - if (o.disabled) return; - if (!that.resizing) { - $(this).addClass("ui-resizable-autohide"); - that._handles.hide(); - } - }); - } - - //Initialize the mouse interaction - this._mouseInit(); - - }, - - _destroy: function() { - - this._mouseDestroy(); - - var _destroy = function(exp) { - $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") - .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); - }; - - //TODO: Unwrap at same DOM position - if (this.elementIsWrapper) { - _destroy(this.element); - var wrapper = this.element; - this.originalElement.css({ - position: wrapper.css('position'), - width: wrapper.outerWidth(), - height: wrapper.outerHeight(), - top: wrapper.css('top'), - left: wrapper.css('left') - }).insertAfter( wrapper ); - wrapper.remove(); - } - - this.originalElement.css('resize', this.originalResizeStyle); - _destroy(this.originalElement); - - return this; - }, - - _mouseCapture: function(event) { - var handle = false; - for (var i in this.handles) { - if ($(this.handles[i])[0] == event.target) { - handle = true; - } - } - - return !this.options.disabled && handle; - }, - - _mouseStart: function(event) { - - var o = this.options, iniPos = this.element.position(), el = this.element; - - this.resizing = true; - this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; - - // bugfix for http://dev.jquery.com/ticket/1749 - if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { - el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); - } - - this._renderProxy(); - - var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); - - if (o.containment) { - curleft += $(o.containment).scrollLeft() || 0; - curtop += $(o.containment).scrollTop() || 0; - } - - //Store needed variables - this.offset = this.helper.offset(); - this.position = { left: curleft, top: curtop }; - this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalPosition = { left: curleft, top: curtop }; - this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; - this.originalMousePosition = { left: event.pageX, top: event.pageY }; - - //Aspect Ratio - this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - - var cursor = $('.ui-resizable-' + this.axis).css('cursor'); - $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); - - el.addClass("ui-resizable-resizing"); - this._propagate("start", event); - return true; - }, - - _mouseDrag: function(event) { - - //Increase performance, avoid regex - var el = this.helper, o = this.options, props = {}, - that = this, smp = this.originalMousePosition, a = this.axis; - - var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; - var trigger = this._change[a]; - if (!trigger) return false; - - // Calculate the attrs that will be change - var data = trigger.apply(this, [event, dx, dy]); - - // Put this in the mouseDrag handler since the user can start pressing shift while resizing - this._updateVirtualBoundaries(event.shiftKey); - if (this._aspectRatio || event.shiftKey) - data = this._updateRatio(data, event); - - data = this._respectSize(data, event); - - // plugins callbacks need to be called first - this._propagate("resize", event); - - el.css({ - top: this.position.top + "px", left: this.position.left + "px", - width: this.size.width + "px", height: this.size.height + "px" - }); - - if (!this._helper && this._proportionallyResizeElements.length) - this._proportionallyResize(); - - this._updateCache(data); - - // calling the user callback at the end - this._trigger('resize', event, this.ui()); - - return false; - }, - - _mouseStop: function(event) { - - this.resizing = false; - var o = this.options, that = this; - - if(this._helper) { - var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height, - soffsetw = ista ? 0 : that.sizeDiff.width; - - var s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }, - left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null, - top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null; - - if (!o.animate) - this.element.css($.extend(s, { top: top, left: left })); - - that.helper.height(that.size.height); - that.helper.width(that.size.width); - - if (this._helper && !o.animate) this._proportionallyResize(); - } - - $('body').css('cursor', 'auto'); - - this.element.removeClass("ui-resizable-resizing"); - - this._propagate("stop", event); - - if (this._helper) this.helper.remove(); - return false; - - }, - - _updateVirtualBoundaries: function(forceAspectRatio) { - var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b; - - b = { - minWidth: isNumber(o.minWidth) ? o.minWidth : 0, - maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, - minHeight: isNumber(o.minHeight) ? o.minHeight : 0, - maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity - }; - - if(this._aspectRatio || forceAspectRatio) { - // We want to create an enclosing box whose aspect ration is the requested one - // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension - pMinWidth = b.minHeight * this.aspectRatio; - pMinHeight = b.minWidth / this.aspectRatio; - pMaxWidth = b.maxHeight * this.aspectRatio; - pMaxHeight = b.maxWidth / this.aspectRatio; - - if(pMinWidth > b.minWidth) b.minWidth = pMinWidth; - if(pMinHeight > b.minHeight) b.minHeight = pMinHeight; - if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth; - if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight; - } - this._vBoundaries = b; - }, - - _updateCache: function(data) { - var o = this.options; - this.offset = this.helper.offset(); - if (isNumber(data.left)) this.position.left = data.left; - if (isNumber(data.top)) this.position.top = data.top; - if (isNumber(data.height)) this.size.height = data.height; - if (isNumber(data.width)) this.size.width = data.width; - }, - - _updateRatio: function(data, event) { - - var o = this.options, cpos = this.position, csize = this.size, a = this.axis; - - if (isNumber(data.height)) data.width = (data.height * this.aspectRatio); - else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio); - - if (a == 'sw') { - data.left = cpos.left + (csize.width - data.width); - data.top = null; - } - if (a == 'nw') { - data.top = cpos.top + (csize.height - data.height); - data.left = cpos.left + (csize.width - data.width); - } - - return data; - }, - - _respectSize: function(data, event) { - - var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, - ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), - isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); - - if (isminw) data.width = o.minWidth; - if (isminh) data.height = o.minHeight; - if (ismaxw) data.width = o.maxWidth; - if (ismaxh) data.height = o.maxHeight; - - var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; - var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - - if (isminw && cw) data.left = dw - o.minWidth; - if (ismaxw && cw) data.left = dw - o.maxWidth; - if (isminh && ch) data.top = dh - o.minHeight; - if (ismaxh && ch) data.top = dh - o.maxHeight; - - // fixing jump error on top/left - bug #2330 - var isNotwh = !data.width && !data.height; - if (isNotwh && !data.left && data.top) data.top = null; - else if (isNotwh && !data.top && data.left) data.left = null; - - return data; - }, - - _proportionallyResize: function() { - - var o = this.options; - if (!this._proportionallyResizeElements.length) return; - var element = this.helper || this.element; - - for (var i=0; i < this._proportionallyResizeElements.length; i++) { - - var prel = this._proportionallyResizeElements[i]; - - if (!this.borderDif) { - var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], - p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; - - this.borderDif = $.map(b, function(v, i) { - var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; - return border + padding; - }); - } - - prel.css({ - height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, - width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 - }); - - }; - - }, - - _renderProxy: function() { - - var el = this.element, o = this.options; - this.elementOffset = el.offset(); - - if(this._helper) { - - this.helper = this.helper || $('<div style="overflow:hidden;"></div>'); - - // fix ie6 offset TODO: This seems broken - var ie6offset = ($.ui.ie6 ? 1 : 0), - pxyoffset = ( $.ui.ie6 ? 2 : -1 ); - - this.helper.addClass(this._helper).css({ - width: this.element.outerWidth() + pxyoffset, - height: this.element.outerHeight() + pxyoffset, - position: 'absolute', - left: this.elementOffset.left - ie6offset +'px', - top: this.elementOffset.top - ie6offset +'px', - zIndex: ++o.zIndex //TODO: Don't modify option - }); - - this.helper - .appendTo("body") - .disableSelection(); - - } else { - this.helper = this.element; - } - - }, - - _change: { - e: function(event, dx, dy) { - return { width: this.originalSize.width + dx }; - }, - w: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { left: sp.left + dx, width: cs.width - dx }; - }, - n: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { top: sp.top + dy, height: cs.height - dy }; - }, - s: function(event, dx, dy) { - return { height: this.originalSize.height + dy }; - }, - se: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - sw: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - }, - ne: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - nw: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - } - }, - - _propagate: function(n, event) { - $.ui.plugin.call(this, n, [event, this.ui()]); - (n != "resize" && this._trigger(n, event, this.ui())); - }, - - plugins: {}, - - ui: function() { - return { - originalElement: this.originalElement, - element: this.element, - helper: this.helper, - position: this.position, - size: this.size, - originalSize: this.originalSize, - originalPosition: this.originalPosition - }; - } - -}); - -/* - * Resizable Extensions - */ - -$.ui.plugin.add("resizable", "alsoResize", { - - start: function (event, ui) { - var that = $(this).data("resizable"), o = that.options; - - var _store = function (exp) { - $(exp).each(function() { - var el = $(this); - el.data("resizable-alsoresize", { - width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), - left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10) - }); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function (exp) { _store(exp); }); } - }else{ - _store(o.alsoResize); - } - }, - - resize: function (event, ui) { - var that = $(this).data("resizable"), o = that.options, os = that.originalSize, op = that.originalPosition; - - var delta = { - height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, - top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 - }, - - _alsoResize = function (exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, - css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; - - $.each(css, function (i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) - style[prop] = sum || null; - }); - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); - } - }, - - stop: function (event, ui) { - $(this).removeData("resizable-alsoresize"); - } -}); - -$.ui.plugin.add("resizable", "animate", { - - stop: function(event, ui) { - var that = $(this).data("resizable"), o = that.options; - - var pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : that.sizeDiff.height, - soffsetw = ista ? 0 : that.sizeDiff.width; - - var style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, - left = (parseInt(that.element.css('left'), 10) + (that.position.left - that.originalPosition.left)) || null, - top = (parseInt(that.element.css('top'), 10) + (that.position.top - that.originalPosition.top)) || null; - - that.element.animate( - $.extend(style, top && left ? { top: top, left: left } : {}), { - duration: o.animateDuration, - easing: o.animateEasing, - step: function() { - - var data = { - width: parseInt(that.element.css('width'), 10), - height: parseInt(that.element.css('height'), 10), - top: parseInt(that.element.css('top'), 10), - left: parseInt(that.element.css('left'), 10) - }; - - if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); - - // propagating resize, and updating values for each animation step - that._updateCache(data); - that._propagate("resize", event); - - } - } - ); - } - -}); - -$.ui.plugin.add("resizable", "containment", { - - start: function(event, ui) { - var that = $(this).data("resizable"), o = that.options, el = that.element; - var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - if (!ce) return; - - that.containerElement = $(ce); - - if (/document/.test(oc) || oc == document) { - that.containerOffset = { left: 0, top: 0 }; - that.containerPosition = { left: 0, top: 0 }; - - that.parentData = { - element: $(document), left: 0, top: 0, - width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight - }; - } - - // i'm a node, so compute top, left, right, bottom - else { - var element = $(ce), p = []; - $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); - - that.containerOffset = element.offset(); - that.containerPosition = element.position(); - that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - - var co = that.containerOffset, ch = that.containerSize.height, cw = that.containerSize.width, - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); - - that.parentData = { - element: ce, left: co.left, top: co.top, width: width, height: height - }; - } - }, - - resize: function(event, ui) { - var that = $(this).data("resizable"), o = that.options, - ps = that.containerSize, co = that.containerOffset, cs = that.size, cp = that.position, - pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement; - - if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; - - if (cp.left < (that._helper ? co.left : 0)) { - that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); - if (pRatio) that.size.height = that.size.width / that.aspectRatio; - that.position.left = o.helper ? co.left : 0; - } - - if (cp.top < (that._helper ? co.top : 0)) { - that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); - if (pRatio) that.size.width = that.size.height * that.aspectRatio; - that.position.top = that._helper ? co.top : 0; - } - - that.offset.left = that.parentData.left+that.position.left; - that.offset.top = that.parentData.top+that.position.top; - - var woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ), - hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); - - var isParent = that.containerElement.get(0) == that.element.parent().get(0), - isOffsetRelative = /relative|absolute/.test(that.containerElement.css('position')); - - if(isParent && isOffsetRelative) woset -= that.parentData.left; - - if (woset + that.size.width >= that.parentData.width) { - that.size.width = that.parentData.width - woset; - if (pRatio) that.size.height = that.size.width / that.aspectRatio; - } - - if (hoset + that.size.height >= that.parentData.height) { - that.size.height = that.parentData.height - hoset; - if (pRatio) that.size.width = that.size.height * that.aspectRatio; - } - }, - - stop: function(event, ui){ - var that = $(this).data("resizable"), o = that.options, cp = that.position, - co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement; - - var helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height; - - if (that._helper && !o.animate && (/relative/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - if (that._helper && !o.animate && (/static/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - } -}); - -$.ui.plugin.add("resizable", "ghost", { - - start: function(event, ui) { - - var that = $(this).data("resizable"), o = that.options, cs = that.size; - - that.ghost = that.originalElement.clone(); - that.ghost - .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) - .addClass('ui-resizable-ghost') - .addClass(typeof o.ghost == 'string' ? o.ghost : ''); - - that.ghost.appendTo(that.helper); - - }, - - resize: function(event, ui){ - var that = $(this).data("resizable"), o = that.options; - if (that.ghost) that.ghost.css({ position: 'relative', height: that.size.height, width: that.size.width }); - }, - - stop: function(event, ui){ - var that = $(this).data("resizable"), o = that.options; - if (that.ghost && that.helper) that.helper.get(0).removeChild(that.ghost.get(0)); - } - -}); - -$.ui.plugin.add("resizable", "grid", { - - resize: function(event, ui) { - var that = $(this).data("resizable"), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, ratio = o._aspectRatio || event.shiftKey; - o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; - var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); - - if (/^(se|s|e)$/.test(a)) { - that.size.width = os.width + ox; - that.size.height = os.height + oy; - } - else if (/^(ne)$/.test(a)) { - that.size.width = os.width + ox; - that.size.height = os.height + oy; - that.position.top = op.top - oy; - } - else if (/^(sw)$/.test(a)) { - that.size.width = os.width + ox; - that.size.height = os.height + oy; - that.position.left = op.left - ox; - } - else { - that.size.width = os.width + ox; - that.size.height = os.height + oy; - that.position.top = op.top - oy; - that.position.left = op.left - ox; - } - } - -}); - -var num = function(v) { - return parseInt(v, 10) || 0; -}; - -var isNumber = function(value) { - return !isNaN(parseInt(value, 10)); -}; - -})(jQuery); - -(function( $, undefined ) { - -$.widget("ui.selectable", $.ui.mouse, { - version: "1.9.2", - options: { - appendTo: 'body', - autoRefresh: true, - distance: 0, - filter: '*', - tolerance: 'touch' - }, - _create: function() { - var that = this; - - this.element.addClass("ui-selectable"); - - this.dragged = false; - - // cache selectee children based on filter - var selectees; - this.refresh = function() { - selectees = $(that.options.filter, that.element[0]); - selectees.addClass("ui-selectee"); - selectees.each(function() { - var $this = $(this); - var pos = $this.offset(); - $.data(this, "selectable-item", { - element: this, - $element: $this, - left: pos.left, - top: pos.top, - right: pos.left + $this.outerWidth(), - bottom: pos.top + $this.outerHeight(), - startselected: false, - selected: $this.hasClass('ui-selected'), - selecting: $this.hasClass('ui-selecting'), - unselecting: $this.hasClass('ui-unselecting') - }); - }); - }; - this.refresh(); - - this.selectees = selectees.addClass("ui-selectee"); - - this._mouseInit(); - - this.helper = $("<div class='ui-selectable-helper'></div>"); - }, - - _destroy: function() { - this.selectees - .removeClass("ui-selectee") - .removeData("selectable-item"); - this.element - .removeClass("ui-selectable ui-selectable-disabled"); - this._mouseDestroy(); - }, - - _mouseStart: function(event) { - var that = this; - - this.opos = [event.pageX, event.pageY]; - - if (this.options.disabled) - return; - - var options = this.options; - - this.selectees = $(options.filter, this.element[0]); - - this._trigger("start", event); - - $(options.appendTo).append(this.helper); - // position helper (lasso) - this.helper.css({ - "left": event.clientX, - "top": event.clientY, - "width": 0, - "height": 0 - }); - - if (options.autoRefresh) { - this.refresh(); - } - - this.selectees.filter('.ui-selected').each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.startselected = true; - if (!event.metaKey && !event.ctrlKey) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - }); - - $(event.target).parents().andSelf().each(function() { - var selectee = $.data(this, "selectable-item"); - if (selectee) { - var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected'); - selectee.$element - .removeClass(doSelect ? "ui-unselecting" : "ui-selected") - .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); - selectee.unselecting = !doSelect; - selectee.selecting = doSelect; - selectee.selected = doSelect; - // selectable (UN)SELECTING callback - if (doSelect) { - that._trigger("selecting", event, { - selecting: selectee.element - }); - } else { - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - return false; - } - }); - - }, - - _mouseDrag: function(event) { - var that = this; - this.dragged = true; - - if (this.options.disabled) - return; - - var options = this.options; - - var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; - if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); - - this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"); - //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element == that.element[0]) - return; - var hit = false; - if (options.tolerance == 'touch') { - hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance == 'fit') { - hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); - } - - if (hit) { - // SELECT - if (selectee.selected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - } - if (selectee.unselecting) { - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - } - if (!selectee.selecting) { - selectee.$element.addClass('ui-selecting'); - selectee.selecting = true; - // selectable SELECTING callback - that._trigger("selecting", event, { - selecting: selectee.element - }); - } - } else { - // UNSELECT - if (selectee.selecting) { - if ((event.metaKey || event.ctrlKey) && selectee.startselected) { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - selectee.$element.addClass('ui-selected'); - selectee.selected = true; - } else { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - if (selectee.startselected) { - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - } - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - if (selectee.selected) { - if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - } - }); - - return false; - }, - - _mouseStop: function(event) { - var that = this; - - this.dragged = false; - - var options = this.options; - - $('.ui-unselecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - selectee.startselected = false; - that._trigger("unselected", event, { - unselected: selectee.element - }); - }); - $('.ui-selecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); - selectee.selecting = false; - selectee.selected = true; - selectee.startselected = true; - that._trigger("selected", event, { - selected: selectee.element - }); - }); - this._trigger("stop", event); - - this.helper.remove(); - - return false; - } - -}); - -})(jQuery); - -(function( $, undefined ) { - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.9.2", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: 'auto', - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: '> *', - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000 - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) - this.items[i].item.removeData(this.widgetName + "-item"); - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type == 'static') return false; - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - var currentItem = null, nodes = $(event.target).parents().each(function() { - if($.data(this, that.widgetName + '-item') == that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + '-item') == that) currentItem = $(event.target); - - if(!currentItem) return false; - if(this.options.handle && !overrideHandle) { - var validHandle = false; - - $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); - if(!validHandle) return false; - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var o = this.options; - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] != this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - if(o.cursor) { // cursor option - if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); - $('body').css("cursor", o.cursor); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') - this.overflowOffset = this.scrollParent.offset(); - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) - this._cacheHelperProportions(); - - - //Post 'activate' events to possible containers - if(!noActivation) { - for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this._uiHash(this)); } - } - - //Prepare possible droppables - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - var o = this.options, scrolled = false; - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - - //Rearrange - for (var i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); - if (!intersection) continue; - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) continue; - - if (itemElement != this.currentItem[0] //cannot intersect with itself - && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before - && !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked - && (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true) - //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container - ) { - - this.direction = intersection == 1 ? "down" : "up"; - - if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - //Call callbacks - this._trigger('sort', event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) return; - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) - $.ui.ddmanager.drop(this, event); - - if(this.options.revert) { - var that = this; - var cur = this.placeholder.offset(); - - this.reverting = true; - - $(this.helper).animate({ - left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), - top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) - }, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper == "original") - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - else - this.currentItem.show(); - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var str = []; o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); - if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); - }); - - if(!str.length && o.key) { - str.push(o.key + '='); - } - - return str.join('&'); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var ret = []; o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height; - - var l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height; - - var dyClick = this.offset.click.top, - dxClick = this.offset.click.left; - - var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; - - if( this.options.tolerance == "pointer" - || this.options.forcePointerForContainers - || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) // Right Half - && x2 - (this.helperProportions.width / 2) < r // Left Half - && t < y1 + (this.helperProportions.height / 2) // Bottom Half - && y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) - return false; - - return this.floating ? - ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta != 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta != 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor == String - ? [options.connectWith] - : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var items = []; - var queries = []; - var connectWith = this._connectWith(); - - if(connectWith && connected) { - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], this.widgetName); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]); - } - }; - }; - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]); - - for (var i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - }; - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] == item.item[0]) - return false; - }; - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - var items = this.items; - var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; - var connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], this.widgetName); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - }; - }; - } - - for (var i = queries.length - 1; i >= 0; i--) { - var targetData = queries[i][1]; - var _queries = queries[i][0]; - - for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { - var item = $(_queries[j]); - - item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - }; - }; - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - for (var i = this.items.length - 1; i >= 0; i--){ - var item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) - continue; - - var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - var p = t.offset(); - item.left = p.left; - item.top = p.top; - }; - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (var i = this.containers.length - 1; i >= 0; i--){ - var p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - }; - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var o = that.options; - - if(!o.placeholder || o.placeholder.constructor == String) { - var className = o.placeholder; - o.placeholder = { - element: function() { - - var el = $(document.createElement(that.currentItem[0].nodeName)) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper")[0]; - - if(!className) - el.style.visibility = "hidden"; - - return el; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) return; - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css('paddingTop')||0, 10) - parseInt(that.currentItem.css('paddingBottom')||0, 10)); }; - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css('paddingLeft')||0, 10) - parseInt(that.currentItem.css('paddingRight')||0, 10)); }; - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - - // get innermost container that intersects with item - var innermostContainer = null, innermostIndex = null; - - - for (var i = this.containers.length - 1; i >= 0; i--){ - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) - continue; - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) - continue; - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) return; - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - var dist = 10000; var itemWithLeastDistance = null; - var posProperty = this.containers[innermostIndex].floating ? 'left' : 'top'; - var sizeProperty = this.containers[innermostIndex].floating ? 'width' : 'height'; - var base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (var j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; - if(this.items[j].item[0] == this.currentItem[0]) continue; - var cur = this.items[j].item.offset()[posProperty]; - var nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled - return; - - this.currentContainer = this.containers[innermostIndex]; - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); - - if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already - $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - - if(helper[0] == this.currentItem[0]) - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - - if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); - if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.ui.ie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment)) { - var ce = $(o.containment)[0]; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; - } - - if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ( ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem); - this._noFinalSort = null; - - if(this.helper[0] == this.currentItem[0]) { - for(var i in this._storedCSS) { - if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor - if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity - if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; - - if(!noPropagation) { - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); - -;(jQuery.effects || (function($, undefined) { - -var backCompat = $.uiBackCompat !== false, - // prefix used for storing data on .data() - dataSpace = "ui-effects-"; - -$.effects = { - effect: {} -}; - -/*! - * jQuery Color Animations v2.0.0 - * http://jquery.com/ - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * Date: Mon Aug 13 13:41:02 2012 -0500 - */ -(function( jQuery, undefined ) { - - var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor".split(" "), - - // plusequals test for += 100 -= 100 - rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, - // a set of RE's that can match strings and generate color tuples. - stringParsers = [{ - re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ], - execResult[ 3 ], - execResult[ 4 ] - ]; - } - }, { - re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ] * 2.55, - execResult[ 2 ] * 2.55, - execResult[ 3 ] * 2.55, - execResult[ 4 ] - ]; - } - }, { - // this regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ], 16 ) - ]; - } - }, { - // this regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) - ]; - } - }, { - re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, - space: "hsla", - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ] / 100, - execResult[ 3 ] / 100, - execResult[ 4 ] - ]; - } - }], - - // jQuery.Color( ) - color = jQuery.Color = function( color, green, blue, alpha ) { - return new jQuery.Color.fn.parse( color, green, blue, alpha ); - }, - spaces = { - rgba: { - props: { - red: { - idx: 0, - type: "byte" - }, - green: { - idx: 1, - type: "byte" - }, - blue: { - idx: 2, - type: "byte" - } - } - }, - - hsla: { - props: { - hue: { - idx: 0, - type: "degrees" - }, - saturation: { - idx: 1, - type: "percent" - }, - lightness: { - idx: 2, - type: "percent" - } - } - } - }, - propTypes = { - "byte": { - floor: true, - max: 255 - }, - "percent": { - max: 1 - }, - "degrees": { - mod: 360, - floor: true - } - }, - support = color.support = {}, - - // element for support tests - supportElem = jQuery( "<p>" )[ 0 ], - - // colors = jQuery.Color.names - colors, - - // local aliases of functions called often - each = jQuery.each; - -// determine rgba support immediately -supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; -support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; - -// define cache name and alpha properties -// for rgba and hsla spaces -each( spaces, function( spaceName, space ) { - space.cache = "_" + spaceName; - space.props.alpha = { - idx: 3, - type: "percent", - def: 1 - }; -}); - -function clamp( value, prop, allowEmpty ) { - var type = propTypes[ prop.type ] || {}; - - if ( value == null ) { - return (allowEmpty || !prop.def) ? null : prop.def; - } - - // ~~ is an short way of doing floor for positive numbers - value = type.floor ? ~~value : parseFloat( value ); - - // IE will pass in empty strings as value for alpha, - // which will hit this case - if ( isNaN( value ) ) { - return prop.def; - } - - if ( type.mod ) { - // we add mod before modding to make sure that negatives values - // get converted properly: -10 -> 350 - return (value + type.mod) % type.mod; - } - - // for now all property types without mod have min and max - return 0 > value ? 0 : type.max < value ? type.max : value; -} - -function stringParse( string ) { - var inst = color(), - rgba = inst._rgba = []; - - string = string.toLowerCase(); - - each( stringParsers, function( i, parser ) { - var parsed, - match = parser.re.exec( string ), - values = match && parser.parse( match ), - spaceName = parser.space || "rgba"; - - if ( values ) { - parsed = inst[ spaceName ]( values ); - - // if this was an rgba parse the assignment might happen twice - // oh well.... - inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; - rgba = inst._rgba = parsed._rgba; - - // exit each( stringParsers ) here because we matched - return false; - } - }); - - // Found a stringParser that handled it - if ( rgba.length ) { - - // if this came from a parsed string, force "transparent" when alpha is 0 - // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) - if ( rgba.join() === "0,0,0,0" ) { - jQuery.extend( rgba, colors.transparent ); - } - return inst; - } - - // named colors - return colors[ string ]; -} - -color.fn = jQuery.extend( color.prototype, { - parse: function( red, green, blue, alpha ) { - if ( red === undefined ) { - this._rgba = [ null, null, null, null ]; - return this; - } - if ( red.jquery || red.nodeType ) { - red = jQuery( red ).css( green ); - green = undefined; - } - - var inst = this, - type = jQuery.type( red ), - rgba = this._rgba = []; - - // more than 1 argument specified - assume ( red, green, blue, alpha ) - if ( green !== undefined ) { - red = [ red, green, blue, alpha ]; - type = "array"; - } - - if ( type === "string" ) { - return this.parse( stringParse( red ) || colors._default ); - } - - if ( type === "array" ) { - each( spaces.rgba.props, function( key, prop ) { - rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); - }); - return this; - } - - if ( type === "object" ) { - if ( red instanceof color ) { - each( spaces, function( spaceName, space ) { - if ( red[ space.cache ] ) { - inst[ space.cache ] = red[ space.cache ].slice(); - } - }); - } else { - each( spaces, function( spaceName, space ) { - var cache = space.cache; - each( space.props, function( key, prop ) { - - // if the cache doesn't exist, and we know how to convert - if ( !inst[ cache ] && space.to ) { - - // if the value was null, we don't need to copy it - // if the key was alpha, we don't need to copy it either - if ( key === "alpha" || red[ key ] == null ) { - return; - } - inst[ cache ] = space.to( inst._rgba ); - } - - // this is the only case where we allow nulls for ALL properties. - // call clamp with alwaysAllowEmpty - inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); - }); - - // everything defined but alpha? - if ( inst[ cache ] && $.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { - // use the default of 1 - inst[ cache ][ 3 ] = 1; - if ( space.from ) { - inst._rgba = space.from( inst[ cache ] ); - } - } - }); - } - return this; - } - }, - is: function( compare ) { - var is = color( compare ), - same = true, - inst = this; - - each( spaces, function( _, space ) { - var localCache, - isCache = is[ space.cache ]; - if (isCache) { - localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; - each( space.props, function( _, prop ) { - if ( isCache[ prop.idx ] != null ) { - same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); - return same; - } - }); - } - return same; - }); - return same; - }, - _space: function() { - var used = [], - inst = this; - each( spaces, function( spaceName, space ) { - if ( inst[ space.cache ] ) { - used.push( spaceName ); - } - }); - return used.pop(); - }, - transition: function( other, distance ) { - var end = color( other ), - spaceName = end._space(), - space = spaces[ spaceName ], - startColor = this.alpha() === 0 ? color( "transparent" ) : this, - start = startColor[ space.cache ] || space.to( startColor._rgba ), - result = start.slice(); - - end = end[ space.cache ]; - each( space.props, function( key, prop ) { - var index = prop.idx, - startValue = start[ index ], - endValue = end[ index ], - type = propTypes[ prop.type ] || {}; - - // if null, don't override start value - if ( endValue === null ) { - return; - } - // if null - use end - if ( startValue === null ) { - result[ index ] = endValue; - } else { - if ( type.mod ) { - if ( endValue - startValue > type.mod / 2 ) { - startValue += type.mod; - } else if ( startValue - endValue > type.mod / 2 ) { - startValue -= type.mod; - } - } - result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); - } - }); - return this[ spaceName ]( result ); - }, - blend: function( opaque ) { - // if we are already opaque - return ourself - if ( this._rgba[ 3 ] === 1 ) { - return this; - } - - var rgb = this._rgba.slice(), - a = rgb.pop(), - blend = color( opaque )._rgba; - - return color( jQuery.map( rgb, function( v, i ) { - return ( 1 - a ) * blend[ i ] + a * v; - })); - }, - toRgbaString: function() { - var prefix = "rgba(", - rgba = jQuery.map( this._rgba, function( v, i ) { - return v == null ? ( i > 2 ? 1 : 0 ) : v; - }); - - if ( rgba[ 3 ] === 1 ) { - rgba.pop(); - prefix = "rgb("; - } - - return prefix + rgba.join() + ")"; - }, - toHslaString: function() { - var prefix = "hsla(", - hsla = jQuery.map( this.hsla(), function( v, i ) { - if ( v == null ) { - v = i > 2 ? 1 : 0; - } - - // catch 1 and 2 - if ( i && i < 3 ) { - v = Math.round( v * 100 ) + "%"; - } - return v; - }); - - if ( hsla[ 3 ] === 1 ) { - hsla.pop(); - prefix = "hsl("; - } - return prefix + hsla.join() + ")"; - }, - toHexString: function( includeAlpha ) { - var rgba = this._rgba.slice(), - alpha = rgba.pop(); - - if ( includeAlpha ) { - rgba.push( ~~( alpha * 255 ) ); - } - - return "#" + jQuery.map( rgba, function( v ) { - - // default to 0 when nulls exist - v = ( v || 0 ).toString( 16 ); - return v.length === 1 ? "0" + v : v; - }).join(""); - }, - toString: function() { - return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); - } -}); -color.fn.parse.prototype = color.fn; - -// hsla conversions adapted from: -// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 - -function hue2rgb( p, q, h ) { - h = ( h + 1 ) % 1; - if ( h * 6 < 1 ) { - return p + (q - p) * h * 6; - } - if ( h * 2 < 1) { - return q; - } - if ( h * 3 < 2 ) { - return p + (q - p) * ((2/3) - h) * 6; - } - return p; -} - -spaces.hsla.to = function ( rgba ) { - if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { - return [ null, null, null, rgba[ 3 ] ]; - } - var r = rgba[ 0 ] / 255, - g = rgba[ 1 ] / 255, - b = rgba[ 2 ] / 255, - a = rgba[ 3 ], - max = Math.max( r, g, b ), - min = Math.min( r, g, b ), - diff = max - min, - add = max + min, - l = add * 0.5, - h, s; - - if ( min === max ) { - h = 0; - } else if ( r === max ) { - h = ( 60 * ( g - b ) / diff ) + 360; - } else if ( g === max ) { - h = ( 60 * ( b - r ) / diff ) + 120; - } else { - h = ( 60 * ( r - g ) / diff ) + 240; - } - - if ( l === 0 || l === 1 ) { - s = l; - } else if ( l <= 0.5 ) { - s = diff / add; - } else { - s = diff / ( 2 - add ); - } - return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; -}; - -spaces.hsla.from = function ( hsla ) { - if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { - return [ null, null, null, hsla[ 3 ] ]; - } - var h = hsla[ 0 ] / 360, - s = hsla[ 1 ], - l = hsla[ 2 ], - a = hsla[ 3 ], - q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, - p = 2 * l - q; - - return [ - Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), - Math.round( hue2rgb( p, q, h ) * 255 ), - Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), - a - ]; -}; - - -each( spaces, function( spaceName, space ) { - var props = space.props, - cache = space.cache, - to = space.to, - from = space.from; - - // makes rgba() and hsla() - color.fn[ spaceName ] = function( value ) { - - // generate a cache for this space if it doesn't exist - if ( to && !this[ cache ] ) { - this[ cache ] = to( this._rgba ); - } - if ( value === undefined ) { - return this[ cache ].slice(); - } - - var ret, - type = jQuery.type( value ), - arr = ( type === "array" || type === "object" ) ? value : arguments, - local = this[ cache ].slice(); - - each( props, function( key, prop ) { - var val = arr[ type === "object" ? key : prop.idx ]; - if ( val == null ) { - val = local[ prop.idx ]; - } - local[ prop.idx ] = clamp( val, prop ); - }); - - if ( from ) { - ret = color( from( local ) ); - ret[ cache ] = local; - return ret; - } else { - return color( local ); - } - }; - - // makes red() green() blue() alpha() hue() saturation() lightness() - each( props, function( key, prop ) { - // alpha is included in more than one space - if ( color.fn[ key ] ) { - return; - } - color.fn[ key ] = function( value ) { - var vtype = jQuery.type( value ), - fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), - local = this[ fn ](), - cur = local[ prop.idx ], - match; - - if ( vtype === "undefined" ) { - return cur; - } - - if ( vtype === "function" ) { - value = value.call( this, cur ); - vtype = jQuery.type( value ); - } - if ( value == null && prop.empty ) { - return this; - } - if ( vtype === "string" ) { - match = rplusequals.exec( value ); - if ( match ) { - value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); - } - } - local[ prop.idx ] = value; - return this[ fn ]( local ); - }; - }); -}); - -// add .fx.step functions -each( stepHooks, function( i, hook ) { - jQuery.cssHooks[ hook ] = { - set: function( elem, value ) { - var parsed, curElem, - backgroundColor = ""; - - if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) { - value = color( parsed || value ); - if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { - curElem = hook === "backgroundColor" ? elem.parentNode : elem; - while ( - (backgroundColor === "" || backgroundColor === "transparent") && - curElem && curElem.style - ) { - try { - backgroundColor = jQuery.css( curElem, "backgroundColor" ); - curElem = curElem.parentNode; - } catch ( e ) { - } - } - - value = value.blend( backgroundColor && backgroundColor !== "transparent" ? - backgroundColor : - "_default" ); - } - - value = value.toRgbaString(); - } - try { - elem.style[ hook ] = value; - } catch( error ) { - // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' - } - } - }; - jQuery.fx.step[ hook ] = function( fx ) { - if ( !fx.colorInit ) { - fx.start = color( fx.elem, hook ); - fx.end = color( fx.end ); - fx.colorInit = true; - } - jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); - }; -}); - -jQuery.cssHooks.borderColor = { - expand: function( value ) { - var expanded = {}; - - each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { - expanded[ "border" + part + "Color" ] = value; - }); - return expanded; - } -}; - -// Basic color names only. -// Usage of any of the other color names requires adding yourself or including -// jquery.color.svg-names.js. -colors = jQuery.Color.names = { - // 4.1. Basic color keywords - aqua: "#00ffff", - black: "#000000", - blue: "#0000ff", - fuchsia: "#ff00ff", - gray: "#808080", - green: "#008000", - lime: "#00ff00", - maroon: "#800000", - navy: "#000080", - olive: "#808000", - purple: "#800080", - red: "#ff0000", - silver: "#c0c0c0", - teal: "#008080", - white: "#ffffff", - yellow: "#ffff00", - - // 4.2.3. "transparent" color keyword - transparent: [ null, null, null, 0 ], - - _default: "#ffffff" -}; - -})( jQuery ); - - - -/******************************************************************************/ -/****************************** CLASS ANIMATIONS ******************************/ -/******************************************************************************/ -(function() { - -var classAnimationActions = [ "add", "remove", "toggle" ], - shorthandStyles = { - border: 1, - borderBottom: 1, - borderColor: 1, - borderLeft: 1, - borderRight: 1, - borderTop: 1, - borderWidth: 1, - margin: 1, - padding: 1 - }; - -$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { - $.fx.step[ prop ] = function( fx ) { - if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { - jQuery.style( fx.elem, prop, fx.end ); - fx.setAttr = true; - } - }; -}); - -function getElementStyles() { - var style = this.ownerDocument.defaultView ? - this.ownerDocument.defaultView.getComputedStyle( this, null ) : - this.currentStyle, - newStyle = {}, - key, - len; - - // webkit enumerates style porperties - if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { - len = style.length; - while ( len-- ) { - key = style[ len ]; - if ( typeof style[ key ] === "string" ) { - newStyle[ $.camelCase( key ) ] = style[ key ]; - } - } - } else { - for ( key in style ) { - if ( typeof style[ key ] === "string" ) { - newStyle[ key ] = style[ key ]; - } - } - } - - return newStyle; -} - - -function styleDifference( oldStyle, newStyle ) { - var diff = {}, - name, value; - - for ( name in newStyle ) { - value = newStyle[ name ]; - if ( oldStyle[ name ] !== value ) { - if ( !shorthandStyles[ name ] ) { - if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { - diff[ name ] = value; - } - } - } - } - - return diff; -} - -$.effects.animateClass = function( value, duration, easing, callback ) { - var o = $.speed( duration, easing, callback ); - - return this.queue( function() { - var animated = $( this ), - baseClass = animated.attr( "class" ) || "", - applyClassChange, - allAnimations = o.children ? animated.find( "*" ).andSelf() : animated; - - // map the animated objects to store the original styles. - allAnimations = allAnimations.map(function() { - var el = $( this ); - return { - el: el, - start: getElementStyles.call( this ) - }; - }); - - // apply class change - applyClassChange = function() { - $.each( classAnimationActions, function(i, action) { - if ( value[ action ] ) { - animated[ action + "Class" ]( value[ action ] ); - } - }); - }; - applyClassChange(); - - // map all animated objects again - calculate new styles and diff - allAnimations = allAnimations.map(function() { - this.end = getElementStyles.call( this.el[ 0 ] ); - this.diff = styleDifference( this.start, this.end ); - return this; - }); - - // apply original class - animated.attr( "class", baseClass ); - - // map all animated objects again - this time collecting a promise - allAnimations = allAnimations.map(function() { - var styleInfo = this, - dfd = $.Deferred(), - opts = jQuery.extend({}, o, { - queue: false, - complete: function() { - dfd.resolve( styleInfo ); - } - }); - - this.el.animate( this.diff, opts ); - return dfd.promise(); - }); - - // once all animations have completed: - $.when.apply( $, allAnimations.get() ).done(function() { - - // set the final class - applyClassChange(); - - // for each animated element, - // clear all css properties that were animated - $.each( arguments, function() { - var el = this.el; - $.each( this.diff, function(key) { - el.css( key, '' ); - }); - }); - - // this is guarnteed to be there if you use jQuery.speed() - // it also handles dequeuing the next anim... - o.complete.call( animated[ 0 ] ); - }); - }); -}; - -$.fn.extend({ - _addClass: $.fn.addClass, - addClass: function( classNames, speed, easing, callback ) { - return speed ? - $.effects.animateClass.call( this, - { add: classNames }, speed, easing, callback ) : - this._addClass( classNames ); - }, - - _removeClass: $.fn.removeClass, - removeClass: function( classNames, speed, easing, callback ) { - return speed ? - $.effects.animateClass.call( this, - { remove: classNames }, speed, easing, callback ) : - this._removeClass( classNames ); - }, - - _toggleClass: $.fn.toggleClass, - toggleClass: function( classNames, force, speed, easing, callback ) { - if ( typeof force === "boolean" || force === undefined ) { - if ( !speed ) { - // without speed parameter - return this._toggleClass( classNames, force ); - } else { - return $.effects.animateClass.call( this, - (force ? { add: classNames } : { remove: classNames }), - speed, easing, callback ); - } - } else { - // without force parameter - return $.effects.animateClass.call( this, - { toggle: classNames }, force, speed, easing ); - } - }, - - switchClass: function( remove, add, speed, easing, callback) { - return $.effects.animateClass.call( this, { - add: add, - remove: remove - }, speed, easing, callback ); - } -}); - -})(); - -/******************************************************************************/ -/*********************************** EFFECTS **********************************/ -/******************************************************************************/ - -(function() { - -$.extend( $.effects, { - version: "1.9.2", - - // Saves a set of properties in a data storage - save: function( element, set ) { - for( var i=0; i < set.length; i++ ) { - if ( set[ i ] !== null ) { - element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); - } - } - }, - - // Restores a set of previously saved properties from a data storage - restore: function( element, set ) { - var val, i; - for( i=0; i < set.length; i++ ) { - if ( set[ i ] !== null ) { - val = element.data( dataSpace + set[ i ] ); - // support: jQuery 1.6.2 - // http://bugs.jquery.com/ticket/9917 - // jQuery 1.6.2 incorrectly returns undefined for any falsy value. - // We can't differentiate between "" and 0 here, so we just assume - // empty string since it's likely to be a more common value... - if ( val === undefined ) { - val = ""; - } - element.css( set[ i ], val ); - } - } - }, - - setMode: function( el, mode ) { - if (mode === "toggle") { - mode = el.is( ":hidden" ) ? "show" : "hide"; - } - return mode; - }, - - // Translates a [top,left] array into a baseline value - // this should be a little more flexible in the future to handle a string & hash - getBaseline: function( origin, original ) { - var y, x; - switch ( origin[ 0 ] ) { - case "top": y = 0; break; - case "middle": y = 0.5; break; - case "bottom": y = 1; break; - default: y = origin[ 0 ] / original.height; - } - switch ( origin[ 1 ] ) { - case "left": x = 0; break; - case "center": x = 0.5; break; - case "right": x = 1; break; - default: x = origin[ 1 ] / original.width; - } - return { - x: x, - y: y - }; - }, - - // Wraps the element around a wrapper that copies position properties - createWrapper: function( element ) { - - // if the element is already wrapped, return it - if ( element.parent().is( ".ui-effects-wrapper" )) { - return element.parent(); - } - - // wrap the element - var props = { - width: element.outerWidth(true), - height: element.outerHeight(true), - "float": element.css( "float" ) - }, - wrapper = $( "<div></div>" ) - .addClass( "ui-effects-wrapper" ) - .css({ - fontSize: "100%", - background: "transparent", - border: "none", - margin: 0, - padding: 0 - }), - // Store the size in case width/height are defined in % - Fixes #5245 - size = { - width: element.width(), - height: element.height() - }, - active = document.activeElement; - - // support: Firefox - // Firefox incorrectly exposes anonymous content - // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 - try { - active.id; - } catch( e ) { - active = document.body; - } - - element.wrap( wrapper ); - - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - - wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element - - // transfer positioning properties to the wrapper - if ( element.css( "position" ) === "static" ) { - wrapper.css({ position: "relative" }); - element.css({ position: "relative" }); - } else { - $.extend( props, { - position: element.css( "position" ), - zIndex: element.css( "z-index" ) - }); - $.each([ "top", "left", "bottom", "right" ], function(i, pos) { - props[ pos ] = element.css( pos ); - if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { - props[ pos ] = "auto"; - } - }); - element.css({ - position: "relative", - top: 0, - left: 0, - right: "auto", - bottom: "auto" - }); - } - element.css(size); - - return wrapper.css( props ).show(); - }, - - removeWrapper: function( element ) { - var active = document.activeElement; - - if ( element.parent().is( ".ui-effects-wrapper" ) ) { - element.parent().replaceWith( element ); - - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - } - - - return element; - }, - - setTransition: function( element, list, factor, value ) { - value = value || {}; - $.each( list, function( i, x ) { - var unit = element.cssUnit( x ); - if ( unit[ 0 ] > 0 ) { - value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; - } - }); - return value; - } -}); - -// return an effect options object for the given parameters: -function _normalizeArguments( effect, options, speed, callback ) { - - // allow passing all options as the first parameter - if ( $.isPlainObject( effect ) ) { - options = effect; - effect = effect.effect; - } - - // convert to an object - effect = { effect: effect }; - - // catch (effect, null, ...) - if ( options == null ) { - options = {}; - } - - // catch (effect, callback) - if ( $.isFunction( options ) ) { - callback = options; - speed = null; - options = {}; - } - - // catch (effect, speed, ?) - if ( typeof options === "number" || $.fx.speeds[ options ] ) { - callback = speed; - speed = options; - options = {}; - } - - // catch (effect, options, callback) - if ( $.isFunction( speed ) ) { - callback = speed; - speed = null; - } - - // add options to effect - if ( options ) { - $.extend( effect, options ); - } - - speed = speed || options.duration; - effect.duration = $.fx.off ? 0 : - typeof speed === "number" ? speed : - speed in $.fx.speeds ? $.fx.speeds[ speed ] : - $.fx.speeds._default; - - effect.complete = callback || options.complete; - - return effect; -} - -function standardSpeed( speed ) { - // valid standard speeds - if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) { - return true; - } - - // invalid strings - treat as "normal" speed - if ( typeof speed === "string" && !$.effects.effect[ speed ] ) { - // TODO: remove in 2.0 (#7115) - if ( backCompat && $.effects[ speed ] ) { - return false; - } - return true; - } - - return false; -} - -$.fn.extend({ - effect: function( /* effect, options, speed, callback */ ) { - var args = _normalizeArguments.apply( this, arguments ), - mode = args.mode, - queue = args.queue, - effectMethod = $.effects.effect[ args.effect ], - - // DEPRECATED: remove in 2.0 (#7115) - oldEffectMethod = !effectMethod && backCompat && $.effects[ args.effect ]; - - if ( $.fx.off || !( effectMethod || oldEffectMethod ) ) { - // delegate to the original method (e.g., .show()) if possible - if ( mode ) { - return this[ mode ]( args.duration, args.complete ); - } else { - return this.each( function() { - if ( args.complete ) { - args.complete.call( this ); - } - }); - } - } - - function run( next ) { - var elem = $( this ), - complete = args.complete, - mode = args.mode; - - function done() { - if ( $.isFunction( complete ) ) { - complete.call( elem[0] ); - } - if ( $.isFunction( next ) ) { - next(); - } - } - - // if the element is hiddden and mode is hide, - // or element is visible and mode is show - if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { - done(); - } else { - effectMethod.call( elem[0], args, done ); - } - } - - // TODO: remove this check in 2.0, effectMethod will always be true - if ( effectMethod ) { - return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); - } else { - // DEPRECATED: remove in 2.0 (#7115) - return oldEffectMethod.call(this, { - options: args, - duration: args.duration, - callback: args.complete, - mode: args.mode - }); - } - }, - - _show: $.fn.show, - show: function( speed ) { - if ( standardSpeed( speed ) ) { - return this._show.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "show"; - return this.effect.call( this, args ); - } - }, - - _hide: $.fn.hide, - hide: function( speed ) { - if ( standardSpeed( speed ) ) { - return this._hide.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "hide"; - return this.effect.call( this, args ); - } - }, - - // jQuery core overloads toggle and creates _toggle - __toggle: $.fn.toggle, - toggle: function( speed ) { - if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) { - return this.__toggle.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "toggle"; - return this.effect.call( this, args ); - } - }, - - // helper functions - cssUnit: function(key) { - var style = this.css( key ), - val = []; - - $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { - if ( style.indexOf( unit ) > 0 ) { - val = [ parseFloat( style ), unit ]; - } - }); - return val; - } -}); - -})(); - -/******************************************************************************/ -/*********************************** EASING ***********************************/ -/******************************************************************************/ - -(function() { - -// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) - -var baseEasings = {}; - -$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { - baseEasings[ name ] = function( p ) { - return Math.pow( p, i + 2 ); - }; -}); - -$.extend( baseEasings, { - Sine: function ( p ) { - return 1 - Math.cos( p * Math.PI / 2 ); - }, - Circ: function ( p ) { - return 1 - Math.sqrt( 1 - p * p ); - }, - Elastic: function( p ) { - return p === 0 || p === 1 ? p : - -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); - }, - Back: function( p ) { - return p * p * ( 3 * p - 2 ); - }, - Bounce: function ( p ) { - var pow2, - bounce = 4; - - while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} - return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); - } -}); - -$.each( baseEasings, function( name, easeIn ) { - $.easing[ "easeIn" + name ] = easeIn; - $.easing[ "easeOut" + name ] = function( p ) { - return 1 - easeIn( 1 - p ); - }; - $.easing[ "easeInOut" + name ] = function( p ) { - return p < 0.5 ? - easeIn( p * 2 ) / 2 : - 1 - easeIn( p * -2 + 2 ) / 2; - }; -}); - -})(); - -})(jQuery)); - -(function( $, undefined ) { - -var uid = 0, - hideProps = {}, - showProps = {}; - -hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = - hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; -showProps.height = showProps.paddingTop = showProps.paddingBottom = - showProps.borderTopWidth = showProps.borderBottomWidth = "show"; - -$.widget( "ui.accordion", { - version: "1.9.2", - options: { - active: 0, - animate: {}, - collapsible: false, - event: "click", - header: "> li > :first-child,> :not(li):even", - heightStyle: "auto", - icons: { - activeHeader: "ui-icon-triangle-1-s", - header: "ui-icon-triangle-1-e" - }, - - // callbacks - activate: null, - beforeActivate: null - }, - - _create: function() { - var accordionId = this.accordionId = "ui-accordion-" + - (this.element.attr( "id" ) || ++uid), - options = this.options; - - this.prevShow = this.prevHide = $(); - this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ); - - this.headers = this.element.find( options.header ) - .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); - this._hoverable( this.headers ); - this._focusable( this.headers ); - - this.headers.next() - .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) - .hide(); - - // don't allow collapsible: false and active: false / null - if ( !options.collapsible && (options.active === false || options.active == null) ) { - options.active = 0; - } - // handle negative values - if ( options.active < 0 ) { - options.active += this.headers.length; - } - this.active = this._findActive( options.active ) - .addClass( "ui-accordion-header-active ui-state-active" ) - .toggleClass( "ui-corner-all ui-corner-top" ); - this.active.next() - .addClass( "ui-accordion-content-active" ) - .show(); - - this._createIcons(); - this.refresh(); - - // ARIA - this.element.attr( "role", "tablist" ); - - this.headers - .attr( "role", "tab" ) - .each(function( i ) { - var header = $( this ), - headerId = header.attr( "id" ), - panel = header.next(), - panelId = panel.attr( "id" ); - if ( !headerId ) { - headerId = accordionId + "-header-" + i; - header.attr( "id", headerId ); - } - if ( !panelId ) { - panelId = accordionId + "-panel-" + i; - panel.attr( "id", panelId ); - } - header.attr( "aria-controls", panelId ); - panel.attr( "aria-labelledby", headerId ); - }) - .next() - .attr( "role", "tabpanel" ); - - this.headers - .not( this.active ) - .attr({ - "aria-selected": "false", - tabIndex: -1 - }) - .next() - .attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }) - .hide(); - - // make sure at least one header is in the tab order - if ( !this.active.length ) { - this.headers.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active.attr({ - "aria-selected": "true", - tabIndex: 0 - }) - .next() - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - } - - this._on( this.headers, { keydown: "_keydown" }); - this._on( this.headers.next(), { keydown: "_panelKeyDown" }); - this._setupEvents( options.event ); - }, - - _getCreateEventData: function() { - return { - header: this.active, - content: !this.active.length ? $() : this.active.next() - }; - }, - - _createIcons: function() { - var icons = this.options.icons; - if ( icons ) { - $( "<span>" ) - .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) - .prependTo( this.headers ); - this.active.children( ".ui-accordion-header-icon" ) - .removeClass( icons.header ) - .addClass( icons.activeHeader ); - this.headers.addClass( "ui-accordion-icons" ); - } - }, - - _destroyIcons: function() { - this.headers - .removeClass( "ui-accordion-icons" ) - .children( ".ui-accordion-header-icon" ) - .remove(); - }, - - _destroy: function() { - var contents; - - // clean up main element - this.element - .removeClass( "ui-accordion ui-widget ui-helper-reset" ) - .removeAttr( "role" ); - - // clean up headers - this.headers - .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) - .removeAttr( "role" ) - .removeAttr( "aria-selected" ) - .removeAttr( "aria-controls" ) - .removeAttr( "tabIndex" ) - .each(function() { - if ( /^ui-accordion/.test( this.id ) ) { - this.removeAttribute( "id" ); - } - }); - this._destroyIcons(); - - // clean up content panels - contents = this.headers.next() - .css( "display", "" ) - .removeAttr( "role" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-labelledby" ) - .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) - .each(function() { - if ( /^ui-accordion/.test( this.id ) ) { - this.removeAttribute( "id" ); - } - }); - if ( this.options.heightStyle !== "content" ) { - contents.css( "height", "" ); - } - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - if ( key === "event" ) { - if ( this.options.event ) { - this._off( this.headers, this.options.event ); - } - this._setupEvents( value ); - } - - this._super( key, value ); - - // setting collapsible: false while collapsed; open first panel - if ( key === "collapsible" && !value && this.options.active === false ) { - this._activate( 0 ); - } - - if ( key === "icons" ) { - this._destroyIcons(); - if ( value ) { - this._createIcons(); - } - } - - // #5332 - opacity doesn't cascade to positioned elements in IE - // so we need to add the disabled class to the headers and panels - if ( key === "disabled" ) { - this.headers.add( this.headers.next() ) - .toggleClass( "ui-state-disabled", !!value ); - } - }, - - _keydown: function( event ) { - if ( event.altKey || event.ctrlKey ) { - return; - } - - var keyCode = $.ui.keyCode, - length = this.headers.length, - currentIndex = this.headers.index( event.target ), - toFocus = false; - - switch ( event.keyCode ) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.headers[ ( currentIndex + 1 ) % length ]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - this._eventHandler( event ); - break; - case keyCode.HOME: - toFocus = this.headers[ 0 ]; - break; - case keyCode.END: - toFocus = this.headers[ length - 1 ]; - break; - } - - if ( toFocus ) { - $( event.target ).attr( "tabIndex", -1 ); - $( toFocus ).attr( "tabIndex", 0 ); - toFocus.focus(); - event.preventDefault(); - } - }, - - _panelKeyDown : function( event ) { - if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { - $( event.currentTarget ).prev().focus(); - } - }, - - refresh: function() { - var maxHeight, overflow, - heightStyle = this.options.heightStyle, - parent = this.element.parent(); - - - if ( heightStyle === "fill" ) { - // IE 6 treats height like minHeight, so we need to turn off overflow - // in order to get a reliable height - // we use the minHeight support test because we assume that only - // browsers that don't support minHeight will treat height as minHeight - if ( !$.support.minHeight ) { - overflow = parent.css( "overflow" ); - parent.css( "overflow", "hidden"); - } - maxHeight = parent.height(); - this.element.siblings( ":visible" ).each(function() { - var elem = $( this ), - position = elem.css( "position" ); - - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - }); - if ( overflow ) { - parent.css( "overflow", overflow ); - } - - this.headers.each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.headers.next() - .each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.headers.next() - .each(function() { - maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); - }) - .height( maxHeight ); - } - }, - - _activate: function( index ) { - var active = this._findActive( index )[ 0 ]; - - // trying to activate the already active panel - if ( active === this.active[ 0 ] ) { - return; - } - - // trying to collapse, simulate a click on the currently active header - active = active || this.active[ 0 ]; - - this._eventHandler({ - target: active, - currentTarget: active, - preventDefault: $.noop - }); - }, - - _findActive: function( selector ) { - return typeof selector === "number" ? this.headers.eq( selector ) : $(); - }, - - _setupEvents: function( event ) { - var events = {}; - if ( !event ) { - return; - } - $.each( event.split(" "), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - }); - this._on( this.headers, events ); - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - clicked = $( event.currentTarget ), - clickedIsActive = clicked[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : clicked.next(), - toHide = active.next(), - eventData = { - oldHeader: active, - oldPanel: toHide, - newHeader: collapsing ? $() : clicked, - newPanel: toShow - }; - - event.preventDefault(); - - if ( - // click on active header, but not collapsible - ( clickedIsActive && !options.collapsible ) || - // allow canceling activation - ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { - return; - } - - options.active = collapsing ? false : this.headers.index( clicked ); - - // when the call to ._toggle() comes after the class changes - // it causes a very odd bug in IE 8 (see #6720) - this.active = clickedIsActive ? $() : clicked; - this._toggle( eventData ); - - // switch classes - // corner classes on the previously active header stay after the animation - active.removeClass( "ui-accordion-header-active ui-state-active" ); - if ( options.icons ) { - active.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.activeHeader ) - .addClass( options.icons.header ); - } - - if ( !clickedIsActive ) { - clicked - .removeClass( "ui-corner-all" ) - .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); - if ( options.icons ) { - clicked.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.header ) - .addClass( options.icons.activeHeader ); - } - - clicked - .next() - .addClass( "ui-accordion-content-active" ); - } - }, - - _toggle: function( data ) { - var toShow = data.newPanel, - toHide = this.prevShow.length ? this.prevShow : data.oldPanel; - - // handle activating a panel during the animation for another activation - this.prevShow.add( this.prevHide ).stop( true, true ); - this.prevShow = toShow; - this.prevHide = toHide; - - if ( this.options.animate ) { - this._animate( toShow, toHide, data ); - } else { - toHide.hide(); - toShow.show(); - this._toggleComplete( data ); - } - - toHide.attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - toHide.prev().attr( "aria-selected", "false" ); - // if we're switching panels, remove the old header from the tab order - // if we're opening from collapsed state, remove the previous header from the tab order - // if we're collapsing, then keep the collapsing header in the tab order - if ( toShow.length && toHide.length ) { - toHide.prev().attr( "tabIndex", -1 ); - } else if ( toShow.length ) { - this.headers.filter(function() { - return $( this ).attr( "tabIndex" ) === 0; - }) - .attr( "tabIndex", -1 ); - } - - toShow - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }) - .prev() - .attr({ - "aria-selected": "true", - tabIndex: 0 - }); - }, - - _animate: function( toShow, toHide, data ) { - var total, easing, duration, - that = this, - adjust = 0, - down = toShow.length && - ( !toHide.length || ( toShow.index() < toHide.index() ) ), - animate = this.options.animate || {}, - options = down && animate.down || animate, - complete = function() { - that._toggleComplete( data ); - }; - - if ( typeof options === "number" ) { - duration = options; - } - if ( typeof options === "string" ) { - easing = options; - } - // fall back from options to animation in case of partial down settings - easing = easing || options.easing || animate.easing; - duration = duration || options.duration || animate.duration; - - if ( !toHide.length ) { - return toShow.animate( showProps, duration, easing, complete ); - } - if ( !toShow.length ) { - return toHide.animate( hideProps, duration, easing, complete ); - } - - total = toShow.show().outerHeight(); - toHide.animate( hideProps, { - duration: duration, - easing: easing, - step: function( now, fx ) { - fx.now = Math.round( now ); - } - }); - toShow - .hide() - .animate( showProps, { - duration: duration, - easing: easing, - complete: complete, - step: function( now, fx ) { - fx.now = Math.round( now ); - if ( fx.prop !== "height" ) { - adjust += fx.now; - } else if ( that.options.heightStyle !== "content" ) { - fx.now = Math.round( total - toHide.outerHeight() - adjust ); - adjust = 0; - } - } - }); - }, - - _toggleComplete: function( data ) { - var toHide = data.oldPanel; - - toHide - .removeClass( "ui-accordion-content-active" ) - .prev() - .removeClass( "ui-corner-top" ) - .addClass( "ui-corner-all" ); - - // Work around for rendering bug in IE (#5421) - if ( toHide.length ) { - toHide.parent()[0].className = toHide.parent()[0].className; - } - - this._trigger( "activate", null, data ); - } -}); - - - -// DEPRECATED -if ( $.uiBackCompat !== false ) { - // navigation options - (function( $, prototype ) { - $.extend( prototype.options, { - navigation: false, - navigationFilter: function() { - return this.href.toLowerCase() === location.href.toLowerCase(); - } - }); - - var _create = prototype._create; - prototype._create = function() { - if ( this.options.navigation ) { - var that = this, - headers = this.element.find( this.options.header ), - content = headers.next(), - current = headers.add( content ) - .find( "a" ) - .filter( this.options.navigationFilter ) - [ 0 ]; - if ( current ) { - headers.add( content ).each( function( index ) { - if ( $.contains( this, current ) ) { - that.options.active = Math.floor( index / 2 ); - return false; - } - }); - } - } - _create.call( this ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // height options - (function( $, prototype ) { - $.extend( prototype.options, { - heightStyle: null, // remove default so we fall back to old values - autoHeight: true, // use heightStyle: "auto" - clearStyle: false, // use heightStyle: "content" - fillSpace: false // use heightStyle: "fill" - }); - - var _create = prototype._create, - _setOption = prototype._setOption; - - $.extend( prototype, { - _create: function() { - this.options.heightStyle = this.options.heightStyle || - this._mergeHeightStyle(); - - _create.call( this ); - }, - - _setOption: function( key ) { - if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) { - this.options.heightStyle = this._mergeHeightStyle(); - } - _setOption.apply( this, arguments ); - }, - - _mergeHeightStyle: function() { - var options = this.options; - - if ( options.fillSpace ) { - return "fill"; - } - - if ( options.clearStyle ) { - return "content"; - } - - if ( options.autoHeight ) { - return "auto"; - } - } - }); - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // icon options - (function( $, prototype ) { - $.extend( prototype.options.icons, { - activeHeader: null, // remove default so we fall back to old values - headerSelected: "ui-icon-triangle-1-s" - }); - - var _createIcons = prototype._createIcons; - prototype._createIcons = function() { - if ( this.options.icons ) { - this.options.icons.activeHeader = this.options.icons.activeHeader || - this.options.icons.headerSelected; - } - _createIcons.call( this ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // expanded active option, activate method - (function( $, prototype ) { - prototype.activate = prototype._activate; - - var _findActive = prototype._findActive; - prototype._findActive = function( index ) { - if ( index === -1 ) { - index = false; - } - if ( index && typeof index !== "number" ) { - index = this.headers.index( this.headers.filter( index ) ); - if ( index === -1 ) { - index = false; - } - } - return _findActive.call( this, index ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // resize method - jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh; - - // change events - (function( $, prototype ) { - $.extend( prototype.options, { - change: null, - changestart: null - }); - - var _trigger = prototype._trigger; - prototype._trigger = function( type, event, data ) { - var ret = _trigger.apply( this, arguments ); - if ( !ret ) { - return false; - } - - if ( type === "beforeActivate" ) { - ret = _trigger.call( this, "changestart", event, { - oldHeader: data.oldHeader, - oldContent: data.oldPanel, - newHeader: data.newHeader, - newContent: data.newPanel - }); - } else if ( type === "activate" ) { - ret = _trigger.call( this, "change", event, { - oldHeader: data.oldHeader, - oldContent: data.oldPanel, - newHeader: data.newHeader, - newContent: data.newPanel - }); - } - return ret; - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); - - // animated option - // NOTE: this only provides support for "slide", "bounceslide", and easings - // not the full $.ui.accordion.animations API - (function( $, prototype ) { - $.extend( prototype.options, { - animate: null, - animated: "slide" - }); - - var _create = prototype._create; - prototype._create = function() { - var options = this.options; - if ( options.animate === null ) { - if ( !options.animated ) { - options.animate = false; - } else if ( options.animated === "slide" ) { - options.animate = 300; - } else if ( options.animated === "bounceslide" ) { - options.animate = { - duration: 200, - down: { - easing: "easeOutBounce", - duration: 1000 - } - }; - } else { - options.animate = options.animated; - } - } - - _create.call( this ); - }; - }( jQuery, jQuery.ui.accordion.prototype ) ); -} - -})( jQuery ); - -(function( $, undefined ) { - -// used to prevent race conditions with remote data sources -var requestIndex = 0; - -$.widget( "ui.autocomplete", { - version: "1.9.2", - defaultElement: "<input>", - options: { - appendTo: "body", - autoFocus: false, - delay: 300, - minLength: 1, - position: { - my: "left top", - at: "left bottom", - collision: "none" - }, - source: null, - - // callbacks - change: null, - close: null, - focus: null, - open: null, - response: null, - search: null, - select: null - }, - - pending: 0, - - _create: function() { - // Some browsers only repeat keydown events, not keypress events, - // so we use the suppressKeyPress flag to determine if we've already - // handled the keydown event. #7269 - // Unfortunately the code for & in keypress is the same as the up arrow, - // so we use the suppressKeyPressRepeat flag to avoid handling keypress - // events when we know the keydown event was used to modify the - // search term. #7799 - var suppressKeyPress, suppressKeyPressRepeat, suppressInput; - - this.isMultiLine = this._isMultiLine(); - this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ]; - this.isNewMenu = true; - - this.element - .addClass( "ui-autocomplete-input" ) - .attr( "autocomplete", "off" ); - - this._on( this.element, { - keydown: function( event ) { - if ( this.element.prop( "readOnly" ) ) { - suppressKeyPress = true; - suppressInput = true; - suppressKeyPressRepeat = true; - return; - } - - suppressKeyPress = false; - suppressInput = false; - suppressKeyPressRepeat = false; - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - suppressKeyPress = true; - this._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - suppressKeyPress = true; - this._move( "nextPage", event ); - break; - case keyCode.UP: - suppressKeyPress = true; - this._keyEvent( "previous", event ); - break; - case keyCode.DOWN: - suppressKeyPress = true; - this._keyEvent( "next", event ); - break; - case keyCode.ENTER: - case keyCode.NUMPAD_ENTER: - // when menu is open and has focus - if ( this.menu.active ) { - // #6055 - Opera still allows the keypress to occur - // which causes forms to submit - suppressKeyPress = true; - event.preventDefault(); - this.menu.select( event ); - } - break; - case keyCode.TAB: - if ( this.menu.active ) { - this.menu.select( event ); - } - break; - case keyCode.ESCAPE: - if ( this.menu.element.is( ":visible" ) ) { - this._value( this.term ); - this.close( event ); - // Different browsers have different default behavior for escape - // Single press can mean undo or clear - // Double press in IE means clear the whole form - event.preventDefault(); - } - break; - default: - suppressKeyPressRepeat = true; - // search timeout should be triggered before the input value is changed - this._searchTimeout( event ); - break; - } - }, - keypress: function( event ) { - if ( suppressKeyPress ) { - suppressKeyPress = false; - event.preventDefault(); - return; - } - if ( suppressKeyPressRepeat ) { - return; - } - - // replicate some key handlers to allow them to repeat in Firefox and Opera - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - this._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - this._move( "nextPage", event ); - break; - case keyCode.UP: - this._keyEvent( "previous", event ); - break; - case keyCode.DOWN: - this._keyEvent( "next", event ); - break; - } - }, - input: function( event ) { - if ( suppressInput ) { - suppressInput = false; - event.preventDefault(); - return; - } - this._searchTimeout( event ); - }, - focus: function() { - this.selectedItem = null; - this.previous = this._value(); - }, - blur: function( event ) { - if ( this.cancelBlur ) { - delete this.cancelBlur; - return; - } - - clearTimeout( this.searching ); - this.close( event ); - this._change( event ); - } - }); - - this._initSource(); - this.menu = $( "<ul>" ) - .addClass( "ui-autocomplete" ) - .appendTo( this.document.find( this.options.appendTo || "body" )[ 0 ] ) - .menu({ - // custom key handling for now - input: $(), - // disable ARIA support, the live region takes care of that - role: null - }) - .zIndex( this.element.zIndex() + 1 ) - .hide() - .data( "menu" ); - - this._on( this.menu.element, { - mousedown: function( event ) { - // prevent moving focus out of the text field - event.preventDefault(); - - // IE doesn't prevent moving focus even with event.preventDefault() - // so we set a flag to know when we should ignore the blur event - this.cancelBlur = true; - this._delay(function() { - delete this.cancelBlur; - }); - - // clicking on the scrollbar causes focus to shift to the body - // but we can't detect a mouseup or a click immediately afterward - // so we have to track the next mousedown and close the menu if - // the user clicks somewhere outside of the autocomplete - var menuElement = this.menu.element[ 0 ]; - if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { - this._delay(function() { - var that = this; - this.document.one( "mousedown", function( event ) { - if ( event.target !== that.element[ 0 ] && - event.target !== menuElement && - !$.contains( menuElement, event.target ) ) { - that.close(); - } - }); - }); - } - }, - menufocus: function( event, ui ) { - // #7024 - Prevent accidental activation of menu items in Firefox - if ( this.isNewMenu ) { - this.isNewMenu = false; - if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { - this.menu.blur(); - - this.document.one( "mousemove", function() { - $( event.target ).trigger( event.originalEvent ); - }); - - return; - } - } - - // back compat for _renderItem using item.autocomplete, via #7810 - // TODO remove the fallback, see #8156 - var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ); - if ( false !== this._trigger( "focus", event, { item: item } ) ) { - // use value to match what will end up in the input, if it was a key event - if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { - this._value( item.value ); - } - } else { - // Normally the input is populated with the item's value as the - // menu is navigated, causing screen readers to notice a change and - // announce the item. Since the focus event was canceled, this doesn't - // happen, so we update the live region so that screen readers can - // still notice the change and announce it. - this.liveRegion.text( item.value ); - } - }, - menuselect: function( event, ui ) { - // back compat for _renderItem using item.autocomplete, via #7810 - // TODO remove the fallback, see #8156 - var item = ui.item.data( "ui-autocomplete-item" ) || ui.item.data( "item.autocomplete" ), - previous = this.previous; - - // only trigger when focus was lost (click on menu) - if ( this.element[0] !== this.document[0].activeElement ) { - this.element.focus(); - this.previous = previous; - // #6109 - IE triggers two focus events and the second - // is asynchronous, so we need to reset the previous - // term synchronously and asynchronously :-( - this._delay(function() { - this.previous = previous; - this.selectedItem = item; - }); - } - - if ( false !== this._trigger( "select", event, { item: item } ) ) { - this._value( item.value ); - } - // reset the term after the select event - // this allows custom select handling to work properly - this.term = this._value(); - - this.close( event ); - this.selectedItem = item; - } - }); - - this.liveRegion = $( "<span>", { - role: "status", - "aria-live": "polite" - }) - .addClass( "ui-helper-hidden-accessible" ) - .insertAfter( this.element ); - - if ( $.fn.bgiframe ) { - this.menu.element.bgiframe(); - } - - // turning off autocomplete prevents the browser from remembering the - // value when navigating through history, so we re-enable autocomplete - // if the page is unloaded before the widget is destroyed. #7790 - this._on( this.window, { - beforeunload: function() { - this.element.removeAttr( "autocomplete" ); - } - }); - }, - - _destroy: function() { - clearTimeout( this.searching ); - this.element - .removeClass( "ui-autocomplete-input" ) - .removeAttr( "autocomplete" ); - this.menu.element.remove(); - this.liveRegion.remove(); - }, - - _setOption: function( key, value ) { - this._super( key, value ); - if ( key === "source" ) { - this._initSource(); - } - if ( key === "appendTo" ) { - this.menu.element.appendTo( this.document.find( value || "body" )[0] ); - } - if ( key === "disabled" && value && this.xhr ) { - this.xhr.abort(); - } - }, - - _isMultiLine: function() { - // Textareas are always multi-line - if ( this.element.is( "textarea" ) ) { - return true; - } - // Inputs are always single-line, even if inside a contentEditable element - // IE also treats inputs as contentEditable - if ( this.element.is( "input" ) ) { - return false; - } - // All other element types are determined by whether or not they're contentEditable - return this.element.prop( "isContentEditable" ); - }, - - _initSource: function() { - var array, url, - that = this; - if ( $.isArray(this.options.source) ) { - array = this.options.source; - this.source = function( request, response ) { - response( $.ui.autocomplete.filter( array, request.term ) ); - }; - } else if ( typeof this.options.source === "string" ) { - url = this.options.source; - this.source = function( request, response ) { - if ( that.xhr ) { - that.xhr.abort(); - } - that.xhr = $.ajax({ - url: url, - data: request, - dataType: "json", - success: function( data ) { - response( data ); - }, - error: function() { - response( [] ); - } - }); - }; - } else { - this.source = this.options.source; - } - }, - - _searchTimeout: function( event ) { - clearTimeout( this.searching ); - this.searching = this._delay(function() { - // only search if the value has changed - if ( this.term !== this._value() ) { - this.selectedItem = null; - this.search( null, event ); - } - }, this.options.delay ); - }, - - search: function( value, event ) { - value = value != null ? value : this._value(); - - // always save the actual value, not the one passed as an argument - this.term = this._value(); - - if ( value.length < this.options.minLength ) { - return this.close( event ); - } - - if ( this._trigger( "search", event ) === false ) { - return; - } - - return this._search( value ); - }, - - _search: function( value ) { - this.pending++; - this.element.addClass( "ui-autocomplete-loading" ); - this.cancelSearch = false; - - this.source( { term: value }, this._response() ); - }, - - _response: function() { - var that = this, - index = ++requestIndex; - - return function( content ) { - if ( index === requestIndex ) { - that.__response( content ); - } - - that.pending--; - if ( !that.pending ) { - that.element.removeClass( "ui-autocomplete-loading" ); - } - }; - }, - - __response: function( content ) { - if ( content ) { - content = this._normalize( content ); - } - this._trigger( "response", null, { content: content } ); - if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { - this._suggest( content ); - this._trigger( "open" ); - } else { - // use ._close() instead of .close() so we don't cancel future searches - this._close(); - } - }, - - close: function( event ) { - this.cancelSearch = true; - this._close( event ); - }, - - _close: function( event ) { - if ( this.menu.element.is( ":visible" ) ) { - this.menu.element.hide(); - this.menu.blur(); - this.isNewMenu = true; - this._trigger( "close", event ); - } - }, - - _change: function( event ) { - if ( this.previous !== this._value() ) { - this._trigger( "change", event, { item: this.selectedItem } ); - } - }, - - _normalize: function( items ) { - // assume all items have the right format when the first item is complete - if ( items.length && items[0].label && items[0].value ) { - return items; - } - return $.map( items, function( item ) { - if ( typeof item === "string" ) { - return { - label: item, - value: item - }; - } - return $.extend({ - label: item.label || item.value, - value: item.value || item.label - }, item ); - }); - }, - - _suggest: function( items ) { - var ul = this.menu.element - .empty() - .zIndex( this.element.zIndex() + 1 ); - this._renderMenu( ul, items ); - this.menu.refresh(); - - // size and position menu - ul.show(); - this._resizeMenu(); - ul.position( $.extend({ - of: this.element - }, this.options.position )); - - if ( this.options.autoFocus ) { - this.menu.next(); - } - }, - - _resizeMenu: function() { - var ul = this.menu.element; - ul.outerWidth( Math.max( - // Firefox wraps long text (possibly a rounding bug) - // so we add 1px to avoid the wrapping (#7513) - ul.width( "" ).outerWidth() + 1, - this.element.outerWidth() - ) ); - }, - - _renderMenu: function( ul, items ) { - var that = this; - $.each( items, function( index, item ) { - that._renderItemData( ul, item ); - }); - }, - - _renderItemData: function( ul, item ) { - return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); - }, - - _renderItem: function( ul, item ) { - return $( "<li>" ) - .append( $( "<a>" ).text( item.label ) ) - .appendTo( ul ); - }, - - _move: function( direction, event ) { - if ( !this.menu.element.is( ":visible" ) ) { - this.search( null, event ); - return; - } - if ( this.menu.isFirstItem() && /^previous/.test( direction ) || - this.menu.isLastItem() && /^next/.test( direction ) ) { - this._value( this.term ); - this.menu.blur(); - return; - } - this.menu[ direction ]( event ); - }, - - widget: function() { - return this.menu.element; - }, - - _value: function() { - return this.valueMethod.apply( this.element, arguments ); - }, - - _keyEvent: function( keyEvent, event ) { - if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { - this._move( keyEvent, event ); - - // prevents moving cursor to beginning/end of the text field in some browsers - event.preventDefault(); - } - } -}); - -$.extend( $.ui.autocomplete, { - escapeRegex: function( value ) { - return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); - }, - filter: function(array, term) { - var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); - return $.grep( array, function(value) { - return matcher.test( value.label || value.value || value ); - }); - } -}); - - -// live region extension, adding a `messages` option -// NOTE: This is an experimental API. We are still investigating -// a full solution for string manipulation and internationalization. -$.widget( "ui.autocomplete", $.ui.autocomplete, { - options: { - messages: { - noResults: "No search results.", - results: function( amount ) { - return amount + ( amount > 1 ? " results are" : " result is" ) + - " available, use up and down arrow keys to navigate."; - } - } - }, - - __response: function( content ) { - var message; - this._superApply( arguments ); - if ( this.options.disabled || this.cancelSearch ) { - return; - } - if ( content && content.length ) { - message = this.options.messages.results( content.length ); - } else { - message = this.options.messages.noResults; - } - this.liveRegion.text( message ); - } -}); - - -}( jQuery )); - -(function( $, undefined ) { - -var lastActive, startXPos, startYPos, clickDragged, - baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", - stateClasses = "ui-state-hover ui-state-active ", - typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", - formResetHandler = function() { - var buttons = $( this ).find( ":ui-button" ); - setTimeout(function() { - buttons.button( "refresh" ); - }, 1 ); - }, - radioGroup = function( radio ) { - var name = radio.name, - form = radio.form, - radios = $( [] ); - if ( name ) { - if ( form ) { - radios = $( form ).find( "[name='" + name + "']" ); - } else { - radios = $( "[name='" + name + "']", radio.ownerDocument ) - .filter(function() { - return !this.form; - }); - } - } - return radios; - }; - -$.widget( "ui.button", { - version: "1.9.2", - defaultElement: "<button>", - options: { - disabled: null, - text: true, - label: null, - icons: { - primary: null, - secondary: null - } - }, - _create: function() { - this.element.closest( "form" ) - .unbind( "reset" + this.eventNamespace ) - .bind( "reset" + this.eventNamespace, formResetHandler ); - - if ( typeof this.options.disabled !== "boolean" ) { - this.options.disabled = !!this.element.prop( "disabled" ); - } else { - this.element.prop( "disabled", this.options.disabled ); - } - - this._determineButtonType(); - this.hasTitle = !!this.buttonElement.attr( "title" ); - - var that = this, - options = this.options, - toggleButton = this.type === "checkbox" || this.type === "radio", - activeClass = !toggleButton ? "ui-state-active" : "", - focusClass = "ui-state-focus"; - - if ( options.label === null ) { - options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html()); - } - - this._hoverable( this.buttonElement ); - - this.buttonElement - .addClass( baseClasses ) - .attr( "role", "button" ) - .bind( "mouseenter" + this.eventNamespace, function() { - if ( options.disabled ) { - return; - } - if ( this === lastActive ) { - $( this ).addClass( "ui-state-active" ); - } - }) - .bind( "mouseleave" + this.eventNamespace, function() { - if ( options.disabled ) { - return; - } - $( this ).removeClass( activeClass ); - }) - .bind( "click" + this.eventNamespace, function( event ) { - if ( options.disabled ) { - event.preventDefault(); - event.stopImmediatePropagation(); - } - }); - - this.element - .bind( "focus" + this.eventNamespace, function() { - // no need to check disabled, focus won't be triggered anyway - that.buttonElement.addClass( focusClass ); - }) - .bind( "blur" + this.eventNamespace, function() { - that.buttonElement.removeClass( focusClass ); - }); - - if ( toggleButton ) { - this.element.bind( "change" + this.eventNamespace, function() { - if ( clickDragged ) { - return; - } - that.refresh(); - }); - // if mouse moves between mousedown and mouseup (drag) set clickDragged flag - // prevents issue where button state changes but checkbox/radio checked state - // does not in Firefox (see ticket #6970) - this.buttonElement - .bind( "mousedown" + this.eventNamespace, function( event ) { - if ( options.disabled ) { - return; - } - clickDragged = false; - startXPos = event.pageX; - startYPos = event.pageY; - }) - .bind( "mouseup" + this.eventNamespace, function( event ) { - if ( options.disabled ) { - return; - } - if ( startXPos !== event.pageX || startYPos !== event.pageY ) { - clickDragged = true; - } - }); - } - - if ( this.type === "checkbox" ) { - this.buttonElement.bind( "click" + this.eventNamespace, function() { - if ( options.disabled || clickDragged ) { - return false; - } - $( this ).toggleClass( "ui-state-active" ); - that.buttonElement.attr( "aria-pressed", that.element[0].checked ); - }); - } else if ( this.type === "radio" ) { - this.buttonElement.bind( "click" + this.eventNamespace, function() { - if ( options.disabled || clickDragged ) { - return false; - } - $( this ).addClass( "ui-state-active" ); - that.buttonElement.attr( "aria-pressed", "true" ); - - var radio = that.element[ 0 ]; - radioGroup( radio ) - .not( radio ) - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", "false" ); - }); - } else { - this.buttonElement - .bind( "mousedown" + this.eventNamespace, function() { - if ( options.disabled ) { - return false; - } - $( this ).addClass( "ui-state-active" ); - lastActive = this; - that.document.one( "mouseup", function() { - lastActive = null; - }); - }) - .bind( "mouseup" + this.eventNamespace, function() { - if ( options.disabled ) { - return false; - } - $( this ).removeClass( "ui-state-active" ); - }) - .bind( "keydown" + this.eventNamespace, function(event) { - if ( options.disabled ) { - return false; - } - if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) { - $( this ).addClass( "ui-state-active" ); - } - }) - .bind( "keyup" + this.eventNamespace, function() { - $( this ).removeClass( "ui-state-active" ); - }); - - if ( this.buttonElement.is("a") ) { - this.buttonElement.keyup(function(event) { - if ( event.keyCode === $.ui.keyCode.SPACE ) { - // TODO pass through original event correctly (just as 2nd argument doesn't work) - $( this ).click(); - } - }); - } - } - - // TODO: pull out $.Widget's handling for the disabled option into - // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can - // be overridden by individual plugins - this._setOption( "disabled", options.disabled ); - this._resetButton(); - }, - - _determineButtonType: function() { - var ancestor, labelSelector, checked; - - if ( this.element.is("[type=checkbox]") ) { - this.type = "checkbox"; - } else if ( this.element.is("[type=radio]") ) { - this.type = "radio"; - } else if ( this.element.is("input") ) { - this.type = "input"; - } else { - this.type = "button"; - } - - if ( this.type === "checkbox" || this.type === "radio" ) { - // we don't search against the document in case the element - // is disconnected from the DOM - ancestor = this.element.parents().last(); - labelSelector = "label[for='" + this.element.attr("id") + "']"; - this.buttonElement = ancestor.find( labelSelector ); - if ( !this.buttonElement.length ) { - ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); - this.buttonElement = ancestor.filter( labelSelector ); - if ( !this.buttonElement.length ) { - this.buttonElement = ancestor.find( labelSelector ); - } - } - this.element.addClass( "ui-helper-hidden-accessible" ); - - checked = this.element.is( ":checked" ); - if ( checked ) { - this.buttonElement.addClass( "ui-state-active" ); - } - this.buttonElement.prop( "aria-pressed", checked ); - } else { - this.buttonElement = this.element; - } - }, - - widget: function() { - return this.buttonElement; - }, - - _destroy: function() { - this.element - .removeClass( "ui-helper-hidden-accessible" ); - this.buttonElement - .removeClass( baseClasses + " " + stateClasses + " " + typeClasses ) - .removeAttr( "role" ) - .removeAttr( "aria-pressed" ) - .html( this.buttonElement.find(".ui-button-text").html() ); - - if ( !this.hasTitle ) { - this.buttonElement.removeAttr( "title" ); - } - }, - - _setOption: function( key, value ) { - this._super( key, value ); - if ( key === "disabled" ) { - if ( value ) { - this.element.prop( "disabled", true ); - } else { - this.element.prop( "disabled", false ); - } - return; - } - this._resetButton(); - }, - - refresh: function() { - //See #8237 & #8828 - var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); - - if ( isDisabled !== this.options.disabled ) { - this._setOption( "disabled", isDisabled ); - } - if ( this.type === "radio" ) { - radioGroup( this.element[0] ).each(function() { - if ( $( this ).is( ":checked" ) ) { - $( this ).button( "widget" ) - .addClass( "ui-state-active" ) - .attr( "aria-pressed", "true" ); - } else { - $( this ).button( "widget" ) - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", "false" ); - } - }); - } else if ( this.type === "checkbox" ) { - if ( this.element.is( ":checked" ) ) { - this.buttonElement - .addClass( "ui-state-active" ) - .attr( "aria-pressed", "true" ); - } else { - this.buttonElement - .removeClass( "ui-state-active" ) - .attr( "aria-pressed", "false" ); - } - } - }, - - _resetButton: function() { - if ( this.type === "input" ) { - if ( this.options.label ) { - this.element.val( this.options.label ); - } - return; - } - var buttonElement = this.buttonElement.removeClass( typeClasses ), - buttonText = $( "<span></span>", this.document[0] ) - .addClass( "ui-button-text" ) - .html( this.options.label ) - .appendTo( buttonElement.empty() ) - .text(), - icons = this.options.icons, - multipleIcons = icons.primary && icons.secondary, - buttonClasses = []; - - if ( icons.primary || icons.secondary ) { - if ( this.options.text ) { - buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); - } - - if ( icons.primary ) { - buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); - } - - if ( icons.secondary ) { - buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); - } - - if ( !this.options.text ) { - buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); - - if ( !this.hasTitle ) { - buttonElement.attr( "title", $.trim( buttonText ) ); - } - } - } else { - buttonClasses.push( "ui-button-text-only" ); - } - buttonElement.addClass( buttonClasses.join( " " ) ); - } -}); - -$.widget( "ui.buttonset", { - version: "1.9.2", - options: { - items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(button)" - }, - - _create: function() { - this.element.addClass( "ui-buttonset" ); - }, - - _init: function() { - this.refresh(); - }, - - _setOption: function( key, value ) { - if ( key === "disabled" ) { - this.buttons.button( "option", key, value ); - } - - this._super( key, value ); - }, - - refresh: function() { - var rtl = this.element.css( "direction" ) === "rtl"; - - this.buttons = this.element.find( this.options.items ) - .filter( ":ui-button" ) - .button( "refresh" ) - .end() - .not( ":ui-button" ) - .button() - .end() - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) - .filter( ":first" ) - .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) - .end() - .filter( ":last" ) - .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) - .end() - .end(); - }, - - _destroy: function() { - this.element.removeClass( "ui-buttonset" ); - this.buttons - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-left ui-corner-right" ) - .end() - .button( "destroy" ); - } -}); - -}( jQuery ) ); - -(function( $, undefined ) { - -$.extend($.ui, { datepicker: { version: "1.9.2" } }); - -var PROP_NAME = 'datepicker'; -var dpuuid = new Date().getTime(); -var instActive; - -/* Date picker manager. - Use the singleton instance of this class, $.datepicker, to interact with the date picker. - Settings for (groups of) date pickers are maintained in an instance object, - allowing multiple different settings on the same page. */ - -function Datepicker() { - this.debug = false; // Change this to true to start debugging - this._curInst = null; // The current instance in use - this._keyEvent = false; // If the last event was a key event - this._disabledInputs = []; // List of date picker inputs that have been disabled - this._datepickerShowing = false; // True if the popup picker is showing , false if not - this._inDialog = false; // True if showing within a "dialog", false if not - this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division - this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class - this._appendClass = 'ui-datepicker-append'; // The name of the append marker class - this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class - this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class - this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class - this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class - this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class - this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class - this.regional = []; // Available regional settings, indexed by language code - this.regional[''] = { // Default regional settings - closeText: 'Done', // Display text for close link - prevText: 'Prev', // Display text for previous month link - nextText: 'Next', // Display text for next month link - currentText: 'Today', // Display text for current month link - monthNames: ['January','February','March','April','May','June', - 'July','August','September','October','November','December'], // Names of months for drop-down and formatting - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting - dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting - dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday - weekHeader: 'Wk', // Column header for week of the year - dateFormat: 'mm/dd/yy', // See format options on parseDate - firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... - isRTL: false, // True if right-to-left language, false if left-to-right - showMonthAfterYear: false, // True if the year select precedes month, false for month then year - yearSuffix: '' // Additional text to append to the year in the month headers - }; - this._defaults = { // Global defaults for all the date picker instances - showOn: 'focus', // 'focus' for popup on focus, - // 'button' for trigger button, or 'both' for either - showAnim: 'fadeIn', // Name of jQuery animation for popup - showOptions: {}, // Options for enhanced animations - defaultDate: null, // Used when field is blank: actual date, - // +/-number for offset from today, null for today - appendText: '', // Display text following the input box, e.g. showing the format - buttonText: '...', // Text for trigger button - buttonImage: '', // URL for trigger button image - buttonImageOnly: false, // True if the image appears alone, false if it appears on a button - hideIfNoPrevNext: false, // True to hide next/previous month links - // if not applicable, false to just disable them - navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links - gotoCurrent: false, // True if today link goes back to current selection instead - changeMonth: false, // True if month can be selected directly, false if only prev/next - changeYear: false, // True if year can be selected directly, false if only prev/next - yearRange: 'c-10:c+10', // Range of years to display in drop-down, - // either relative to today's year (-nn:+nn), relative to currently displayed year - // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) - showOtherMonths: false, // True to show dates in other months, false to leave blank - selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable - showWeek: false, // True to show week of the year, false to not show it - calculateWeek: this.iso8601Week, // How to calculate the week of the year, - // takes a Date and returns the number of the week for it - shortYearCutoff: '+10', // Short year values < this are in the current century, - // > this are in the previous century, - // string value starting with '+' for current year + value - minDate: null, // The earliest selectable date, or null for no limit - maxDate: null, // The latest selectable date, or null for no limit - duration: 'fast', // Duration of display/closure - beforeShowDay: null, // Function that takes a date and returns an array with - // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', - // [2] = cell title (optional), e.g. $.datepicker.noWeekends - beforeShow: null, // Function that takes an input field and - // returns a set of custom settings for the date picker - onSelect: null, // Define a callback function when a date is selected - onChangeMonthYear: null, // Define a callback function when the month or year is changed - onClose: null, // Define a callback function when the datepicker is closed - numberOfMonths: 1, // Number of months to show at a time - showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) - stepMonths: 1, // Number of months to step back/forward - stepBigMonths: 12, // Number of months to step back/forward for the big links - altField: '', // Selector for an alternate field to store selected dates into - altFormat: '', // The date format to use for the alternate field - constrainInput: true, // The input is constrained by the current date format - showButtonPanel: false, // True to show button panel, false to not show it - autoSize: false, // True to size the input for the date format, false to leave as is - disabled: false // The initial disabled state - }; - $.extend(this._defaults, this.regional['']); - this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')); -} - -$.extend(Datepicker.prototype, { - /* Class name added to elements to indicate already configured with a date picker. */ - markerClassName: 'hasDatepicker', - - //Keep track of the maximum number of rows displayed (see #7043) - maxRows: 4, - - /* Debug logging (if enabled). */ - log: function () { - if (this.debug) - console.log.apply('', arguments); - }, - - // TODO rename to "widget" when switching to widget factory - _widgetDatepicker: function() { - return this.dpDiv; - }, - - /* Override the default settings for all instances of the date picker. - @param settings object - the new settings to use as defaults (anonymous object) - @return the manager object */ - setDefaults: function(settings) { - extendRemove(this._defaults, settings || {}); - return this; - }, - - /* Attach the date picker to a jQuery selection. - @param target element - the target input field or division or span - @param settings object - the new settings to use for this date picker instance (anonymous) */ - _attachDatepicker: function(target, settings) { - // check for settings on the control itself - in namespace 'date:' - var inlineSettings = null; - for (var attrName in this._defaults) { - var attrValue = target.getAttribute('date:' + attrName); - if (attrValue) { - inlineSettings = inlineSettings || {}; - try { - inlineSettings[attrName] = eval(attrValue); - } catch (err) { - inlineSettings[attrName] = attrValue; - } - } - } - var nodeName = target.nodeName.toLowerCase(); - var inline = (nodeName == 'div' || nodeName == 'span'); - if (!target.id) { - this.uuid += 1; - target.id = 'dp' + this.uuid; - } - var inst = this._newInst($(target), inline); - inst.settings = $.extend({}, settings || {}, inlineSettings || {}); - if (nodeName == 'input') { - this._connectDatepicker(target, inst); - } else if (inline) { - this._inlineDatepicker(target, inst); - } - }, - - /* Create a new instance object. */ - _newInst: function(target, inline) { - var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars - return {id: id, input: target, // associated target - selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection - drawMonth: 0, drawYear: 0, // month being drawn - inline: inline, // is datepicker inline or not - dpDiv: (!inline ? this.dpDiv : // presentation div - bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))}; - }, - - /* Attach the date picker to an input field. */ - _connectDatepicker: function(target, inst) { - var input = $(target); - inst.append = $([]); - inst.trigger = $([]); - if (input.hasClass(this.markerClassName)) - return; - this._attachments(input, inst); - input.addClass(this.markerClassName).keydown(this._doKeyDown). - keypress(this._doKeyPress).keyup(this._doKeyUp). - bind("setData.datepicker", function(event, key, value) { - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key) { - return this._get(inst, key); - }); - this._autoSize(inst); - $.data(target, PROP_NAME, inst); - //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) - if( inst.settings.disabled ) { - this._disableDatepicker( target ); - } - }, - - /* Make attachments based on settings. */ - _attachments: function(input, inst) { - var appendText = this._get(inst, 'appendText'); - var isRTL = this._get(inst, 'isRTL'); - if (inst.append) - inst.append.remove(); - if (appendText) { - inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>'); - input[isRTL ? 'before' : 'after'](inst.append); - } - input.unbind('focus', this._showDatepicker); - if (inst.trigger) - inst.trigger.remove(); - var showOn = this._get(inst, 'showOn'); - if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field - input.focus(this._showDatepicker); - if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked - var buttonText = this._get(inst, 'buttonText'); - var buttonImage = this._get(inst, 'buttonImage'); - inst.trigger = $(this._get(inst, 'buttonImageOnly') ? - $('<img/>').addClass(this._triggerClass). - attr({ src: buttonImage, alt: buttonText, title: buttonText }) : - $('<button type="button"></button>').addClass(this._triggerClass). - html(buttonImage == '' ? buttonText : $('<img/>').attr( - { src:buttonImage, alt:buttonText, title:buttonText }))); - input[isRTL ? 'before' : 'after'](inst.trigger); - inst.trigger.click(function() { - if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) - $.datepicker._hideDatepicker(); - else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) { - $.datepicker._hideDatepicker(); - $.datepicker._showDatepicker(input[0]); - } else - $.datepicker._showDatepicker(input[0]); - return false; - }); - } - }, - - /* Apply the maximum length for the date format. */ - _autoSize: function(inst) { - if (this._get(inst, 'autoSize') && !inst.inline) { - var date = new Date(2009, 12 - 1, 20); // Ensure double digits - var dateFormat = this._get(inst, 'dateFormat'); - if (dateFormat.match(/[DM]/)) { - var findMax = function(names) { - var max = 0; - var maxI = 0; - for (var i = 0; i < names.length; i++) { - if (names[i].length > max) { - max = names[i].length; - maxI = i; - } - } - return maxI; - }; - date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? - 'monthNames' : 'monthNamesShort')))); - date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? - 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); - } - inst.input.attr('size', this._formatDate(inst, date).length); - } - }, - - /* Attach an inline date picker to a div. */ - _inlineDatepicker: function(target, inst) { - var divSpan = $(target); - if (divSpan.hasClass(this.markerClassName)) - return; - divSpan.addClass(this.markerClassName).append(inst.dpDiv). - bind("setData.datepicker", function(event, key, value){ - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key){ - return this._get(inst, key); - }); - $.data(target, PROP_NAME, inst); - this._setDate(inst, this._getDefaultDate(inst), true); - this._updateDatepicker(inst); - this._updateAlternate(inst); - //If disabled option is true, disable the datepicker before showing it (see ticket #5665) - if( inst.settings.disabled ) { - this._disableDatepicker( target ); - } - // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements - // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height - inst.dpDiv.css( "display", "block" ); - }, - - /* Pop-up the date picker in a "dialog" box. - @param input element - ignored - @param date string or Date - the initial date to display - @param onSelect function - the function to call when a date is selected - @param settings object - update the dialog date picker instance's settings (anonymous object) - @param pos int[2] - coordinates for the dialog's position within the screen or - event - with x/y coordinates or - leave empty for default (screen centre) - @return the manager object */ - _dialogDatepicker: function(input, date, onSelect, settings, pos) { - var inst = this._dialogInst; // internal instance - if (!inst) { - this.uuid += 1; - var id = 'dp' + this.uuid; - this._dialogInput = $('<input type="text" id="' + id + - '" style="position: absolute; top: -100px; width: 0px;"/>'); - this._dialogInput.keydown(this._doKeyDown); - $('body').append(this._dialogInput); - inst = this._dialogInst = this._newInst(this._dialogInput, false); - inst.settings = {}; - $.data(this._dialogInput[0], PROP_NAME, inst); - } - extendRemove(inst.settings, settings || {}); - date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); - this._dialogInput.val(date); - - this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); - if (!this._pos) { - var browserWidth = document.documentElement.clientWidth; - var browserHeight = document.documentElement.clientHeight; - var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; - var scrollY = document.documentElement.scrollTop || document.body.scrollTop; - this._pos = // should use actual width/height below - [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; - } - - // move input on screen for focus, but hidden behind dialog - this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); - inst.settings.onSelect = onSelect; - this._inDialog = true; - this.dpDiv.addClass(this._dialogClass); - this._showDatepicker(this._dialogInput[0]); - if ($.blockUI) - $.blockUI(this.dpDiv); - $.data(this._dialogInput[0], PROP_NAME, inst); - return this; - }, - - /* Detach a datepicker from its control. - @param target element - the target input field or division or span */ - _destroyDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - $.removeData(target, PROP_NAME); - if (nodeName == 'input') { - inst.append.remove(); - inst.trigger.remove(); - $target.removeClass(this.markerClassName). - unbind('focus', this._showDatepicker). - unbind('keydown', this._doKeyDown). - unbind('keypress', this._doKeyPress). - unbind('keyup', this._doKeyUp); - } else if (nodeName == 'div' || nodeName == 'span') - $target.removeClass(this.markerClassName).empty(); - }, - - /* Enable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _enableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = false; - inst.trigger.filter('button'). - each(function() { this.disabled = false; }).end(). - filter('img').css({opacity: '1.0', cursor: ''}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().removeClass('ui-state-disabled'); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - prop("disabled", false); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - }, - - /* Disable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _disableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = true; - inst.trigger.filter('button'). - each(function() { this.disabled = true; }).end(). - filter('img').css({opacity: '0.5', cursor: 'default'}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().addClass('ui-state-disabled'); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - prop("disabled", true); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - this._disabledInputs[this._disabledInputs.length] = target; - }, - - /* Is the first field in a jQuery collection disabled as a datepicker? - @param target element - the target input field or division or span - @return boolean - true if disabled, false if enabled */ - _isDisabledDatepicker: function(target) { - if (!target) { - return false; - } - for (var i = 0; i < this._disabledInputs.length; i++) { - if (this._disabledInputs[i] == target) - return true; - } - return false; - }, - - /* Retrieve the instance data for the target control. - @param target element - the target input field or division or span - @return object - the associated instance data - @throws error if a jQuery problem getting data */ - _getInst: function(target) { - try { - return $.data(target, PROP_NAME); - } - catch (err) { - throw 'Missing instance data for this datepicker'; - } - }, - - /* Update or retrieve the settings for a date picker attached to an input field or division. - @param target element - the target input field or division or span - @param name object - the new settings to update or - string - the name of the setting to change or retrieve, - when retrieving also 'all' for all instance settings or - 'defaults' for all global defaults - @param value any - the new value for the setting - (omit if above is an object or to retrieve a value) */ - _optionDatepicker: function(target, name, value) { - var inst = this._getInst(target); - if (arguments.length == 2 && typeof name == 'string') { - return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : - (inst ? (name == 'all' ? $.extend({}, inst.settings) : - this._get(inst, name)) : null)); - } - var settings = name || {}; - if (typeof name == 'string') { - settings = {}; - settings[name] = value; - } - if (inst) { - if (this._curInst == inst) { - this._hideDatepicker(); - } - var date = this._getDateDatepicker(target, true); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - extendRemove(inst.settings, settings); - // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided - if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined) - inst.settings.minDate = this._formatDate(inst, minDate); - if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined) - inst.settings.maxDate = this._formatDate(inst, maxDate); - this._attachments($(target), inst); - this._autoSize(inst); - this._setDate(inst, date); - this._updateAlternate(inst); - this._updateDatepicker(inst); - } - }, - - // change method deprecated - _changeDatepicker: function(target, name, value) { - this._optionDatepicker(target, name, value); - }, - - /* Redraw the date picker attached to an input field or division. - @param target element - the target input field or division or span */ - _refreshDatepicker: function(target) { - var inst = this._getInst(target); - if (inst) { - this._updateDatepicker(inst); - } - }, - - /* Set the dates for a jQuery selection. - @param target element - the target input field or division or span - @param date Date - the new date */ - _setDateDatepicker: function(target, date) { - var inst = this._getInst(target); - if (inst) { - this._setDate(inst, date); - this._updateDatepicker(inst); - this._updateAlternate(inst); - } - }, - - /* Get the date(s) for the first entry in a jQuery selection. - @param target element - the target input field or division or span - @param noDefault boolean - true if no default date is to be used - @return Date - the current date */ - _getDateDatepicker: function(target, noDefault) { - var inst = this._getInst(target); - if (inst && !inst.inline) - this._setDateFromField(inst, noDefault); - return (inst ? this._getDate(inst) : null); - }, - - /* Handle keystrokes. */ - _doKeyDown: function(event) { - var inst = $.datepicker._getInst(event.target); - var handled = true; - var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); - inst._keyEvent = true; - if ($.datepicker._datepickerShowing) - switch (event.keyCode) { - case 9: $.datepicker._hideDatepicker(); - handled = false; - break; // hide on tab out - case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + - $.datepicker._currentClass + ')', inst.dpDiv); - if (sel[0]) - $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); - var onSelect = $.datepicker._get(inst, 'onSelect'); - if (onSelect) { - var dateStr = $.datepicker._formatDate(inst); - - // trigger custom callback - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); - } - else - $.datepicker._hideDatepicker(); - return false; // don't submit the form - break; // select the value on enter - case 27: $.datepicker._hideDatepicker(); - break; // hide on escape - case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // previous month/year on page up/+ ctrl - case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // next month/year on page down/+ ctrl - case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); - handled = event.ctrlKey || event.metaKey; - break; // clear on ctrl or command +end - case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); - handled = event.ctrlKey || event.metaKey; - break; // current on ctrl or command +home - case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); - handled = event.ctrlKey || event.metaKey; - // -1 day on ctrl or command +left - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +left on Mac - break; - case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // -1 week on ctrl or command +up - case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); - handled = event.ctrlKey || event.metaKey; - // +1 day on ctrl or command +right - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +right - break; - case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // +1 week on ctrl or command +down - default: handled = false; - } - else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home - $.datepicker._showDatepicker(this); - else { - handled = false; - } - if (handled) { - event.preventDefault(); - event.stopPropagation(); - } - }, - - /* Filter entered characters - based on date format. */ - _doKeyPress: function(event) { - var inst = $.datepicker._getInst(event.target); - if ($.datepicker._get(inst, 'constrainInput')) { - var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); - var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); - return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); - } - }, - - /* Synchronise manual entry and field/alternate field. */ - _doKeyUp: function(event) { - var inst = $.datepicker._getInst(event.target); - if (inst.input.val() != inst.lastVal) { - try { - var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - (inst.input ? inst.input.val() : null), - $.datepicker._getFormatConfig(inst)); - if (date) { // only if valid - $.datepicker._setDateFromField(inst); - $.datepicker._updateAlternate(inst); - $.datepicker._updateDatepicker(inst); - } - } - catch (err) { - $.datepicker.log(err); - } - } - return true; - }, - - /* Pop-up the date picker for a given input field. - If false returned from beforeShow event handler do not show. - @param input element - the input field attached to the date picker or - event - if triggered by focus */ - _showDatepicker: function(input) { - input = input.target || input; - if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger - input = $('input', input.parentNode)[0]; - if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here - return; - var inst = $.datepicker._getInst(input); - if ($.datepicker._curInst && $.datepicker._curInst != inst) { - $.datepicker._curInst.dpDiv.stop(true, true); - if ( inst && $.datepicker._datepickerShowing ) { - $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); - } - } - var beforeShow = $.datepicker._get(inst, 'beforeShow'); - var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; - if(beforeShowSettings === false){ - //false - return; - } - extendRemove(inst.settings, beforeShowSettings); - inst.lastVal = null; - $.datepicker._lastInput = input; - $.datepicker._setDateFromField(inst); - if ($.datepicker._inDialog) // hide cursor - input.value = ''; - if (!$.datepicker._pos) { // position below input - $.datepicker._pos = $.datepicker._findPos(input); - $.datepicker._pos[1] += input.offsetHeight; // add the height - } - var isFixed = false; - $(input).parents().each(function() { - isFixed |= $(this).css('position') == 'fixed'; - return !isFixed; - }); - var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; - $.datepicker._pos = null; - //to avoid flashes on Firefox - inst.dpDiv.empty(); - // determine sizing offscreen - inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); - $.datepicker._updateDatepicker(inst); - // fix width for dynamic number of date pickers - // and adjust position before showing - offset = $.datepicker._checkOffset(inst, offset, isFixed); - inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? - 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', - left: offset.left + 'px', top: offset.top + 'px'}); - if (!inst.inline) { - var showAnim = $.datepicker._get(inst, 'showAnim'); - var duration = $.datepicker._get(inst, 'duration'); - var postProcess = function() { - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !! cover.length ){ - var borders = $.datepicker._getBorders(inst.dpDiv); - cover.css({left: -borders[0], top: -borders[1], - width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); - } - }; - inst.dpDiv.zIndex($(input).zIndex()+1); - $.datepicker._datepickerShowing = true; - - // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed - if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) - inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); - if (!showAnim || !duration) - postProcess(); - if (inst.input.is(':visible') && !inst.input.is(':disabled')) - inst.input.focus(); - $.datepicker._curInst = inst; - } - }, - - /* Generate the date picker content. */ - _updateDatepicker: function(inst) { - this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) - var borders = $.datepicker._getBorders(inst.dpDiv); - instActive = inst; // for delegate hover events - inst.dpDiv.empty().append(this._generateHTML(inst)); - this._attachHandlers(inst); - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6 - cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) - } - inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover(); - var numMonths = this._getNumberOfMonths(inst); - var cols = numMonths[1]; - var width = 17; - inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); - if (cols > 1) - inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); - inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + - 'Class']('ui-datepicker-multi'); - inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + - 'Class']('ui-datepicker-rtl'); - if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && - // #6694 - don't focus the input if it's already focused - // this breaks the change event in IE - inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement) - inst.input.focus(); - // deffered render of the years select (to avoid flashes on Firefox) - if( inst.yearshtml ){ - var origyearshtml = inst.yearshtml; - setTimeout(function(){ - //assure that inst.yearshtml didn't change. - if( origyearshtml === inst.yearshtml && inst.yearshtml ){ - inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml); - } - origyearshtml = inst.yearshtml = null; - }, 0); - } - }, - - /* Retrieve the size of left and top borders for an element. - @param elem (jQuery object) the element of interest - @return (number[2]) the left and top borders */ - _getBorders: function(elem) { - var convert = function(value) { - return {thin: 1, medium: 2, thick: 3}[value] || value; - }; - return [parseFloat(convert(elem.css('border-left-width'))), - parseFloat(convert(elem.css('border-top-width')))]; - }, - - /* Check positioning to remain on screen. */ - _checkOffset: function(inst, offset, isFixed) { - var dpWidth = inst.dpDiv.outerWidth(); - var dpHeight = inst.dpDiv.outerHeight(); - var inputWidth = inst.input ? inst.input.outerWidth() : 0; - var inputHeight = inst.input ? inst.input.outerHeight() : 0; - var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()); - var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); - - offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); - offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; - offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; - - // now check if datepicker is showing outside window viewport - move to a better place if so. - offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? - Math.abs(offset.left + dpWidth - viewWidth) : 0); - offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? - Math.abs(dpHeight + inputHeight) : 0); - - return offset; - }, - - /* Find an object's position on the screen. */ - _findPos: function(obj) { - var inst = this._getInst(obj); - var isRTL = this._get(inst, 'isRTL'); - while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) { - obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; - } - var position = $(obj).offset(); - return [position.left, position.top]; - }, - - /* Hide the date picker from view. - @param input element - the input field attached to the date picker */ - _hideDatepicker: function(input) { - var inst = this._curInst; - if (!inst || (input && inst != $.data(input, PROP_NAME))) - return; - if (this._datepickerShowing) { - var showAnim = this._get(inst, 'showAnim'); - var duration = this._get(inst, 'duration'); - var postProcess = function() { - $.datepicker._tidyDialog(inst); - }; - - // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed - if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) - inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : - (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); - if (!showAnim) - postProcess(); - this._datepickerShowing = false; - var onClose = this._get(inst, 'onClose'); - if (onClose) - onClose.apply((inst.input ? inst.input[0] : null), - [(inst.input ? inst.input.val() : ''), inst]); - this._lastInput = null; - if (this._inDialog) { - this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); - if ($.blockUI) { - $.unblockUI(); - $('body').append(this.dpDiv); - } - } - this._inDialog = false; - } - }, - - /* Tidy up after a dialog display. */ - _tidyDialog: function(inst) { - inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); - }, - - /* Close date picker if clicked elsewhere. */ - _checkExternalClick: function(event) { - if (!$.datepicker._curInst) - return; - - var $target = $(event.target), - inst = $.datepicker._getInst($target[0]); - - if ( ( ( $target[0].id != $.datepicker._mainDivId && - $target.parents('#' + $.datepicker._mainDivId).length == 0 && - !$target.hasClass($.datepicker.markerClassName) && - !$target.closest("." + $.datepicker._triggerClass).length && - $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || - ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) ) - $.datepicker._hideDatepicker(); - }, - - /* Adjust one of the date sub-fields. */ - _adjustDate: function(id, offset, period) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._isDisabledDatepicker(target[0])) { - return; - } - this._adjustInstDate(inst, offset + - (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning - period); - this._updateDatepicker(inst); - }, - - /* Action for current link. */ - _gotoToday: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._get(inst, 'gotoCurrent') && inst.currentDay) { - inst.selectedDay = inst.currentDay; - inst.drawMonth = inst.selectedMonth = inst.currentMonth; - inst.drawYear = inst.selectedYear = inst.currentYear; - } - else { - var date = new Date(); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - } - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Action for selecting a new month/year. */ - _selectMonthYear: function(id, select, period) { - var target = $(id); - var inst = this._getInst(target[0]); - inst['selected' + (period == 'M' ? 'Month' : 'Year')] = - inst['draw' + (period == 'M' ? 'Month' : 'Year')] = - parseInt(select.options[select.selectedIndex].value,10); - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Action for selecting a day. */ - _selectDay: function(id, month, year, td) { - var target = $(id); - if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { - return; - } - var inst = this._getInst(target[0]); - inst.selectedDay = inst.currentDay = $('a', td).html(); - inst.selectedMonth = inst.currentMonth = month; - inst.selectedYear = inst.currentYear = year; - this._selectDate(id, this._formatDate(inst, - inst.currentDay, inst.currentMonth, inst.currentYear)); - }, - - /* Erase the input field and hide the date picker. */ - _clearDate: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - this._selectDate(target, ''); - }, - - /* Update the input field with the selected date. */ - _selectDate: function(id, dateStr) { - var target = $(id); - var inst = this._getInst(target[0]); - dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); - if (inst.input) - inst.input.val(dateStr); - this._updateAlternate(inst); - var onSelect = this._get(inst, 'onSelect'); - if (onSelect) - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback - else if (inst.input) - inst.input.trigger('change'); // fire the change event - if (inst.inline) - this._updateDatepicker(inst); - else { - this._hideDatepicker(); - this._lastInput = inst.input[0]; - if (typeof(inst.input[0]) != 'object') - inst.input.focus(); // restore focus - this._lastInput = null; - } - }, - - /* Update any alternate field to synchronise with the main field. */ - _updateAlternate: function(inst) { - var altField = this._get(inst, 'altField'); - if (altField) { // update alternate field too - var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); - var date = this._getDate(inst); - var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); - $(altField).each(function() { $(this).val(dateStr); }); - } - }, - - /* Set as beforeShowDay function to prevent selection of weekends. - @param date Date - the date to customise - @return [boolean, string] - is this date selectable?, what is its CSS class? */ - noWeekends: function(date) { - var day = date.getDay(); - return [(day > 0 && day < 6), '']; - }, - - /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - @param date Date - the date to get the week for - @return number - the number of the week within the year that contains this date */ - iso8601Week: function(date) { - var checkDate = new Date(date.getTime()); - // Find Thursday of this week starting on Monday - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - var time = checkDate.getTime(); - checkDate.setMonth(0); // Compare with Jan 1 - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; - }, - - /* Parse a string value into a date object. - See formatDate below for the possible formats. - - @param format string - the expected format of the date - @param value string - the date in the above format - @param settings Object - attributes include: - shortYearCutoff number - the cutoff year for determining the century (optional) - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return Date - the extracted date value or null if value is blank */ - parseDate: function (format, value, settings) { - if (format == null || value == null) - throw 'Invalid arguments'; - value = (typeof value == 'object' ? value.toString() : value + ''); - if (value == '') - return null; - var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - var year = -1; - var month = -1; - var day = -1; - var doy = -1; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Extract a number from the string value - var getNumber = function(match) { - var isDoubled = lookAhead(match); - var size = (match == '@' ? 14 : (match == '!' ? 20 : - (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2)))); - var digits = new RegExp('^\\d{1,' + size + '}'); - var num = value.substring(iValue).match(digits); - if (!num) - throw 'Missing number at position ' + iValue; - iValue += num[0].length; - return parseInt(num[0], 10); - }; - // Extract a name from the string value and convert to an index - var getName = function(match, shortNames, longNames) { - var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { - return [ [k, v] ]; - }).sort(function (a, b) { - return -(a[1].length - b[1].length); - }); - var index = -1; - $.each(names, function (i, pair) { - var name = pair[1]; - if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) { - index = pair[0]; - iValue += name.length; - return false; - } - }); - if (index != -1) - return index + 1; - else - throw 'Unknown name at position ' + iValue; - }; - // Confirm that a literal character matches the string value - var checkLiteral = function() { - if (value.charAt(iValue) != format.charAt(iFormat)) - throw 'Unexpected literal at position ' + iValue; - iValue++; - }; - var iValue = 0; - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - checkLiteral(); - else - switch (format.charAt(iFormat)) { - case 'd': - day = getNumber('d'); - break; - case 'D': - getName('D', dayNamesShort, dayNames); - break; - case 'o': - doy = getNumber('o'); - break; - case 'm': - month = getNumber('m'); - break; - case 'M': - month = getName('M', monthNamesShort, monthNames); - break; - case 'y': - year = getNumber('y'); - break; - case '@': - var date = new Date(getNumber('@')); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case '!': - var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "'": - if (lookAhead("'")) - checkLiteral(); - else - literal = true; - break; - default: - checkLiteral(); - } - } - if (iValue < value.length){ - var extra = value.substr(iValue); - if (!/^\s+/.test(extra)) { - throw "Extra/unparsed characters found in date: " + extra; - } - } - if (year == -1) - year = new Date().getFullYear(); - else if (year < 100) - year += new Date().getFullYear() - new Date().getFullYear() % 100 + - (year <= shortYearCutoff ? 0 : -100); - if (doy > -1) { - month = 1; - day = doy; - do { - var dim = this._getDaysInMonth(year, month - 1); - if (day <= dim) - break; - month++; - day -= dim; - } while (true); - } - var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); - if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) - throw 'Invalid date'; // E.g. 31/02/00 - return date; - }, - - /* Standard date formats. */ - ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) - COOKIE: 'D, dd M yy', - ISO_8601: 'yy-mm-dd', - RFC_822: 'D, d M y', - RFC_850: 'DD, dd-M-y', - RFC_1036: 'D, d M y', - RFC_1123: 'D, d M yy', - RFC_2822: 'D, d M yy', - RSS: 'D, d M y', // RFC 822 - TICKS: '!', - TIMESTAMP: '@', - W3C: 'yy-mm-dd', // ISO 8601 - - _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + - Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), - - /* Format a date object into a string value. - The format can be combinations of the following: - d - day of month (no leading zero) - dd - day of month (two digit) - o - day of year (no leading zeros) - oo - day of year (three digit) - D - day name short - DD - day name long - m - month of year (no leading zero) - mm - month of year (two digit) - M - month name short - MM - month name long - y - year (two digit) - yy - year (four digit) - @ - Unix timestamp (ms since 01/01/1970) - ! - Windows ticks (100ns since 01/01/0001) - '...' - literal text - '' - single quote - - @param format string - the desired format of the date - @param date Date - the date value to format - @param settings Object - attributes include: - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return string - the date in the above format */ - formatDate: function (format, date, settings) { - if (!date) - return ''; - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Format a number, with leading zero if necessary - var formatNumber = function(match, value, len) { - var num = '' + value; - if (lookAhead(match)) - while (num.length < len) - num = '0' + num; - return num; - }; - // Format a name, short or long as requested - var formatName = function(match, value, shortNames, longNames) { - return (lookAhead(match) ? longNames[value] : shortNames[value]); - }; - var output = ''; - var literal = false; - if (date) - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - output += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': - output += formatNumber('d', date.getDate(), 2); - break; - case 'D': - output += formatName('D', date.getDay(), dayNamesShort, dayNames); - break; - case 'o': - output += formatNumber('o', - Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); - break; - case 'm': - output += formatNumber('m', date.getMonth() + 1, 2); - break; - case 'M': - output += formatName('M', date.getMonth(), monthNamesShort, monthNames); - break; - case 'y': - output += (lookAhead('y') ? date.getFullYear() : - (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); - break; - case '@': - output += date.getTime(); - break; - case '!': - output += date.getTime() * 10000 + this._ticksTo1970; - break; - case "'": - if (lookAhead("'")) - output += "'"; - else - literal = true; - break; - default: - output += format.charAt(iFormat); - } - } - return output; - }, - - /* Extract all possible characters from the date format. */ - _possibleChars: function (format) { - var chars = ''; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - for (var iFormat = 0; iFormat < format.length; iFormat++) - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - chars += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': case 'm': case 'y': case '@': - chars += '0123456789'; - break; - case 'D': case 'M': - return null; // Accept anything - case "'": - if (lookAhead("'")) - chars += "'"; - else - literal = true; - break; - default: - chars += format.charAt(iFormat); - } - return chars; - }, - - /* Get a setting value, defaulting if necessary. */ - _get: function(inst, name) { - return inst.settings[name] !== undefined ? - inst.settings[name] : this._defaults[name]; - }, - - /* Parse existing date and initialise date picker. */ - _setDateFromField: function(inst, noDefault) { - if (inst.input.val() == inst.lastVal) { - return; - } - var dateFormat = this._get(inst, 'dateFormat'); - var dates = inst.lastVal = inst.input ? inst.input.val() : null; - var date, defaultDate; - date = defaultDate = this._getDefaultDate(inst); - var settings = this._getFormatConfig(inst); - try { - date = this.parseDate(dateFormat, dates, settings) || defaultDate; - } catch (event) { - this.log(event); - dates = (noDefault ? '' : dates); - } - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - inst.currentDay = (dates ? date.getDate() : 0); - inst.currentMonth = (dates ? date.getMonth() : 0); - inst.currentYear = (dates ? date.getFullYear() : 0); - this._adjustInstDate(inst); - }, - - /* Retrieve the default date shown on opening. */ - _getDefaultDate: function(inst) { - return this._restrictMinMax(inst, - this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); - }, - - /* A date may be specified as an exact value or a relative one. */ - _determineDate: function(inst, date, defaultDate) { - var offsetNumeric = function(offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - return date; - }; - var offsetString = function(offset) { - try { - return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - offset, $.datepicker._getFormatConfig(inst)); - } - catch (e) { - // Ignore - } - var date = (offset.toLowerCase().match(/^c/) ? - $.datepicker._getDate(inst) : null) || new Date(); - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; - var matches = pattern.exec(offset); - while (matches) { - switch (matches[2] || 'd') { - case 'd' : case 'D' : - day += parseInt(matches[1],10); break; - case 'w' : case 'W' : - day += parseInt(matches[1],10) * 7; break; - case 'm' : case 'M' : - month += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - case 'y': case 'Y' : - year += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - } - matches = pattern.exec(offset); - } - return new Date(year, month, day); - }; - var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) : - (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); - newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate); - if (newDate) { - newDate.setHours(0); - newDate.setMinutes(0); - newDate.setSeconds(0); - newDate.setMilliseconds(0); - } - return this._daylightSavingAdjust(newDate); - }, - - /* Handle switch to/from daylight saving. - Hours may be non-zero on daylight saving cut-over: - > 12 when midnight changeover, but then cannot generate - midnight datetime, so jump to 1AM, otherwise reset. - @param date (Date) the date to check - @return (Date) the corrected date */ - _daylightSavingAdjust: function(date) { - if (!date) return null; - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; - }, - - /* Set the date(s) directly. */ - _setDate: function(inst, date, noChange) { - var clear = !date; - var origMonth = inst.selectedMonth; - var origYear = inst.selectedYear; - var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); - inst.selectedDay = inst.currentDay = newDate.getDate(); - inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); - inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); - if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) - this._notifyChange(inst); - this._adjustInstDate(inst); - if (inst.input) { - inst.input.val(clear ? '' : this._formatDate(inst)); - } - }, - - /* Retrieve the date(s) directly. */ - _getDate: function(inst) { - var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : - this._daylightSavingAdjust(new Date( - inst.currentYear, inst.currentMonth, inst.currentDay))); - return startDate; - }, - - /* Attach the onxxx handlers. These are declared statically so - * they work with static code transformers like Caja. - */ - _attachHandlers: function(inst) { - var stepMonths = this._get(inst, 'stepMonths'); - var id = '#' + inst.id.replace( /\\\\/g, "\\" ); - inst.dpDiv.find('[data-handler]').map(function () { - var handler = { - prev: function () { - window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M'); - }, - next: function () { - window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M'); - }, - hide: function () { - window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker(); - }, - today: function () { - window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id); - }, - selectDay: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this); - return false; - }, - selectMonth: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M'); - return false; - }, - selectYear: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y'); - return false; - } - }; - $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]); - }); - }, - - /* Generate the HTML for the current state of the date picker. */ - _generateHTML: function(inst) { - var today = new Date(); - today = this._daylightSavingAdjust( - new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time - var isRTL = this._get(inst, 'isRTL'); - var showButtonPanel = this._get(inst, 'showButtonPanel'); - var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); - var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); - var numMonths = this._getNumberOfMonths(inst); - var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); - var stepMonths = this._get(inst, 'stepMonths'); - var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); - var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : - new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var drawMonth = inst.drawMonth - showCurrentAtPos; - var drawYear = inst.drawYear; - if (drawMonth < 0) { - drawMonth += 12; - drawYear--; - } - if (maxDate) { - var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), - maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); - maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); - while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { - drawMonth--; - if (drawMonth < 0) { - drawMonth = 11; - drawYear--; - } - } - } - inst.drawMonth = drawMonth; - inst.drawYear = drawYear; - var prevText = this._get(inst, 'prevText'); - prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), - this._getFormatConfig(inst))); - var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? - '<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click"' + - ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' : - (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+ prevText +'"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>')); - var nextText = this._get(inst, 'nextText'); - nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), - this._getFormatConfig(inst))); - var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? - '<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click"' + - ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' : - (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+ nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>')); - var currentText = this._get(inst, 'currentText'); - var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); - currentText = (!navigationAsDateFormat ? currentText : - this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); - var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">' + - this._get(inst, 'closeText') + '</button>' : ''); - var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') + - (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click"' + - '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : ''; - var firstDay = parseInt(this._get(inst, 'firstDay'),10); - firstDay = (isNaN(firstDay) ? 0 : firstDay); - var showWeek = this._get(inst, 'showWeek'); - var dayNames = this._get(inst, 'dayNames'); - var dayNamesShort = this._get(inst, 'dayNamesShort'); - var dayNamesMin = this._get(inst, 'dayNamesMin'); - var monthNames = this._get(inst, 'monthNames'); - var monthNamesShort = this._get(inst, 'monthNamesShort'); - var beforeShowDay = this._get(inst, 'beforeShowDay'); - var showOtherMonths = this._get(inst, 'showOtherMonths'); - var selectOtherMonths = this._get(inst, 'selectOtherMonths'); - var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; - var defaultDate = this._getDefaultDate(inst); - var html = ''; - for (var row = 0; row < numMonths[0]; row++) { - var group = ''; - this.maxRows = 4; - for (var col = 0; col < numMonths[1]; col++) { - var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); - var cornerClass = ' ui-corner-all'; - var calender = ''; - if (isMultiMonth) { - calender += '<div class="ui-datepicker-group'; - if (numMonths[1] > 1) - switch (col) { - case 0: calender += ' ui-datepicker-group-first'; - cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break; - case numMonths[1]-1: calender += ' ui-datepicker-group-last'; - cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break; - default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break; - } - calender += '">'; - } - calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' + - (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + - (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + - this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, - row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers - '</div><table class="ui-datepicker-calendar"><thead>' + - '<tr>'; - var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : ''); - for (var dow = 0; dow < 7; dow++) { // days of the week - var day = (dow + firstDay) % 7; - thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + - '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>'; - } - calender += thead + '</tr></thead><tbody>'; - var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); - if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) - inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); - var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; - var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate - var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) - this.maxRows = numRows; - var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); - for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows - calender += '<tr>'; - var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' + - this._get(inst, 'calculateWeek')(printDate) + '</td>'); - for (var dow = 0; dow < 7; dow++) { // create date picker days - var daySettings = (beforeShowDay ? - beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); - var otherMonth = (printDate.getMonth() != drawMonth); - var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || - (minDate && printDate < minDate) || (maxDate && printDate > maxDate); - tbody += '<td class="' + - ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends - (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months - ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key - (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ? - // or defaultDate is current printedDate and defaultDate is selectedDate - ' ' + this._dayOverClass : '') + // highlight selected day - (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days - (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates - (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day - (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different) - ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title - (unselectable ? '' : ' data-handler="selectDay" data-event="click" data-month="' + printDate.getMonth() + '" data-year="' + printDate.getFullYear() + '"') + '>' + // actions - (otherMonth && !showOtherMonths ? ' ' : // display for other months - (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' + - (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') + - (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day - (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months - '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date - printDate.setDate(printDate.getDate() + 1); - printDate = this._daylightSavingAdjust(printDate); - } - calender += tbody + '</tr>'; - } - drawMonth++; - if (drawMonth > 11) { - drawMonth = 0; - drawYear++; - } - calender += '</tbody></table>' + (isMultiMonth ? '</div>' + - ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : ''); - group += calender; - } - html += group; - } - html += buttonPanel + ($.ui.ie6 && !inst.inline ? - '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : ''); - inst._keyEvent = false; - return html; - }, - - /* Generate the month and year header. */ - _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, - secondary, monthNames, monthNamesShort) { - var changeMonth = this._get(inst, 'changeMonth'); - var changeYear = this._get(inst, 'changeYear'); - var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); - var html = '<div class="ui-datepicker-title">'; - var monthHtml = ''; - // month selection - if (secondary || !changeMonth) - monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>'; - else { - var inMinYear = (minDate && minDate.getFullYear() == drawYear); - var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); - monthHtml += '<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">'; - for (var month = 0; month < 12; month++) { - if ((!inMinYear || month >= minDate.getMonth()) && - (!inMaxYear || month <= maxDate.getMonth())) - monthHtml += '<option value="' + month + '"' + - (month == drawMonth ? ' selected="selected"' : '') + - '>' + monthNamesShort[month] + '</option>'; - } - monthHtml += '</select>'; - } - if (!showMonthAfterYear) - html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); - // year selection - if ( !inst.yearshtml ) { - inst.yearshtml = ''; - if (secondary || !changeYear) - html += '<span class="ui-datepicker-year">' + drawYear + '</span>'; - else { - // determine range of years to display - var years = this._get(inst, 'yearRange').split(':'); - var thisYear = new Date().getFullYear(); - var determineYear = function(value) { - var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : - parseInt(value, 10))); - return (isNaN(year) ? thisYear : year); - }; - var year = determineYear(years[0]); - var endYear = Math.max(year, determineYear(years[1] || '')); - year = (minDate ? Math.max(year, minDate.getFullYear()) : year); - endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); - inst.yearshtml += '<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">'; - for (; year <= endYear; year++) { - inst.yearshtml += '<option value="' + year + '"' + - (year == drawYear ? ' selected="selected"' : '') + - '>' + year + '</option>'; - } - inst.yearshtml += '</select>'; - - html += inst.yearshtml; - inst.yearshtml = null; - } - } - html += this._get(inst, 'yearSuffix'); - if (showMonthAfterYear) - html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; - html += '</div>'; // Close datepicker_header - return html; - }, - - /* Adjust one of the date sub-fields. */ - _adjustInstDate: function(inst, offset, period) { - var year = inst.drawYear + (period == 'Y' ? offset : 0); - var month = inst.drawMonth + (period == 'M' ? offset : 0); - var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + - (period == 'D' ? offset : 0); - var date = this._restrictMinMax(inst, - this._daylightSavingAdjust(new Date(year, month, day))); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - if (period == 'M' || period == 'Y') - this._notifyChange(inst); - }, - - /* Ensure a date is within any min/max bounds. */ - _restrictMinMax: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var newDate = (minDate && date < minDate ? minDate : date); - newDate = (maxDate && newDate > maxDate ? maxDate : newDate); - return newDate; - }, - - /* Notify change of month/year. */ - _notifyChange: function(inst) { - var onChange = this._get(inst, 'onChangeMonthYear'); - if (onChange) - onChange.apply((inst.input ? inst.input[0] : null), - [inst.selectedYear, inst.selectedMonth + 1, inst]); - }, - - /* Determine the number of months to show. */ - _getNumberOfMonths: function(inst) { - var numMonths = this._get(inst, 'numberOfMonths'); - return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); - }, - - /* Determine the current maximum date - ensure no time components are set. */ - _getMinMaxDate: function(inst, minMax) { - return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); - }, - - /* Find the number of days in a given month. */ - _getDaysInMonth: function(year, month) { - return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); - }, - - /* Find the day of the week of the first of a month. */ - _getFirstDayOfMonth: function(year, month) { - return new Date(year, month, 1).getDay(); - }, - - /* Determines if we should allow a "next/prev" month display change. */ - _canAdjustMonth: function(inst, offset, curYear, curMonth) { - var numMonths = this._getNumberOfMonths(inst); - var date = this._daylightSavingAdjust(new Date(curYear, - curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); - if (offset < 0) - date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); - return this._isInRange(inst, date); - }, - - /* Is the given date in the accepted range? */ - _isInRange: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - return ((!minDate || date.getTime() >= minDate.getTime()) && - (!maxDate || date.getTime() <= maxDate.getTime())); - }, - - /* Provide the configuration settings for formatting/parsing. */ - _getFormatConfig: function(inst) { - var shortYearCutoff = this._get(inst, 'shortYearCutoff'); - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - return {shortYearCutoff: shortYearCutoff, - dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), - monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; - }, - - /* Format the given date for display. */ - _formatDate: function(inst, day, month, year) { - if (!day) { - inst.currentDay = inst.selectedDay; - inst.currentMonth = inst.selectedMonth; - inst.currentYear = inst.selectedYear; - } - var date = (day ? (typeof day == 'object' ? day : - this._daylightSavingAdjust(new Date(year, month, day))) : - this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); - } -}); - -/* - * Bind hover events for datepicker elements. - * Done via delegate so the binding only occurs once in the lifetime of the parent div. - * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. - */ -function bindHover(dpDiv) { - var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; - return dpDiv.delegate(selector, 'mouseout', function() { - $(this).removeClass('ui-state-hover'); - if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); - if (this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); - }) - .delegate(selector, 'mouseover', function(){ - if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { - $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); - $(this).addClass('ui-state-hover'); - if (this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); - if (this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); - } - }); -} - -/* jQuery extend now ignores nulls! */ -function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) - if (props[name] == null || props[name] == undefined) - target[name] = props[name]; - return target; -}; - -/* Invoke the datepicker functionality. - @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality - @return jQuery object */ -$.fn.datepicker = function(options){ - - /* Verify an empty collection wasn't passed - Fixes #6976 */ - if ( !this.length ) { - return this; - } - - /* Initialise the date picker. */ - if (!$.datepicker.initialized) { - $(document).mousedown($.datepicker._checkExternalClick). - find(document.body).append($.datepicker.dpDiv); - $.datepicker.initialized = true; - } - - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - return this.each(function() { - typeof options == 'string' ? - $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this].concat(otherArgs)) : - $.datepicker._attachDatepicker(this, options); - }); -}; - -$.datepicker = new Datepicker(); // singleton instance -$.datepicker.initialized = false; -$.datepicker.uuid = new Date().getTime(); -$.datepicker.version = "1.9.2"; - -// Workaround for #4055 -// Add another global to avoid noConflict issues with inline event handlers -window['DP_jQuery_' + dpuuid] = $; - -})(jQuery); - -(function( $, undefined ) { - -var uiDialogClasses = "ui-dialog ui-widget ui-widget-content ui-corner-all ", - sizeRelatedOptions = { - buttons: true, - height: true, - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true, - width: true - }, - resizableRelatedOptions = { - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true - }; - -$.widget("ui.dialog", { - version: "1.9.2", - options: { - autoOpen: true, - buttons: {}, - closeOnEscape: true, - closeText: "close", - dialogClass: "", - draggable: true, - hide: null, - height: "auto", - maxHeight: false, - maxWidth: false, - minHeight: 150, - minWidth: 150, - modal: false, - position: { - my: "center", - at: "center", - of: window, - collision: "fit", - // ensure that the titlebar is never outside the document - using: function( pos ) { - var topOffset = $( this ).css( pos ).offset().top; - if ( topOffset < 0 ) { - $( this ).css( "top", pos.top - topOffset ); - } - } - }, - resizable: true, - show: null, - stack: true, - title: "", - width: 300, - zIndex: 1000 - }, - - _create: function() { - this.originalTitle = this.element.attr( "title" ); - // #5742 - .attr() might return a DOMElement - if ( typeof this.originalTitle !== "string" ) { - this.originalTitle = ""; - } - this.oldPosition = { - parent: this.element.parent(), - index: this.element.parent().children().index( this.element ) - }; - this.options.title = this.options.title || this.originalTitle; - var that = this, - options = this.options, - - title = options.title || " ", - uiDialog, - uiDialogTitlebar, - uiDialogTitlebarClose, - uiDialogTitle, - uiDialogButtonPane; - - uiDialog = ( this.uiDialog = $( "<div>" ) ) - .addClass( uiDialogClasses + options.dialogClass ) - .css({ - display: "none", - outline: 0, // TODO: move to stylesheet - zIndex: options.zIndex - }) - // setting tabIndex makes the div focusable - .attr( "tabIndex", -1) - .keydown(function( event ) { - if ( options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE ) { - that.close( event ); - event.preventDefault(); - } - }) - .mousedown(function( event ) { - that.moveToTop( false, event ); - }) - .appendTo( "body" ); - - this.element - .show() - .removeAttr( "title" ) - .addClass( "ui-dialog-content ui-widget-content" ) - .appendTo( uiDialog ); - - uiDialogTitlebar = ( this.uiDialogTitlebar = $( "<div>" ) ) - .addClass( "ui-dialog-titlebar ui-widget-header " + - "ui-corner-all ui-helper-clearfix" ) - .bind( "mousedown", function() { - // Dialog isn't getting focus when dragging (#8063) - uiDialog.focus(); - }) - .prependTo( uiDialog ); - - uiDialogTitlebarClose = $( "<a href='#'></a>" ) - .addClass( "ui-dialog-titlebar-close ui-corner-all" ) - .attr( "role", "button" ) - .click(function( event ) { - event.preventDefault(); - that.close( event ); - }) - .appendTo( uiDialogTitlebar ); - - ( this.uiDialogTitlebarCloseText = $( "<span>" ) ) - .addClass( "ui-icon ui-icon-closethick" ) - .text( options.closeText ) - .appendTo( uiDialogTitlebarClose ); - - uiDialogTitle = $( "<span>" ) - .uniqueId() - .addClass( "ui-dialog-title" ) - .html( title ) - .prependTo( uiDialogTitlebar ); - - uiDialogButtonPane = ( this.uiDialogButtonPane = $( "<div>" ) ) - .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ); - - ( this.uiButtonSet = $( "<div>" ) ) - .addClass( "ui-dialog-buttonset" ) - .appendTo( uiDialogButtonPane ); - - uiDialog.attr({ - role: "dialog", - "aria-labelledby": uiDialogTitle.attr( "id" ) - }); - - uiDialogTitlebar.find( "*" ).add( uiDialogTitlebar ).disableSelection(); - this._hoverable( uiDialogTitlebarClose ); - this._focusable( uiDialogTitlebarClose ); - - if ( options.draggable && $.fn.draggable ) { - this._makeDraggable(); - } - if ( options.resizable && $.fn.resizable ) { - this._makeResizable(); - } - - this._createButtons( options.buttons ); - this._isOpen = false; - - if ( $.fn.bgiframe ) { - uiDialog.bgiframe(); - } - - // prevent tabbing out of modal dialogs - this._on( uiDialog, { keydown: function( event ) { - if ( !options.modal || event.keyCode !== $.ui.keyCode.TAB ) { - return; - } - - var tabbables = $( ":tabbable", uiDialog ), - first = tabbables.filter( ":first" ), - last = tabbables.filter( ":last" ); - - if ( event.target === last[0] && !event.shiftKey ) { - first.focus( 1 ); - return false; - } else if ( event.target === first[0] && event.shiftKey ) { - last.focus( 1 ); - return false; - } - }}); - }, - - _init: function() { - if ( this.options.autoOpen ) { - this.open(); - } - }, - - _destroy: function() { - var next, - oldPosition = this.oldPosition; - - if ( this.overlay ) { - this.overlay.destroy(); - } - this.uiDialog.hide(); - this.element - .removeClass( "ui-dialog-content ui-widget-content" ) - .hide() - .appendTo( "body" ); - this.uiDialog.remove(); - - if ( this.originalTitle ) { - this.element.attr( "title", this.originalTitle ); - } - - next = oldPosition.parent.children().eq( oldPosition.index ); - // Don't try to place the dialog next to itself (#8613) - if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { - next.before( this.element ); - } else { - oldPosition.parent.append( this.element ); - } - }, - - widget: function() { - return this.uiDialog; - }, - - close: function( event ) { - var that = this, - maxZ, thisZ; - - if ( !this._isOpen ) { - return; - } - - if ( false === this._trigger( "beforeClose", event ) ) { - return; - } - - this._isOpen = false; - - if ( this.overlay ) { - this.overlay.destroy(); - } - - if ( this.options.hide ) { - this._hide( this.uiDialog, this.options.hide, function() { - that._trigger( "close", event ); - }); - } else { - this.uiDialog.hide(); - this._trigger( "close", event ); - } - - $.ui.dialog.overlay.resize(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - if ( this.options.modal ) { - maxZ = 0; - $( ".ui-dialog" ).each(function() { - if ( this !== that.uiDialog[0] ) { - thisZ = $( this ).css( "z-index" ); - if ( !isNaN( thisZ ) ) { - maxZ = Math.max( maxZ, thisZ ); - } - } - }); - $.ui.dialog.maxZ = maxZ; - } - - return this; - }, - - isOpen: function() { - return this._isOpen; - }, - - // the force parameter allows us to move modal dialogs to their correct - // position on open - moveToTop: function( force, event ) { - var options = this.options, - saveScroll; - - if ( ( options.modal && !force ) || - ( !options.stack && !options.modal ) ) { - return this._trigger( "focus", event ); - } - - if ( options.zIndex > $.ui.dialog.maxZ ) { - $.ui.dialog.maxZ = options.zIndex; - } - if ( this.overlay ) { - $.ui.dialog.maxZ += 1; - $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ; - this.overlay.$el.css( "z-index", $.ui.dialog.overlay.maxZ ); - } - - // Save and then restore scroll - // Opera 9.5+ resets when parent z-index is changed. - // http://bugs.jqueryui.com/ticket/3193 - saveScroll = { - scrollTop: this.element.scrollTop(), - scrollLeft: this.element.scrollLeft() - }; - $.ui.dialog.maxZ += 1; - this.uiDialog.css( "z-index", $.ui.dialog.maxZ ); - this.element.attr( saveScroll ); - this._trigger( "focus", event ); - - return this; - }, - - open: function() { - if ( this._isOpen ) { - return; - } - - var hasFocus, - options = this.options, - uiDialog = this.uiDialog; - - this._size(); - this._position( options.position ); - uiDialog.show( options.show ); - this.overlay = options.modal ? new $.ui.dialog.overlay( this ) : null; - this.moveToTop( true ); - - // set focus to the first tabbable element in the content area or the first button - // if there are no tabbable elements, set focus on the dialog itself - hasFocus = this.element.find( ":tabbable" ); - if ( !hasFocus.length ) { - hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); - if ( !hasFocus.length ) { - hasFocus = uiDialog; - } - } - hasFocus.eq( 0 ).focus(); - - this._isOpen = true; - this._trigger( "open" ); - - return this; - }, - - _createButtons: function( buttons ) { - var that = this, - hasButtons = false; - - // if we already have a button pane, remove it - this.uiDialogButtonPane.remove(); - this.uiButtonSet.empty(); - - if ( typeof buttons === "object" && buttons !== null ) { - $.each( buttons, function() { - return !(hasButtons = true); - }); - } - if ( hasButtons ) { - $.each( buttons, function( name, props ) { - var button, click; - props = $.isFunction( props ) ? - { click: props, text: name } : - props; - // Default to a non-submitting button - props = $.extend( { type: "button" }, props ); - // Change the context for the click callback to be the main element - click = props.click; - props.click = function() { - click.apply( that.element[0], arguments ); - }; - button = $( "<button></button>", props ) - .appendTo( that.uiButtonSet ); - if ( $.fn.button ) { - button.button(); - } - }); - this.uiDialog.addClass( "ui-dialog-buttons" ); - this.uiDialogButtonPane.appendTo( this.uiDialog ); - } else { - this.uiDialog.removeClass( "ui-dialog-buttons" ); - } - }, - - _makeDraggable: function() { - var that = this, - options = this.options; - - function filteredUi( ui ) { - return { - position: ui.position, - offset: ui.offset - }; - } - - this.uiDialog.draggable({ - cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", - handle: ".ui-dialog-titlebar", - containment: "document", - start: function( event, ui ) { - $( this ) - .addClass( "ui-dialog-dragging" ); - that._trigger( "dragStart", event, filteredUi( ui ) ); - }, - drag: function( event, ui ) { - that._trigger( "drag", event, filteredUi( ui ) ); - }, - stop: function( event, ui ) { - options.position = [ - ui.position.left - that.document.scrollLeft(), - ui.position.top - that.document.scrollTop() - ]; - $( this ) - .removeClass( "ui-dialog-dragging" ); - that._trigger( "dragStop", event, filteredUi( ui ) ); - $.ui.dialog.overlay.resize(); - } - }); - }, - - _makeResizable: function( handles ) { - handles = (handles === undefined ? this.options.resizable : handles); - var that = this, - options = this.options, - // .ui-resizable has position: relative defined in the stylesheet - // but dialogs have to use absolute or fixed positioning - position = this.uiDialog.css( "position" ), - resizeHandles = typeof handles === 'string' ? - handles : - "n,e,s,w,se,sw,ne,nw"; - - function filteredUi( ui ) { - return { - originalPosition: ui.originalPosition, - originalSize: ui.originalSize, - position: ui.position, - size: ui.size - }; - } - - this.uiDialog.resizable({ - cancel: ".ui-dialog-content", - containment: "document", - alsoResize: this.element, - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - minWidth: options.minWidth, - minHeight: this._minHeight(), - handles: resizeHandles, - start: function( event, ui ) { - $( this ).addClass( "ui-dialog-resizing" ); - that._trigger( "resizeStart", event, filteredUi( ui ) ); - }, - resize: function( event, ui ) { - that._trigger( "resize", event, filteredUi( ui ) ); - }, - stop: function( event, ui ) { - $( this ).removeClass( "ui-dialog-resizing" ); - options.height = $( this ).height(); - options.width = $( this ).width(); - that._trigger( "resizeStop", event, filteredUi( ui ) ); - $.ui.dialog.overlay.resize(); - } - }) - .css( "position", position ) - .find( ".ui-resizable-se" ) - .addClass( "ui-icon ui-icon-grip-diagonal-se" ); - }, - - _minHeight: function() { - var options = this.options; - - if ( options.height === "auto" ) { - return options.minHeight; - } else { - return Math.min( options.minHeight, options.height ); - } - }, - - _position: function( position ) { - var myAt = [], - offset = [ 0, 0 ], - isVisible; - - if ( position ) { - // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( - // if (typeof position == 'string' || $.isArray(position)) { - // myAt = $.isArray(position) ? position : position.split(' '); - - if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { - myAt = position.split ? position.split( " " ) : [ position[ 0 ], position[ 1 ] ]; - if ( myAt.length === 1 ) { - myAt[ 1 ] = myAt[ 0 ]; - } - - $.each( [ "left", "top" ], function( i, offsetPosition ) { - if ( +myAt[ i ] === myAt[ i ] ) { - offset[ i ] = myAt[ i ]; - myAt[ i ] = offsetPosition; - } - }); - - position = { - my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + - myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), - at: myAt.join( " " ) - }; - } - - position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); - } else { - position = $.ui.dialog.prototype.options.position; - } - - // need to show the dialog to get the actual offset in the position plugin - isVisible = this.uiDialog.is( ":visible" ); - if ( !isVisible ) { - this.uiDialog.show(); - } - this.uiDialog.position( position ); - if ( !isVisible ) { - this.uiDialog.hide(); - } - }, - - _setOptions: function( options ) { - var that = this, - resizableOptions = {}, - resize = false; - - $.each( options, function( key, value ) { - that._setOption( key, value ); - - if ( key in sizeRelatedOptions ) { - resize = true; - } - if ( key in resizableRelatedOptions ) { - resizableOptions[ key ] = value; - } - }); - - if ( resize ) { - this._size(); - } - if ( this.uiDialog.is( ":data(resizable)" ) ) { - this.uiDialog.resizable( "option", resizableOptions ); - } - }, - - _setOption: function( key, value ) { - var isDraggable, isResizable, - uiDialog = this.uiDialog; - - switch ( key ) { - case "buttons": - this._createButtons( value ); - break; - case "closeText": - // ensure that we always pass a string - this.uiDialogTitlebarCloseText.text( "" + value ); - break; - case "dialogClass": - uiDialog - .removeClass( this.options.dialogClass ) - .addClass( uiDialogClasses + value ); - break; - case "disabled": - if ( value ) { - uiDialog.addClass( "ui-dialog-disabled" ); - } else { - uiDialog.removeClass( "ui-dialog-disabled" ); - } - break; - case "draggable": - isDraggable = uiDialog.is( ":data(draggable)" ); - if ( isDraggable && !value ) { - uiDialog.draggable( "destroy" ); - } - - if ( !isDraggable && value ) { - this._makeDraggable(); - } - break; - case "position": - this._position( value ); - break; - case "resizable": - // currently resizable, becoming non-resizable - isResizable = uiDialog.is( ":data(resizable)" ); - if ( isResizable && !value ) { - uiDialog.resizable( "destroy" ); - } - - // currently resizable, changing handles - if ( isResizable && typeof value === "string" ) { - uiDialog.resizable( "option", "handles", value ); - } - - // currently non-resizable, becoming resizable - if ( !isResizable && value !== false ) { - this._makeResizable( value ); - } - break; - case "title": - // convert whatever was passed in o a string, for html() to not throw up - $( ".ui-dialog-title", this.uiDialogTitlebar ) - .html( "" + ( value || " " ) ); - break; - } - - this._super( key, value ); - }, - - _size: function() { - /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - * divs will both have width and height set, so we need to reset them - */ - var nonContentHeight, minContentHeight, autoHeight, - options = this.options, - isVisible = this.uiDialog.is( ":visible" ); - - // reset content sizing - this.element.show().css({ - width: "auto", - minHeight: 0, - height: 0 - }); - - if ( options.minWidth > options.width ) { - options.width = options.minWidth; - } - - // reset wrapper sizing - // determine the height of all the non-content elements - nonContentHeight = this.uiDialog.css({ - height: "auto", - width: options.width - }) - .outerHeight(); - minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); - - if ( options.height === "auto" ) { - // only needed for IE6 support - if ( $.support.minHeight ) { - this.element.css({ - minHeight: minContentHeight, - height: "auto" - }); - } else { - this.uiDialog.show(); - autoHeight = this.element.css( "height", "auto" ).height(); - if ( !isVisible ) { - this.uiDialog.hide(); - } - this.element.height( Math.max( autoHeight, minContentHeight ) ); - } - } else { - this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); - } - - if (this.uiDialog.is( ":data(resizable)" ) ) { - this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); - } - } -}); - -$.extend($.ui.dialog, { - uuid: 0, - maxZ: 0, - - getTitleId: function($el) { - var id = $el.attr( "id" ); - if ( !id ) { - this.uuid += 1; - id = this.uuid; - } - return "ui-dialog-title-" + id; - }, - - overlay: function( dialog ) { - this.$el = $.ui.dialog.overlay.create( dialog ); - } -}); - -$.extend( $.ui.dialog.overlay, { - instances: [], - // reuse old instances due to IE memory leak with alpha transparency (see #5185) - oldInstances: [], - maxZ: 0, - events: $.map( - "focus,mousedown,mouseup,keydown,keypress,click".split( "," ), - function( event ) { - return event + ".dialog-overlay"; - } - ).join( " " ), - create: function( dialog ) { - if ( this.instances.length === 0 ) { - // prevent use of anchors and inputs - // we use a setTimeout in case the overlay is created from an - // event that we're going to be cancelling (see #2804) - setTimeout(function() { - // handle $(el).dialog().dialog('close') (see #4065) - if ( $.ui.dialog.overlay.instances.length ) { - $( document ).bind( $.ui.dialog.overlay.events, function( event ) { - // stop events if the z-index of the target is < the z-index of the overlay - // we cannot return true when we don't want to cancel the event (#3523) - if ( $( event.target ).zIndex() < $.ui.dialog.overlay.maxZ ) { - return false; - } - }); - } - }, 1 ); - - // handle window resize - $( window ).bind( "resize.dialog-overlay", $.ui.dialog.overlay.resize ); - } - - var $el = ( this.oldInstances.pop() || $( "<div>" ).addClass( "ui-widget-overlay" ) ); - - // allow closing by pressing the escape key - $( document ).bind( "keydown.dialog-overlay", function( event ) { - var instances = $.ui.dialog.overlay.instances; - // only react to the event if we're the top overlay - if ( instances.length !== 0 && instances[ instances.length - 1 ] === $el && - dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE ) { - - dialog.close( event ); - event.preventDefault(); - } - }); - - $el.appendTo( document.body ).css({ - width: this.width(), - height: this.height() - }); - - if ( $.fn.bgiframe ) { - $el.bgiframe(); - } - - this.instances.push( $el ); - return $el; - }, - - destroy: function( $el ) { - var indexOf = $.inArray( $el, this.instances ), - maxZ = 0; - - if ( indexOf !== -1 ) { - this.oldInstances.push( this.instances.splice( indexOf, 1 )[ 0 ] ); - } - - if ( this.instances.length === 0 ) { - $( [ document, window ] ).unbind( ".dialog-overlay" ); - } - - $el.height( 0 ).width( 0 ).remove(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - $.each( this.instances, function() { - maxZ = Math.max( maxZ, this.css( "z-index" ) ); - }); - this.maxZ = maxZ; - }, - - height: function() { - var scrollHeight, - offsetHeight; - // handle IE - if ( $.ui.ie ) { - scrollHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight - ); - offsetHeight = Math.max( - document.documentElement.offsetHeight, - document.body.offsetHeight - ); - - if ( scrollHeight < offsetHeight ) { - return $( window ).height() + "px"; - } else { - return scrollHeight + "px"; - } - // handle "good" browsers - } else { - return $( document ).height() + "px"; - } - }, - - width: function() { - var scrollWidth, - offsetWidth; - // handle IE - if ( $.ui.ie ) { - scrollWidth = Math.max( - document.documentElement.scrollWidth, - document.body.scrollWidth - ); - offsetWidth = Math.max( - document.documentElement.offsetWidth, - document.body.offsetWidth - ); - - if ( scrollWidth < offsetWidth ) { - return $( window ).width() + "px"; - } else { - return scrollWidth + "px"; - } - // handle "good" browsers - } else { - return $( document ).width() + "px"; - } - }, - - resize: function() { - /* If the dialog is draggable and the user drags it past the - * right edge of the window, the document becomes wider so we - * need to stretch the overlay. If the user then drags the - * dialog back to the left, the document will become narrower, - * so we need to shrink the overlay to the appropriate size. - * This is handled by shrinking the overlay before setting it - * to the full document size. - */ - var $overlays = $( [] ); - $.each( $.ui.dialog.overlay.instances, function() { - $overlays = $overlays.add( this ); - }); - - $overlays.css({ - width: 0, - height: 0 - }).css({ - width: $.ui.dialog.overlay.width(), - height: $.ui.dialog.overlay.height() - }); - } -}); - -$.extend( $.ui.dialog.overlay.prototype, { - destroy: function() { - $.ui.dialog.overlay.destroy( this.$el ); - } -}); - -}( jQuery ) ); - -(function( $, undefined ) { - -var rvertical = /up|down|vertical/, - rpositivemotion = /up|left|vertical|horizontal/; - -$.effects.effect.blind = function( o, done ) { - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - direction = o.direction || "up", - vertical = rvertical.test( direction ), - ref = vertical ? "height" : "width", - ref2 = vertical ? "top" : "left", - motion = rpositivemotion.test( direction ), - animation = {}, - show = mode === "show", - wrapper, distance, margin; - - // if already wrapped, the wrapper's properties are my property. #6245 - if ( el.parent().is( ".ui-effects-wrapper" ) ) { - $.effects.save( el.parent(), props ); - } else { - $.effects.save( el, props ); - } - el.show(); - wrapper = $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - - distance = wrapper[ ref ](); - margin = parseFloat( wrapper.css( ref2 ) ) || 0; - - animation[ ref ] = show ? distance : 0; - if ( !motion ) { - el - .css( vertical ? "bottom" : "right", 0 ) - .css( vertical ? "top" : "left", "auto" ) - .css({ position: "absolute" }); - - animation[ ref2 ] = show ? margin : distance + margin; - } - - // start at 0 if we are showing - if ( show ) { - wrapper.css( ref, 0 ); - if ( ! motion ) { - wrapper.css( ref2, margin + distance ); - } - } - - // Animate - wrapper.animate( animation, { - duration: o.duration, - easing: o.easing, - queue: false, - complete: function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); - -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.bounce = function( o, done ) { - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - - // defaults: - mode = $.effects.setMode( el, o.mode || "effect" ), - hide = mode === "hide", - show = mode === "show", - direction = o.direction || "up", - distance = o.distance, - times = o.times || 5, - - // number of internal animations - anims = times * 2 + ( show || hide ? 1 : 0 ), - speed = o.duration / anims, - easing = o.easing, - - // utility: - ref = ( direction === "up" || direction === "down" ) ? "top" : "left", - motion = ( direction === "up" || direction === "left" ), - i, - upAnim, - downAnim, - - // we will need to re-assemble the queue to stack our animations in place - queue = el.queue(), - queuelen = queue.length; - - // Avoid touching opacity to prevent clearType and PNG issues in IE - if ( show || hide ) { - props.push( "opacity" ); - } - - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); // Create Wrapper - - // default distance for the BIGGEST bounce is the outer Distance / 3 - if ( !distance ) { - distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; - } - - if ( show ) { - downAnim = { opacity: 1 }; - downAnim[ ref ] = 0; - - // if we are showing, force opacity 0 and set the initial position - // then do the "first" animation - el.css( "opacity", 0 ) - .css( ref, motion ? -distance * 2 : distance * 2 ) - .animate( downAnim, speed, easing ); - } - - // start at the smallest distance if we are hiding - if ( hide ) { - distance = distance / Math.pow( 2, times - 1 ); - } - - downAnim = {}; - downAnim[ ref ] = 0; - // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here - for ( i = 0; i < times; i++ ) { - upAnim = {}; - upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; - - el.animate( upAnim, speed, easing ) - .animate( downAnim, speed, easing ); - - distance = hide ? distance * 2 : distance / 2; - } - - // Last Bounce when Hiding - if ( hide ) { - upAnim = { opacity: 0 }; - upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; - - el.animate( upAnim, speed, easing ); - } - - el.queue(function() { - if ( hide ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - }); - - // inject all the animations we just queued to be first in line (after "inprogress") - if ( queuelen > 1) { - queue.splice.apply( queue, - [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); - } - el.dequeue(); - -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.clip = function( o, done ) { - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - direction = o.direction || "vertical", - vert = direction === "vertical", - size = vert ? "height" : "width", - position = vert ? "top" : "left", - animation = {}, - wrapper, animate, distance; - - // Save & Show - $.effects.save( el, props ); - el.show(); - - // Create Wrapper - wrapper = $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - animate = ( el[0].tagName === "IMG" ) ? wrapper : el; - distance = animate[ size ](); - - // Shift - if ( show ) { - animate.css( size, 0 ); - animate.css( position, distance / 2 ); - } - - // Create Animation Object: - animation[ size ] = show ? distance : 0; - animation[ position ] = show ? 0 : distance / 2; - - // Animate - animate.animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( !show ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); - -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.drop = function( o, done ) { - - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - direction = o.direction || "left", - ref = ( direction === "up" || direction === "down" ) ? "top" : "left", - motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", - animation = { - opacity: show ? 1 : 0 - }, - distance; - - // Adjust - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); - - distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2; - - if ( show ) { - el - .css( "opacity", 0 ) - .css( ref, motion === "pos" ? -distance : distance ); - } - - // Animation - animation[ ref ] = ( show ? - ( motion === "pos" ? "+=" : "-=" ) : - ( motion === "pos" ? "-=" : "+=" ) ) + - distance; - - // Animate - el.animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.explode = function( o, done ) { - - var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, - cells = rows, - el = $( this ), - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - - // show and then visibility:hidden the element before calculating offset - offset = el.show().css( "visibility", "hidden" ).offset(), - - // width and height of a piece - width = Math.ceil( el.outerWidth() / cells ), - height = Math.ceil( el.outerHeight() / rows ), - pieces = [], - - // loop - i, j, left, top, mx, my; - - // children animate complete: - function childComplete() { - pieces.push( this ); - if ( pieces.length === rows * cells ) { - animComplete(); - } - } - - // clone the element for each row and cell. - for( i = 0; i < rows ; i++ ) { // ===> - top = offset.top + i * height; - my = i - ( rows - 1 ) / 2 ; - - for( j = 0; j < cells ; j++ ) { // ||| - left = offset.left + j * width; - mx = j - ( cells - 1 ) / 2 ; - - // Create a clone of the now hidden main element that will be absolute positioned - // within a wrapper div off the -left and -top equal to size of our pieces - el - .clone() - .appendTo( "body" ) - .wrap( "<div></div>" ) - .css({ - position: "absolute", - visibility: "visible", - left: -j * width, - top: -i * height - }) - - // select the wrapper - make it overflow: hidden and absolute positioned based on - // where the original was located +left and +top equal to the size of pieces - .parent() - .addClass( "ui-effects-explode" ) - .css({ - position: "absolute", - overflow: "hidden", - width: width, - height: height, - left: left + ( show ? mx * width : 0 ), - top: top + ( show ? my * height : 0 ), - opacity: show ? 0 : 1 - }).animate({ - left: left + ( show ? 0 : mx * width ), - top: top + ( show ? 0 : my * height ), - opacity: show ? 1 : 0 - }, o.duration || 500, o.easing, childComplete ); - } - } - - function animComplete() { - el.css({ - visibility: "visible" - }); - $( pieces ).remove(); - if ( !show ) { - el.hide(); - } - done(); - } -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.fade = function( o, done ) { - var el = $( this ), - mode = $.effects.setMode( el, o.mode || "toggle" ); - - el.animate({ - opacity: mode - }, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: done - }); -}; - -})( jQuery ); - -(function( $, undefined ) { - -$.effects.effect.fold = function( o, done ) { - - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "hide" ), - show = mode === "show", - hide = mode === "hide", - size = o.size || 15, - percent = /([0-9]+)%/.exec( size ), - horizFirst = !!o.horizFirst, - widthFirst = show !== horizFirst, - ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], - duration = o.duration / 2, - wrapper, distance, - animation1 = {}, - animation2 = {}; - - $.effects.save( el, props ); - el.show(); - - // Create Wrapper - wrapper = $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - distance = widthFirst ? - [ wrapper.width(), wrapper.height() ] : - [ wrapper.height(), wrapper.width() ]; - - if ( percent ) { - size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; - } - if ( show ) { - wrapper.css( horizFirst ? { - height: 0, - width: size - } : { - height: size, - width: 0 - }); - } - - // Animation - animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; - animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; - - // Animate - wrapper - .animate( animation1, duration, o.easing ) - .animate( animation2, duration, o.easing, function() { - if ( hide ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - }); - -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.highlight = function( o, done ) { - var elem = $( this ), - props = [ "backgroundImage", "backgroundColor", "opacity" ], - mode = $.effects.setMode( elem, o.mode || "show" ), - animation = { - backgroundColor: elem.css( "backgroundColor" ) - }; - - if (mode === "hide") { - animation.opacity = 0; - } - - $.effects.save( elem, props ); - - elem - .show() - .css({ - backgroundImage: "none", - backgroundColor: o.color || "#ffff99" - }) - .animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( mode === "hide" ) { - elem.hide(); - } - $.effects.restore( elem, props ); - done(); - } - }); -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.pulsate = function( o, done ) { - var elem = $( this ), - mode = $.effects.setMode( elem, o.mode || "show" ), - show = mode === "show", - hide = mode === "hide", - showhide = ( show || mode === "hide" ), - - // showing or hiding leaves of the "last" animation - anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), - duration = o.duration / anims, - animateTo = 0, - queue = elem.queue(), - queuelen = queue.length, - i; - - if ( show || !elem.is(":visible")) { - elem.css( "opacity", 0 ).show(); - animateTo = 1; - } - - // anims - 1 opacity "toggles" - for ( i = 1; i < anims; i++ ) { - elem.animate({ - opacity: animateTo - }, duration, o.easing ); - animateTo = 1 - animateTo; - } - - elem.animate({ - opacity: animateTo - }, duration, o.easing); - - elem.queue(function() { - if ( hide ) { - elem.hide(); - } - done(); - }); - - // We just queued up "anims" animations, we need to put them next in the queue - if ( queuelen > 1 ) { - queue.splice.apply( queue, - [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); - } - elem.dequeue(); -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.puff = function( o, done ) { - var elem = $( this ), - mode = $.effects.setMode( elem, o.mode || "hide" ), - hide = mode === "hide", - percent = parseInt( o.percent, 10 ) || 150, - factor = percent / 100, - original = { - height: elem.height(), - width: elem.width(), - outerHeight: elem.outerHeight(), - outerWidth: elem.outerWidth() - }; - - $.extend( o, { - effect: "scale", - queue: false, - fade: true, - mode: mode, - complete: done, - percent: hide ? percent : 100, - from: hide ? - original : - { - height: original.height * factor, - width: original.width * factor, - outerHeight: original.outerHeight * factor, - outerWidth: original.outerWidth * factor - } - }); - - elem.effect( o ); -}; - -$.effects.effect.scale = function( o, done ) { - - // Create element - var el = $( this ), - options = $.extend( true, {}, o ), - mode = $.effects.setMode( el, o.mode || "effect" ), - percent = parseInt( o.percent, 10 ) || - ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), - direction = o.direction || "both", - origin = o.origin, - original = { - height: el.height(), - width: el.width(), - outerHeight: el.outerHeight(), - outerWidth: el.outerWidth() - }, - factor = { - y: direction !== "horizontal" ? (percent / 100) : 1, - x: direction !== "vertical" ? (percent / 100) : 1 - }; - - // We are going to pass this effect to the size effect: - options.effect = "size"; - options.queue = false; - options.complete = done; - - // Set default origin and restore for show/hide - if ( mode !== "effect" ) { - options.origin = origin || ["middle","center"]; - options.restore = true; - } - - options.from = o.from || ( mode === "show" ? { - height: 0, - width: 0, - outerHeight: 0, - outerWidth: 0 - } : original ); - options.to = { - height: original.height * factor.y, - width: original.width * factor.x, - outerHeight: original.outerHeight * factor.y, - outerWidth: original.outerWidth * factor.x - }; - - // Fade option to support puff - if ( options.fade ) { - if ( mode === "show" ) { - options.from.opacity = 0; - options.to.opacity = 1; - } - if ( mode === "hide" ) { - options.from.opacity = 1; - options.to.opacity = 0; - } - } - - // Animate - el.effect( options ); - -}; - -$.effects.effect.size = function( o, done ) { - - // Create element - var original, baseline, factor, - el = $( this ), - props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], - - // Always restore - props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], - - // Copy for children - props2 = [ "width", "height", "overflow" ], - cProps = [ "fontSize" ], - vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], - hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], - - // Set options - mode = $.effects.setMode( el, o.mode || "effect" ), - restore = o.restore || mode !== "effect", - scale = o.scale || "both", - origin = o.origin || [ "middle", "center" ], - position = el.css( "position" ), - props = restore ? props0 : props1, - zero = { - height: 0, - width: 0, - outerHeight: 0, - outerWidth: 0 - }; - - if ( mode === "show" ) { - el.show(); - } - original = { - height: el.height(), - width: el.width(), - outerHeight: el.outerHeight(), - outerWidth: el.outerWidth() - }; - - if ( o.mode === "toggle" && mode === "show" ) { - el.from = o.to || zero; - el.to = o.from || original; - } else { - el.from = o.from || ( mode === "show" ? zero : original ); - el.to = o.to || ( mode === "hide" ? zero : original ); - } - - // Set scaling factor - factor = { - from: { - y: el.from.height / original.height, - x: el.from.width / original.width - }, - to: { - y: el.to.height / original.height, - x: el.to.width / original.width - } - }; - - // Scale the css box - if ( scale === "box" || scale === "both" ) { - - // Vertical props scaling - if ( factor.from.y !== factor.to.y ) { - props = props.concat( vProps ); - el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); - el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); - } - - // Horizontal props scaling - if ( factor.from.x !== factor.to.x ) { - props = props.concat( hProps ); - el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); - el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); - } - } - - // Scale the content - if ( scale === "content" || scale === "both" ) { - - // Vertical props scaling - if ( factor.from.y !== factor.to.y ) { - props = props.concat( cProps ).concat( props2 ); - el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); - el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); - } - } - - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); - el.css( "overflow", "hidden" ).css( el.from ); - - // Adjust - if (origin) { // Calculate baseline shifts - baseline = $.effects.getBaseline( origin, original ); - el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; - el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; - el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; - el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; - } - el.css( el.from ); // set top & left - - // Animate - if ( scale === "content" || scale === "both" ) { // Scale the children - - // Add margins/font-size - vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); - hProps = hProps.concat([ "marginLeft", "marginRight" ]); - props2 = props0.concat(vProps).concat(hProps); - - el.find( "*[width]" ).each( function(){ - var child = $( this ), - c_original = { - height: child.height(), - width: child.width(), - outerHeight: child.outerHeight(), - outerWidth: child.outerWidth() - }; - if (restore) { - $.effects.save(child, props2); - } - - child.from = { - height: c_original.height * factor.from.y, - width: c_original.width * factor.from.x, - outerHeight: c_original.outerHeight * factor.from.y, - outerWidth: c_original.outerWidth * factor.from.x - }; - child.to = { - height: c_original.height * factor.to.y, - width: c_original.width * factor.to.x, - outerHeight: c_original.height * factor.to.y, - outerWidth: c_original.width * factor.to.x - }; - - // Vertical props scaling - if ( factor.from.y !== factor.to.y ) { - child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); - child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); - } - - // Horizontal props scaling - if ( factor.from.x !== factor.to.x ) { - child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); - child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); - } - - // Animate children - child.css( child.from ); - child.animate( child.to, o.duration, o.easing, function() { - - // Restore children - if ( restore ) { - $.effects.restore( child, props2 ); - } - }); - }); - } - - // Animate - el.animate( el.to, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( el.to.opacity === 0 ) { - el.css( "opacity", el.from.opacity ); - } - if( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - if ( !restore ) { - - // we need to calculate our new positioning based on the scaling - if ( position === "static" ) { - el.css({ - position: "relative", - top: el.to.top, - left: el.to.left - }); - } else { - $.each([ "top", "left" ], function( idx, pos ) { - el.css( pos, function( _, str ) { - var val = parseInt( str, 10 ), - toRef = idx ? el.to.left : el.to.top; - - // if original was "auto", recalculate the new value from wrapper - if ( str === "auto" ) { - return toRef + "px"; - } - - return val + toRef + "px"; - }); - }); - } - } - - $.effects.removeWrapper( el ); - done(); - } - }); - -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.shake = function( o, done ) { - - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "height", "width" ], - mode = $.effects.setMode( el, o.mode || "effect" ), - direction = o.direction || "left", - distance = o.distance || 20, - times = o.times || 3, - anims = times * 2 + 1, - speed = Math.round(o.duration/anims), - ref = (direction === "up" || direction === "down") ? "top" : "left", - positiveMotion = (direction === "up" || direction === "left"), - animation = {}, - animation1 = {}, - animation2 = {}, - i, - - // we will need to re-assemble the queue to stack our animations in place - queue = el.queue(), - queuelen = queue.length; - - $.effects.save( el, props ); - el.show(); - $.effects.createWrapper( el ); - - // Animation - animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; - animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; - animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; - - // Animate - el.animate( animation, speed, o.easing ); - - // Shakes - for ( i = 1; i < times; i++ ) { - el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); - } - el - .animate( animation1, speed, o.easing ) - .animate( animation, speed / 2, o.easing ) - .queue(function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - }); - - // inject all the animations we just queued to be first in line (after "inprogress") - if ( queuelen > 1) { - queue.splice.apply( queue, - [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); - } - el.dequeue(); - -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.slide = function( o, done ) { - - // Create element - var el = $( this ), - props = [ "position", "top", "bottom", "left", "right", "width", "height" ], - mode = $.effects.setMode( el, o.mode || "show" ), - show = mode === "show", - direction = o.direction || "left", - ref = (direction === "up" || direction === "down") ? "top" : "left", - positiveMotion = (direction === "up" || direction === "left"), - distance, - animation = {}; - - // Adjust - $.effects.save( el, props ); - el.show(); - distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); - - $.effects.createWrapper( el ).css({ - overflow: "hidden" - }); - - if ( show ) { - el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); - } - - // Animation - animation[ ref ] = ( show ? - ( positiveMotion ? "+=" : "-=") : - ( positiveMotion ? "-=" : "+=")) + - distance; - - // Animate - el.animate( animation, { - queue: false, - duration: o.duration, - easing: o.easing, - complete: function() { - if ( mode === "hide" ) { - el.hide(); - } - $.effects.restore( el, props ); - $.effects.removeWrapper( el ); - done(); - } - }); -}; - -})(jQuery); - -(function( $, undefined ) { - -$.effects.effect.transfer = function( o, done ) { - var elem = $( this ), - target = $( o.to ), - targetFixed = target.css( "position" ) === "fixed", - body = $("body"), - fixTop = targetFixed ? body.scrollTop() : 0, - fixLeft = targetFixed ? body.scrollLeft() : 0, - endPosition = target.offset(), - animation = { - top: endPosition.top - fixTop , - left: endPosition.left - fixLeft , - height: target.innerHeight(), - width: target.innerWidth() - }, - startPosition = elem.offset(), - transfer = $( '<div class="ui-effects-transfer"></div>' ) - .appendTo( document.body ) - .addClass( o.className ) - .css({ - top: startPosition.top - fixTop , - left: startPosition.left - fixLeft , - height: elem.innerHeight(), - width: elem.innerWidth(), - position: targetFixed ? "fixed" : "absolute" - }) - .animate( animation, o.duration, o.easing, function() { - transfer.remove(); - done(); - }); -}; - -})(jQuery); - -(function( $, undefined ) { - -var mouseHandled = false; - -$.widget( "ui.menu", { - version: "1.9.2", - defaultElement: "<ul>", - delay: 300, - options: { - icons: { - submenu: "ui-icon-carat-1-e" - }, - menus: "ul", - position: { - my: "left top", - at: "right top" - }, - role: "menu", - - // callbacks - blur: null, - focus: null, - select: null - }, - - _create: function() { - this.activeMenu = this.element; - this.element - .uniqueId() - .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) - .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) - .attr({ - role: this.options.role, - tabIndex: 0 - }) - // need to catch all clicks on disabled menu - // not possible through _on - .bind( "click" + this.eventNamespace, $.proxy(function( event ) { - if ( this.options.disabled ) { - event.preventDefault(); - } - }, this )); - - if ( this.options.disabled ) { - this.element - .addClass( "ui-state-disabled" ) - .attr( "aria-disabled", "true" ); - } - - this._on({ - // Prevent focus from sticking to links inside menu after clicking - // them (focus should always stay on UL during navigation). - "mousedown .ui-menu-item > a": function( event ) { - event.preventDefault(); - }, - "click .ui-state-disabled > a": function( event ) { - event.preventDefault(); - }, - "click .ui-menu-item:has(a)": function( event ) { - var target = $( event.target ).closest( ".ui-menu-item" ); - if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) { - mouseHandled = true; - - this.select( event ); - // Open submenu on click - if ( target.has( ".ui-menu" ).length ) { - this.expand( event ); - } else if ( !this.element.is( ":focus" ) ) { - // Redirect focus to the menu - this.element.trigger( "focus", [ true ] ); - - // If the active item is on the top level, let it stay active. - // Otherwise, blur the active item since it is no longer visible. - if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { - clearTimeout( this.timer ); - } - } - } - }, - "mouseenter .ui-menu-item": function( event ) { - var target = $( event.currentTarget ); - // Remove ui-state-active class from siblings of the newly focused menu item - // to avoid a jump caused by adjacent elements both having a class with a border - target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); - this.focus( event, target ); - }, - mouseleave: "collapseAll", - "mouseleave .ui-menu": "collapseAll", - focus: function( event, keepActiveItem ) { - // If there's already an active item, keep it active - // If not, activate the first item - var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 ); - - if ( !keepActiveItem ) { - this.focus( event, item ); - } - }, - blur: function( event ) { - this._delay(function() { - if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { - this.collapseAll( event ); - } - }); - }, - keydown: "_keydown" - }); - - this.refresh(); - - // Clicks outside of a menu collapse any open menus - this._on( this.document, { - click: function( event ) { - if ( !$( event.target ).closest( ".ui-menu" ).length ) { - this.collapseAll( event ); - } - - // Reset the mouseHandled flag - mouseHandled = false; - } - }); - }, - - _destroy: function() { - // Destroy (sub)menus - this.element - .removeAttr( "aria-activedescendant" ) - .find( ".ui-menu" ).andSelf() - .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" ) - .removeAttr( "role" ) - .removeAttr( "tabIndex" ) - .removeAttr( "aria-labelledby" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-disabled" ) - .removeUniqueId() - .show(); - - // Destroy menu items - this.element.find( ".ui-menu-item" ) - .removeClass( "ui-menu-item" ) - .removeAttr( "role" ) - .removeAttr( "aria-disabled" ) - .children( "a" ) - .removeUniqueId() - .removeClass( "ui-corner-all ui-state-hover" ) - .removeAttr( "tabIndex" ) - .removeAttr( "role" ) - .removeAttr( "aria-haspopup" ) - .children().each( function() { - var elem = $( this ); - if ( elem.data( "ui-menu-submenu-carat" ) ) { - elem.remove(); - } - }); - - // Destroy menu dividers - this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); - }, - - _keydown: function( event ) { - var match, prev, character, skip, regex, - preventDefault = true; - - function escape( value ) { - return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.PAGE_UP: - this.previousPage( event ); - break; - case $.ui.keyCode.PAGE_DOWN: - this.nextPage( event ); - break; - case $.ui.keyCode.HOME: - this._move( "first", "first", event ); - break; - case $.ui.keyCode.END: - this._move( "last", "last", event ); - break; - case $.ui.keyCode.UP: - this.previous( event ); - break; - case $.ui.keyCode.DOWN: - this.next( event ); - break; - case $.ui.keyCode.LEFT: - this.collapse( event ); - break; - case $.ui.keyCode.RIGHT: - if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { - this.expand( event ); - } - break; - case $.ui.keyCode.ENTER: - case $.ui.keyCode.SPACE: - this._activate( event ); - break; - case $.ui.keyCode.ESCAPE: - this.collapse( event ); - break; - default: - preventDefault = false; - prev = this.previousFilter || ""; - character = String.fromCharCode( event.keyCode ); - skip = false; - - clearTimeout( this.filterTimer ); - - if ( character === prev ) { - skip = true; - } else { - character = prev + character; - } - - regex = new RegExp( "^" + escape( character ), "i" ); - match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { - return regex.test( $( this ).children( "a" ).text() ); - }); - match = skip && match.index( this.active.next() ) !== -1 ? - this.active.nextAll( ".ui-menu-item" ) : - match; - - // If no matches on the current filter, reset to the last character pressed - // to move down the menu to the first item that starts with that character - if ( !match.length ) { - character = String.fromCharCode( event.keyCode ); - regex = new RegExp( "^" + escape( character ), "i" ); - match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { - return regex.test( $( this ).children( "a" ).text() ); - }); - } - - if ( match.length ) { - this.focus( event, match ); - if ( match.length > 1 ) { - this.previousFilter = character; - this.filterTimer = this._delay(function() { - delete this.previousFilter; - }, 1000 ); - } else { - delete this.previousFilter; - } - } else { - delete this.previousFilter; - } - } - - if ( preventDefault ) { - event.preventDefault(); - } - }, - - _activate: function( event ) { - if ( !this.active.is( ".ui-state-disabled" ) ) { - if ( this.active.children( "a[aria-haspopup='true']" ).length ) { - this.expand( event ); - } else { - this.select( event ); - } - } - }, - - refresh: function() { - var menus, - icon = this.options.icons.submenu, - submenus = this.element.find( this.options.menus ); - - // Initialize nested menus - submenus.filter( ":not(.ui-menu)" ) - .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) - .hide() - .attr({ - role: this.options.role, - "aria-hidden": "true", - "aria-expanded": "false" - }) - .each(function() { - var menu = $( this ), - item = menu.prev( "a" ), - submenuCarat = $( "<span>" ) - .addClass( "ui-menu-icon ui-icon " + icon ) - .data( "ui-menu-submenu-carat", true ); - - item - .attr( "aria-haspopup", "true" ) - .prepend( submenuCarat ); - menu.attr( "aria-labelledby", item.attr( "id" ) ); - }); - - menus = submenus.add( this.element ); - - // Don't refresh list items that are already adapted - menus.children( ":not(.ui-menu-item):has(a)" ) - .addClass( "ui-menu-item" ) - .attr( "role", "presentation" ) - .children( "a" ) - .uniqueId() - .addClass( "ui-corner-all" ) - .attr({ - tabIndex: -1, - role: this._itemRole() - }); - - // Initialize unlinked menu-items containing spaces and/or dashes only as dividers - menus.children( ":not(.ui-menu-item)" ).each(function() { - var item = $( this ); - // hyphen, em dash, en dash - if ( !/[^\-—–\s]/.test( item.text() ) ) { - item.addClass( "ui-widget-content ui-menu-divider" ); - } - }); - - // Add aria-disabled attribute to any disabled menu item - menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); - - // If the active item has been removed, blur the menu - if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { - this.blur(); - } - }, - - _itemRole: function() { - return { - menu: "menuitem", - listbox: "option" - }[ this.options.role ]; - }, - - focus: function( event, item ) { - var nested, focused; - this.blur( event, event && event.type === "focus" ); - - this._scrollIntoView( item ); - - this.active = item.first(); - focused = this.active.children( "a" ).addClass( "ui-state-focus" ); - // Only update aria-activedescendant if there's a role - // otherwise we assume focus is managed elsewhere - if ( this.options.role ) { - this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); - } - - // Highlight active parent menu item, if any - this.active - .parent() - .closest( ".ui-menu-item" ) - .children( "a:first" ) - .addClass( "ui-state-active" ); - - if ( event && event.type === "keydown" ) { - this._close(); - } else { - this.timer = this._delay(function() { - this._close(); - }, this.delay ); - } - - nested = item.children( ".ui-menu" ); - if ( nested.length && ( /^mouse/.test( event.type ) ) ) { - this._startOpening(nested); - } - this.activeMenu = item.parent(); - - this._trigger( "focus", event, { item: item } ); - }, - - _scrollIntoView: function( item ) { - var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; - if ( this._hasScroll() ) { - borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; - paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; - offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; - scroll = this.activeMenu.scrollTop(); - elementHeight = this.activeMenu.height(); - itemHeight = item.height(); - - if ( offset < 0 ) { - this.activeMenu.scrollTop( scroll + offset ); - } else if ( offset + itemHeight > elementHeight ) { - this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); - } - } - }, - - blur: function( event, fromFocus ) { - if ( !fromFocus ) { - clearTimeout( this.timer ); - } - - if ( !this.active ) { - return; - } - - this.active.children( "a" ).removeClass( "ui-state-focus" ); - this.active = null; - - this._trigger( "blur", event, { item: this.active } ); - }, - - _startOpening: function( submenu ) { - clearTimeout( this.timer ); - - // Don't open if already open fixes a Firefox bug that caused a .5 pixel - // shift in the submenu position when mousing over the carat icon - if ( submenu.attr( "aria-hidden" ) !== "true" ) { - return; - } - - this.timer = this._delay(function() { - this._close(); - this._open( submenu ); - }, this.delay ); - }, - - _open: function( submenu ) { - var position = $.extend({ - of: this.active - }, this.options.position ); - - clearTimeout( this.timer ); - this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) - .hide() - .attr( "aria-hidden", "true" ); - - submenu - .show() - .removeAttr( "aria-hidden" ) - .attr( "aria-expanded", "true" ) - .position( position ); - }, - - collapseAll: function( event, all ) { - clearTimeout( this.timer ); - this.timer = this._delay(function() { - // If we were passed an event, look for the submenu that contains the event - var currentMenu = all ? this.element : - $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); - - // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway - if ( !currentMenu.length ) { - currentMenu = this.element; - } - - this._close( currentMenu ); - - this.blur( event ); - this.activeMenu = currentMenu; - }, this.delay ); - }, - - // With no arguments, closes the currently active menu - if nothing is active - // it closes all menus. If passed an argument, it will search for menus BELOW - _close: function( startMenu ) { - if ( !startMenu ) { - startMenu = this.active ? this.active.parent() : this.element; - } - - startMenu - .find( ".ui-menu" ) - .hide() - .attr( "aria-hidden", "true" ) - .attr( "aria-expanded", "false" ) - .end() - .find( "a.ui-state-active" ) - .removeClass( "ui-state-active" ); - }, - - collapse: function( event ) { - var newItem = this.active && - this.active.parent().closest( ".ui-menu-item", this.element ); - if ( newItem && newItem.length ) { - this._close(); - this.focus( event, newItem ); - } - }, - - expand: function( event ) { - var newItem = this.active && - this.active - .children( ".ui-menu " ) - .children( ".ui-menu-item" ) - .first(); - - if ( newItem && newItem.length ) { - this._open( newItem.parent() ); - - // Delay so Firefox will not hide activedescendant change in expanding submenu from AT - this._delay(function() { - this.focus( event, newItem ); - }); - } - }, - - next: function( event ) { - this._move( "next", "first", event ); - }, - - previous: function( event ) { - this._move( "prev", "last", event ); - }, - - isFirstItem: function() { - return this.active && !this.active.prevAll( ".ui-menu-item" ).length; - }, - - isLastItem: function() { - return this.active && !this.active.nextAll( ".ui-menu-item" ).length; - }, - - _move: function( direction, filter, event ) { - var next; - if ( this.active ) { - if ( direction === "first" || direction === "last" ) { - next = this.active - [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) - .eq( -1 ); - } else { - next = this.active - [ direction + "All" ]( ".ui-menu-item" ) - .eq( 0 ); - } - } - if ( !next || !next.length || !this.active ) { - next = this.activeMenu.children( ".ui-menu-item" )[ filter ](); - } - - this.focus( event, next ); - }, - - nextPage: function( event ) { - var item, base, height; - - if ( !this.active ) { - this.next( event ); - return; - } - if ( this.isLastItem() ) { - return; - } - if ( this._hasScroll() ) { - base = this.active.offset().top; - height = this.element.height(); - this.active.nextAll( ".ui-menu-item" ).each(function() { - item = $( this ); - return item.offset().top - base - height < 0; - }); - - this.focus( event, item ); - } else { - this.focus( event, this.activeMenu.children( ".ui-menu-item" ) - [ !this.active ? "first" : "last" ]() ); - } - }, - - previousPage: function( event ) { - var item, base, height; - if ( !this.active ) { - this.next( event ); - return; - } - if ( this.isFirstItem() ) { - return; - } - if ( this._hasScroll() ) { - base = this.active.offset().top; - height = this.element.height(); - this.active.prevAll( ".ui-menu-item" ).each(function() { - item = $( this ); - return item.offset().top - base + height > 0; - }); - - this.focus( event, item ); - } else { - this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() ); - } - }, - - _hasScroll: function() { - return this.element.outerHeight() < this.element.prop( "scrollHeight" ); - }, - - select: function( event ) { - // TODO: It should never be possible to not have an active item at this - // point, but the tests don't trigger mouseenter before click. - this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); - var ui = { item: this.active }; - if ( !this.active.has( ".ui-menu" ).length ) { - this.collapseAll( event, true ); - } - this._trigger( "select", event, ui ); - } -}); - -}( jQuery )); - -(function( $, undefined ) { - -$.ui = $.ui || {}; - -var cachedScrollbarWidth, - max = Math.max, - abs = Math.abs, - round = Math.round, - rhorizontal = /left|center|right/, - rvertical = /top|center|bottom/, - roffset = /[\+\-]\d+%?/, - rposition = /^\w+/, - rpercent = /%$/, - _position = $.fn.position; - -function getOffsets( offsets, width, height ) { - return [ - parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), - parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) - ]; -} -function parseCss( element, property ) { - return parseInt( $.css( element, property ), 10 ) || 0; -} - -$.position = { - scrollbarWidth: function() { - if ( cachedScrollbarWidth !== undefined ) { - return cachedScrollbarWidth; - } - var w1, w2, - div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), - innerDiv = div.children()[0]; - - $( "body" ).append( div ); - w1 = innerDiv.offsetWidth; - div.css( "overflow", "scroll" ); - - w2 = innerDiv.offsetWidth; - - if ( w1 === w2 ) { - w2 = div[0].clientWidth; - } - - div.remove(); - - return (cachedScrollbarWidth = w1 - w2); - }, - getScrollInfo: function( within ) { - var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ), - overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ), - hasOverflowX = overflowX === "scroll" || - ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), - hasOverflowY = overflowY === "scroll" || - ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); - return { - width: hasOverflowX ? $.position.scrollbarWidth() : 0, - height: hasOverflowY ? $.position.scrollbarWidth() : 0 - }; - }, - getWithinInfo: function( element ) { - var withinElement = $( element || window ), - isWindow = $.isWindow( withinElement[0] ); - return { - element: withinElement, - isWindow: isWindow, - offset: withinElement.offset() || { left: 0, top: 0 }, - scrollLeft: withinElement.scrollLeft(), - scrollTop: withinElement.scrollTop(), - width: isWindow ? withinElement.width() : withinElement.outerWidth(), - height: isWindow ? withinElement.height() : withinElement.outerHeight() - }; - } -}; - -$.fn.position = function( options ) { - if ( !options || !options.of ) { - return _position.apply( this, arguments ); - } - - // make a copy, we don't want to modify arguments - options = $.extend( {}, options ); - - var atOffset, targetWidth, targetHeight, targetOffset, basePosition, - target = $( options.of ), - within = $.position.getWithinInfo( options.within ), - scrollInfo = $.position.getScrollInfo( within ), - targetElem = target[0], - collision = ( options.collision || "flip" ).split( " " ), - offsets = {}; - - if ( targetElem.nodeType === 9 ) { - targetWidth = target.width(); - targetHeight = target.height(); - targetOffset = { top: 0, left: 0 }; - } else if ( $.isWindow( targetElem ) ) { - targetWidth = target.width(); - targetHeight = target.height(); - targetOffset = { top: target.scrollTop(), left: target.scrollLeft() }; - } else if ( targetElem.preventDefault ) { - // force left top to allow flipping - options.at = "left top"; - targetWidth = targetHeight = 0; - targetOffset = { top: targetElem.pageY, left: targetElem.pageX }; - } else { - targetWidth = target.outerWidth(); - targetHeight = target.outerHeight(); - targetOffset = target.offset(); - } - // clone to reuse original targetOffset later - basePosition = $.extend( {}, targetOffset ); - - // force my and at to have valid horizontal and vertical positions - // if a value is missing or invalid, it will be converted to center - $.each( [ "my", "at" ], function() { - var pos = ( options[ this ] || "" ).split( " " ), - horizontalOffset, - verticalOffset; - - if ( pos.length === 1) { - pos = rhorizontal.test( pos[ 0 ] ) ? - pos.concat( [ "center" ] ) : - rvertical.test( pos[ 0 ] ) ? - [ "center" ].concat( pos ) : - [ "center", "center" ]; - } - pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; - pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; - - // calculate offsets - horizontalOffset = roffset.exec( pos[ 0 ] ); - verticalOffset = roffset.exec( pos[ 1 ] ); - offsets[ this ] = [ - horizontalOffset ? horizontalOffset[ 0 ] : 0, - verticalOffset ? verticalOffset[ 0 ] : 0 - ]; - - // reduce to just the positions without the offsets - options[ this ] = [ - rposition.exec( pos[ 0 ] )[ 0 ], - rposition.exec( pos[ 1 ] )[ 0 ] - ]; - }); - - // normalize collision option - if ( collision.length === 1 ) { - collision[ 1 ] = collision[ 0 ]; - } - - if ( options.at[ 0 ] === "right" ) { - basePosition.left += targetWidth; - } else if ( options.at[ 0 ] === "center" ) { - basePosition.left += targetWidth / 2; - } - - if ( options.at[ 1 ] === "bottom" ) { - basePosition.top += targetHeight; - } else if ( options.at[ 1 ] === "center" ) { - basePosition.top += targetHeight / 2; - } - - atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); - basePosition.left += atOffset[ 0 ]; - basePosition.top += atOffset[ 1 ]; - - return this.each(function() { - var collisionPosition, using, - elem = $( this ), - elemWidth = elem.outerWidth(), - elemHeight = elem.outerHeight(), - marginLeft = parseCss( this, "marginLeft" ), - marginTop = parseCss( this, "marginTop" ), - collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, - collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, - position = $.extend( {}, basePosition ), - myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); - - if ( options.my[ 0 ] === "right" ) { - position.left -= elemWidth; - } else if ( options.my[ 0 ] === "center" ) { - position.left -= elemWidth / 2; - } - - if ( options.my[ 1 ] === "bottom" ) { - position.top -= elemHeight; - } else if ( options.my[ 1 ] === "center" ) { - position.top -= elemHeight / 2; - } - - position.left += myOffset[ 0 ]; - position.top += myOffset[ 1 ]; - - // if the browser doesn't support fractions, then round for consistent results - if ( !$.support.offsetFractions ) { - position.left = round( position.left ); - position.top = round( position.top ); - } - - collisionPosition = { - marginLeft: marginLeft, - marginTop: marginTop - }; - - $.each( [ "left", "top" ], function( i, dir ) { - if ( $.ui.position[ collision[ i ] ] ) { - $.ui.position[ collision[ i ] ][ dir ]( position, { - targetWidth: targetWidth, - targetHeight: targetHeight, - elemWidth: elemWidth, - elemHeight: elemHeight, - collisionPosition: collisionPosition, - collisionWidth: collisionWidth, - collisionHeight: collisionHeight, - offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], - my: options.my, - at: options.at, - within: within, - elem : elem - }); - } - }); - - if ( $.fn.bgiframe ) { - elem.bgiframe(); - } - - if ( options.using ) { - // adds feedback as second argument to using callback, if present - using = function( props ) { - var left = targetOffset.left - position.left, - right = left + targetWidth - elemWidth, - top = targetOffset.top - position.top, - bottom = top + targetHeight - elemHeight, - feedback = { - target: { - element: target, - left: targetOffset.left, - top: targetOffset.top, - width: targetWidth, - height: targetHeight - }, - element: { - element: elem, - left: position.left, - top: position.top, - width: elemWidth, - height: elemHeight - }, - horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", - vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" - }; - if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { - feedback.horizontal = "center"; - } - if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { - feedback.vertical = "middle"; - } - if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { - feedback.important = "horizontal"; - } else { - feedback.important = "vertical"; - } - options.using.call( this, props, feedback ); - }; - } - - elem.offset( $.extend( position, { using: using } ) ); - }); -}; - -$.ui.position = { - fit: { - left: function( position, data ) { - var within = data.within, - withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, - outerWidth = within.width, - collisionPosLeft = position.left - data.collisionPosition.marginLeft, - overLeft = withinOffset - collisionPosLeft, - overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, - newOverRight; - - // element is wider than within - if ( data.collisionWidth > outerWidth ) { - // element is initially over the left side of within - if ( overLeft > 0 && overRight <= 0 ) { - newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; - position.left += overLeft - newOverRight; - // element is initially over right side of within - } else if ( overRight > 0 && overLeft <= 0 ) { - position.left = withinOffset; - // element is initially over both left and right sides of within - } else { - if ( overLeft > overRight ) { - position.left = withinOffset + outerWidth - data.collisionWidth; - } else { - position.left = withinOffset; - } - } - // too far left -> align with left edge - } else if ( overLeft > 0 ) { - position.left += overLeft; - // too far right -> align with right edge - } else if ( overRight > 0 ) { - position.left -= overRight; - // adjust based on position and margin - } else { - position.left = max( position.left - collisionPosLeft, position.left ); - } - }, - top: function( position, data ) { - var within = data.within, - withinOffset = within.isWindow ? within.scrollTop : within.offset.top, - outerHeight = data.within.height, - collisionPosTop = position.top - data.collisionPosition.marginTop, - overTop = withinOffset - collisionPosTop, - overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, - newOverBottom; - - // element is taller than within - if ( data.collisionHeight > outerHeight ) { - // element is initially over the top of within - if ( overTop > 0 && overBottom <= 0 ) { - newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; - position.top += overTop - newOverBottom; - // element is initially over bottom of within - } else if ( overBottom > 0 && overTop <= 0 ) { - position.top = withinOffset; - // element is initially over both top and bottom of within - } else { - if ( overTop > overBottom ) { - position.top = withinOffset + outerHeight - data.collisionHeight; - } else { - position.top = withinOffset; - } - } - // too far up -> align with top - } else if ( overTop > 0 ) { - position.top += overTop; - // too far down -> align with bottom edge - } else if ( overBottom > 0 ) { - position.top -= overBottom; - // adjust based on position and margin - } else { - position.top = max( position.top - collisionPosTop, position.top ); - } - } - }, - flip: { - left: function( position, data ) { - var within = data.within, - withinOffset = within.offset.left + within.scrollLeft, - outerWidth = within.width, - offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, - collisionPosLeft = position.left - data.collisionPosition.marginLeft, - overLeft = collisionPosLeft - offsetLeft, - overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, - myOffset = data.my[ 0 ] === "left" ? - -data.elemWidth : - data.my[ 0 ] === "right" ? - data.elemWidth : - 0, - atOffset = data.at[ 0 ] === "left" ? - data.targetWidth : - data.at[ 0 ] === "right" ? - -data.targetWidth : - 0, - offset = -2 * data.offset[ 0 ], - newOverRight, - newOverLeft; - - if ( overLeft < 0 ) { - newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; - if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { - position.left += myOffset + atOffset + offset; - } - } - else if ( overRight > 0 ) { - newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; - if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { - position.left += myOffset + atOffset + offset; - } - } - }, - top: function( position, data ) { - var within = data.within, - withinOffset = within.offset.top + within.scrollTop, - outerHeight = within.height, - offsetTop = within.isWindow ? within.scrollTop : within.offset.top, - collisionPosTop = position.top - data.collisionPosition.marginTop, - overTop = collisionPosTop - offsetTop, - overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, - top = data.my[ 1 ] === "top", - myOffset = top ? - -data.elemHeight : - data.my[ 1 ] === "bottom" ? - data.elemHeight : - 0, - atOffset = data.at[ 1 ] === "top" ? - data.targetHeight : - data.at[ 1 ] === "bottom" ? - -data.targetHeight : - 0, - offset = -2 * data.offset[ 1 ], - newOverTop, - newOverBottom; - if ( overTop < 0 ) { - newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; - if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { - position.top += myOffset + atOffset + offset; - } - } - else if ( overBottom > 0 ) { - newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; - if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { - position.top += myOffset + atOffset + offset; - } - } - } - }, - flipfit: { - left: function() { - $.ui.position.flip.left.apply( this, arguments ); - $.ui.position.fit.left.apply( this, arguments ); - }, - top: function() { - $.ui.position.flip.top.apply( this, arguments ); - $.ui.position.fit.top.apply( this, arguments ); - } - } -}; - -// fraction support test -(function () { - var testElement, testElementParent, testElementStyle, offsetLeft, i, - body = document.getElementsByTagName( "body" )[ 0 ], - div = document.createElement( "div" ); - - //Create a "fake body" for testing based on method used in jQuery.support - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - $.extend( testElementStyle, { - position: "absolute", - left: "-1000px", - top: "-1000px" - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || document.documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - div.style.cssText = "position: absolute; left: 10.7432222px;"; - - offsetLeft = $( div ).offset().left; - $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; - - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); -})(); - -// DEPRECATED -if ( $.uiBackCompat !== false ) { - // offset option - (function( $ ) { - var _position = $.fn.position; - $.fn.position = function( options ) { - if ( !options || !options.offset ) { - return _position.call( this, options ); - } - var offset = options.offset.split( " " ), - at = options.at.split( " " ); - if ( offset.length === 1 ) { - offset[ 1 ] = offset[ 0 ]; - } - if ( /^\d/.test( offset[ 0 ] ) ) { - offset[ 0 ] = "+" + offset[ 0 ]; - } - if ( /^\d/.test( offset[ 1 ] ) ) { - offset[ 1 ] = "+" + offset[ 1 ]; - } - if ( at.length === 1 ) { - if ( /left|center|right/.test( at[ 0 ] ) ) { - at[ 1 ] = "center"; - } else { - at[ 1 ] = at[ 0 ]; - at[ 0 ] = "center"; - } - } - return _position.call( this, $.extend( options, { - at: at[ 0 ] + offset[ 0 ] + " " + at[ 1 ] + offset[ 1 ], - offset: undefined - } ) ); - }; - }( jQuery ) ); -} - -}( jQuery ) ); - -(function( $, undefined ) { - -$.widget( "ui.progressbar", { - version: "1.9.2", - options: { - value: 0, - max: 100 - }, - - min: 0, - - _create: function() { - this.element - .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .attr({ - role: "progressbar", - "aria-valuemin": this.min, - "aria-valuemax": this.options.max, - "aria-valuenow": this._value() - }); - - this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) - .appendTo( this.element ); - - this.oldValue = this._value(); - this._refreshValue(); - }, - - _destroy: function() { - this.element - .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - - this.valueDiv.remove(); - }, - - value: function( newValue ) { - if ( newValue === undefined ) { - return this._value(); - } - - this._setOption( "value", newValue ); - return this; - }, - - _setOption: function( key, value ) { - if ( key === "value" ) { - this.options.value = value; - this._refreshValue(); - if ( this._value() === this.options.max ) { - this._trigger( "complete" ); - } - } - - this._super( key, value ); - }, - - _value: function() { - var val = this.options.value; - // normalize invalid value - if ( typeof val !== "number" ) { - val = 0; - } - return Math.min( this.options.max, Math.max( this.min, val ) ); - }, - - _percentage: function() { - return 100 * this._value() / this.options.max; - }, - - _refreshValue: function() { - var value = this.value(), - percentage = this._percentage(); - - if ( this.oldValue !== value ) { - this.oldValue = value; - this._trigger( "change" ); - } - - this.valueDiv - .toggle( value > this.min ) - .toggleClass( "ui-corner-right", value === this.options.max ) - .width( percentage.toFixed(0) + "%" ); - this.element.attr( "aria-valuenow", value ); - } -}); - -})( jQuery ); - -(function( $, undefined ) { - -// number of pages in a slider -// (how many times can you page up/down to go through the whole range) -var numPages = 5; - -$.widget( "ui.slider", $.ui.mouse, { - version: "1.9.2", - widgetEventPrefix: "slide", - - options: { - animate: false, - distance: 0, - max: 100, - min: 0, - orientation: "horizontal", - range: false, - step: 1, - value: 0, - values: null - }, - - _create: function() { - var i, handleCount, - o = this.options, - existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), - handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>", - handles = []; - - this._keySliding = false; - this._mouseSliding = false; - this._animateOff = true; - this._handleIndex = null; - this._detectOrientation(); - this._mouseInit(); - - this.element - .addClass( "ui-slider" + - " ui-slider-" + this.orientation + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" + - ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) ); - - this.range = $([]); - - if ( o.range ) { - if ( o.range === true ) { - if ( !o.values ) { - o.values = [ this._valueMin(), this._valueMin() ]; - } - if ( o.values.length && o.values.length !== 2 ) { - o.values = [ o.values[0], o.values[0] ]; - } - } - - this.range = $( "<div></div>" ) - .appendTo( this.element ) - .addClass( "ui-slider-range" + - // note: this isn't the most fittingly semantic framework class for this element, - // but worked best visually with a variety of themes - " ui-widget-header" + - ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); - } - - handleCount = ( o.values && o.values.length ) || 1; - - for ( i = existingHandles.length; i < handleCount; i++ ) { - handles.push( handle ); - } - - this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); - - this.handle = this.handles.eq( 0 ); - - this.handles.add( this.range ).filter( "a" ) - .click(function( event ) { - event.preventDefault(); - }) - .mouseenter(function() { - if ( !o.disabled ) { - $( this ).addClass( "ui-state-hover" ); - } - }) - .mouseleave(function() { - $( this ).removeClass( "ui-state-hover" ); - }) - .focus(function() { - if ( !o.disabled ) { - $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); - $( this ).addClass( "ui-state-focus" ); - } else { - $( this ).blur(); - } - }) - .blur(function() { - $( this ).removeClass( "ui-state-focus" ); - }); - - this.handles.each(function( i ) { - $( this ).data( "ui-slider-handle-index", i ); - }); - - this._on( this.handles, { - keydown: function( event ) { - var allowed, curVal, newVal, step, - index = $( event.target ).data( "ui-slider-handle-index" ); - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.PAGE_UP: - case $.ui.keyCode.PAGE_DOWN: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - event.preventDefault(); - if ( !this._keySliding ) { - this._keySliding = true; - $( event.target ).addClass( "ui-state-active" ); - allowed = this._start( event, index ); - if ( allowed === false ) { - return; - } - } - break; - } - - step = this.options.step; - if ( this.options.values && this.options.values.length ) { - curVal = newVal = this.values( index ); - } else { - curVal = newVal = this.value(); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - newVal = this._valueMin(); - break; - case $.ui.keyCode.END: - newVal = this._valueMax(); - break; - case $.ui.keyCode.PAGE_UP: - newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.PAGE_DOWN: - newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - if ( curVal === this._valueMax() ) { - return; - } - newVal = this._trimAlignValue( curVal + step ); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if ( curVal === this._valueMin() ) { - return; - } - newVal = this._trimAlignValue( curVal - step ); - break; - } - - this._slide( event, index, newVal ); - }, - keyup: function( event ) { - var index = $( event.target ).data( "ui-slider-handle-index" ); - - if ( this._keySliding ) { - this._keySliding = false; - this._stop( event, index ); - this._change( event, index ); - $( event.target ).removeClass( "ui-state-active" ); - } - } - }); - - this._refreshValue(); - - this._animateOff = false; - }, - - _destroy: function() { - this.handles.remove(); - this.range.remove(); - - this.element - .removeClass( "ui-slider" + - " ui-slider-horizontal" + - " ui-slider-vertical" + - " ui-slider-disabled" + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" ); - - this._mouseDestroy(); - }, - - _mouseCapture: function( event ) { - var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, - that = this, - o = this.options; - - if ( o.disabled ) { - return false; - } - - this.elementSize = { - width: this.element.outerWidth(), - height: this.element.outerHeight() - }; - this.elementOffset = this.element.offset(); - - position = { x: event.pageX, y: event.pageY }; - normValue = this._normValueFromMouse( position ); - distance = this._valueMax() - this._valueMin() + 1; - this.handles.each(function( i ) { - var thisDistance = Math.abs( normValue - that.values(i) ); - if ( distance > thisDistance ) { - distance = thisDistance; - closestHandle = $( this ); - index = i; - } - }); - - // workaround for bug #3736 (if both handles of a range are at 0, - // the first is always used as the one with least distance, - // and moving it is obviously prevented by preventing negative ranges) - if( o.range === true && this.values(1) === o.min ) { - index += 1; - closestHandle = $( this.handles[index] ); - } - - allowed = this._start( event, index ); - if ( allowed === false ) { - return false; - } - this._mouseSliding = true; - - this._handleIndex = index; - - closestHandle - .addClass( "ui-state-active" ) - .focus(); - - offset = closestHandle.offset(); - mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); - this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { - left: event.pageX - offset.left - ( closestHandle.width() / 2 ), - top: event.pageY - offset.top - - ( closestHandle.height() / 2 ) - - ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - - ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + - ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) - }; - - if ( !this.handles.hasClass( "ui-state-hover" ) ) { - this._slide( event, index, normValue ); - } - this._animateOff = true; - return true; - }, - - _mouseStart: function() { - return true; - }, - - _mouseDrag: function( event ) { - var position = { x: event.pageX, y: event.pageY }, - normValue = this._normValueFromMouse( position ); - - this._slide( event, this._handleIndex, normValue ); - - return false; - }, - - _mouseStop: function( event ) { - this.handles.removeClass( "ui-state-active" ); - this._mouseSliding = false; - - this._stop( event, this._handleIndex ); - this._change( event, this._handleIndex ); - - this._handleIndex = null; - this._clickOffset = null; - this._animateOff = false; - - return false; - }, - - _detectOrientation: function() { - this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; - }, - - _normValueFromMouse: function( position ) { - var pixelTotal, - pixelMouse, - percentMouse, - valueTotal, - valueMouse; - - if ( this.orientation === "horizontal" ) { - pixelTotal = this.elementSize.width; - pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); - } else { - pixelTotal = this.elementSize.height; - pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); - } - - percentMouse = ( pixelMouse / pixelTotal ); - if ( percentMouse > 1 ) { - percentMouse = 1; - } - if ( percentMouse < 0 ) { - percentMouse = 0; - } - if ( this.orientation === "vertical" ) { - percentMouse = 1 - percentMouse; - } - - valueTotal = this._valueMax() - this._valueMin(); - valueMouse = this._valueMin() + percentMouse * valueTotal; - - return this._trimAlignValue( valueMouse ); - }, - - _start: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - return this._trigger( "start", event, uiHash ); - }, - - _slide: function( event, index, newVal ) { - var otherVal, - newValues, - allowed; - - if ( this.options.values && this.options.values.length ) { - otherVal = this.values( index ? 0 : 1 ); - - if ( ( this.options.values.length === 2 && this.options.range === true ) && - ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) - ) { - newVal = otherVal; - } - - if ( newVal !== this.values( index ) ) { - newValues = this.values(); - newValues[ index ] = newVal; - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal, - values: newValues - } ); - otherVal = this.values( index ? 0 : 1 ); - if ( allowed !== false ) { - this.values( index, newVal, true ); - } - } - } else { - if ( newVal !== this.value() ) { - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal - } ); - if ( allowed !== false ) { - this.value( newVal ); - } - } - } - }, - - _stop: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "stop", event, uiHash ); - }, - - _change: function( event, index ) { - if ( !this._keySliding && !this._mouseSliding ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "change", event, uiHash ); - } - }, - - value: function( newValue ) { - if ( arguments.length ) { - this.options.value = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, 0 ); - return; - } - - return this._value(); - }, - - values: function( index, newValue ) { - var vals, - newValues, - i; - - if ( arguments.length > 1 ) { - this.options.values[ index ] = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, index ); - return; - } - - if ( arguments.length ) { - if ( $.isArray( arguments[ 0 ] ) ) { - vals = this.options.values; - newValues = arguments[ 0 ]; - for ( i = 0; i < vals.length; i += 1 ) { - vals[ i ] = this._trimAlignValue( newValues[ i ] ); - this._change( null, i ); - } - this._refreshValue(); - } else { - if ( this.options.values && this.options.values.length ) { - return this._values( index ); - } else { - return this.value(); - } - } - } else { - return this._values(); - } - }, - - _setOption: function( key, value ) { - var i, - valsLength = 0; - - if ( $.isArray( this.options.values ) ) { - valsLength = this.options.values.length; - } - - $.Widget.prototype._setOption.apply( this, arguments ); - - switch ( key ) { - case "disabled": - if ( value ) { - this.handles.filter( ".ui-state-focus" ).blur(); - this.handles.removeClass( "ui-state-hover" ); - this.handles.prop( "disabled", true ); - this.element.addClass( "ui-disabled" ); - } else { - this.handles.prop( "disabled", false ); - this.element.removeClass( "ui-disabled" ); - } - break; - case "orientation": - this._detectOrientation(); - this.element - .removeClass( "ui-slider-horizontal ui-slider-vertical" ) - .addClass( "ui-slider-" + this.orientation ); - this._refreshValue(); - break; - case "value": - this._animateOff = true; - this._refreshValue(); - this._change( null, 0 ); - this._animateOff = false; - break; - case "values": - this._animateOff = true; - this._refreshValue(); - for ( i = 0; i < valsLength; i += 1 ) { - this._change( null, i ); - } - this._animateOff = false; - break; - case "min": - case "max": - this._animateOff = true; - this._refreshValue(); - this._animateOff = false; - break; - } - }, - - //internal value getter - // _value() returns value trimmed by min and max, aligned by step - _value: function() { - var val = this.options.value; - val = this._trimAlignValue( val ); - - return val; - }, - - //internal values getter - // _values() returns array of values trimmed by min and max, aligned by step - // _values( index ) returns single value trimmed by min and max, aligned by step - _values: function( index ) { - var val, - vals, - i; - - if ( arguments.length ) { - val = this.options.values[ index ]; - val = this._trimAlignValue( val ); - - return val; - } else { - // .slice() creates a copy of the array - // this copy gets trimmed by min and max and then returned - vals = this.options.values.slice(); - for ( i = 0; i < vals.length; i+= 1) { - vals[ i ] = this._trimAlignValue( vals[ i ] ); - } - - return vals; - } - }, - - // returns the step-aligned value that val is closest to, between (inclusive) min and max - _trimAlignValue: function( val ) { - if ( val <= this._valueMin() ) { - return this._valueMin(); - } - if ( val >= this._valueMax() ) { - return this._valueMax(); - } - var step = ( this.options.step > 0 ) ? this.options.step : 1, - valModStep = (val - this._valueMin()) % step, - alignValue = val - valModStep; - - if ( Math.abs(valModStep) * 2 >= step ) { - alignValue += ( valModStep > 0 ) ? step : ( -step ); - } - - // Since JavaScript has problems with large floats, round - // the final value to 5 digits after the decimal point (see #4124) - return parseFloat( alignValue.toFixed(5) ); - }, - - _valueMin: function() { - return this.options.min; - }, - - _valueMax: function() { - return this.options.max; - }, - - _refreshValue: function() { - var lastValPercent, valPercent, value, valueMin, valueMax, - oRange = this.options.range, - o = this.options, - that = this, - animate = ( !this._animateOff ) ? o.animate : false, - _set = {}; - - if ( this.options.values && this.options.values.length ) { - this.handles.each(function( i ) { - valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; - _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - if ( that.options.range === true ) { - if ( that.orientation === "horizontal" ) { - if ( i === 0 ) { - that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); - } - if ( i === 1 ) { - that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } else { - if ( i === 0 ) { - that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); - } - if ( i === 1 ) { - that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - lastValPercent = valPercent; - }); - } else { - value = this.value(); - valueMin = this._valueMin(); - valueMax = this._valueMax(); - valPercent = ( valueMax !== valueMin ) ? - ( value - valueMin ) / ( valueMax - valueMin ) * 100 : - 0; - _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - - if ( oRange === "min" && this.orientation === "horizontal" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "horizontal" ) { - this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - if ( oRange === "min" && this.orientation === "vertical" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "vertical" ) { - this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - -}); - -}(jQuery)); - -(function( $ ) { - -function modifier( fn ) { - return function() { - var previous = this.element.val(); - fn.apply( this, arguments ); - this._refresh(); - if ( previous !== this.element.val() ) { - this._trigger( "change" ); - } - }; -} - -$.widget( "ui.spinner", { - version: "1.9.2", - defaultElement: "<input>", - widgetEventPrefix: "spin", - options: { - culture: null, - icons: { - down: "ui-icon-triangle-1-s", - up: "ui-icon-triangle-1-n" - }, - incremental: true, - max: null, - min: null, - numberFormat: null, - page: 10, - step: 1, - - change: null, - spin: null, - start: null, - stop: null - }, - - _create: function() { - // handle string values that need to be parsed - this._setOption( "max", this.options.max ); - this._setOption( "min", this.options.min ); - this._setOption( "step", this.options.step ); - - // format the value, but don't constrain - this._value( this.element.val(), true ); - - this._draw(); - this._on( this._events ); - this._refresh(); - - // turning off autocomplete prevents the browser from remembering the - // value when navigating through history, so we re-enable autocomplete - // if the page is unloaded before the widget is destroyed. #7790 - this._on( this.window, { - beforeunload: function() { - this.element.removeAttr( "autocomplete" ); - } - }); - }, - - _getCreateOptions: function() { - var options = {}, - element = this.element; - - $.each( [ "min", "max", "step" ], function( i, option ) { - var value = element.attr( option ); - if ( value !== undefined && value.length ) { - options[ option ] = value; - } - }); - - return options; - }, - - _events: { - keydown: function( event ) { - if ( this._start( event ) && this._keydown( event ) ) { - event.preventDefault(); - } - }, - keyup: "_stop", - focus: function() { - this.previous = this.element.val(); - }, - blur: function( event ) { - if ( this.cancelBlur ) { - delete this.cancelBlur; - return; - } - - this._refresh(); - if ( this.previous !== this.element.val() ) { - this._trigger( "change", event ); - } - }, - mousewheel: function( event, delta ) { - if ( !delta ) { - return; - } - if ( !this.spinning && !this._start( event ) ) { - return false; - } - - this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); - clearTimeout( this.mousewheelTimer ); - this.mousewheelTimer = this._delay(function() { - if ( this.spinning ) { - this._stop( event ); - } - }, 100 ); - event.preventDefault(); - }, - "mousedown .ui-spinner-button": function( event ) { - var previous; - - // We never want the buttons to have focus; whenever the user is - // interacting with the spinner, the focus should be on the input. - // If the input is focused then this.previous is properly set from - // when the input first received focus. If the input is not focused - // then we need to set this.previous based on the value before spinning. - previous = this.element[0] === this.document[0].activeElement ? - this.previous : this.element.val(); - function checkFocus() { - var isActive = this.element[0] === this.document[0].activeElement; - if ( !isActive ) { - this.element.focus(); - this.previous = previous; - // support: IE - // IE sets focus asynchronously, so we need to check if focus - // moved off of the input because the user clicked on the button. - this._delay(function() { - this.previous = previous; - }); - } - } - - // ensure focus is on (or stays on) the text field - event.preventDefault(); - checkFocus.call( this ); - - // support: IE - // IE doesn't prevent moving focus even with event.preventDefault() - // so we set a flag to know when we should ignore the blur event - // and check (again) if focus moved off of the input. - this.cancelBlur = true; - this._delay(function() { - delete this.cancelBlur; - checkFocus.call( this ); - }); - - if ( this._start( event ) === false ) { - return; - } - - this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); - }, - "mouseup .ui-spinner-button": "_stop", - "mouseenter .ui-spinner-button": function( event ) { - // button will add ui-state-active if mouse was down while mouseleave and kept down - if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { - return; - } - - if ( this._start( event ) === false ) { - return false; - } - this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); - }, - // TODO: do we really want to consider this a stop? - // shouldn't we just stop the repeater and wait until mouseup before - // we trigger the stop event? - "mouseleave .ui-spinner-button": "_stop" - }, - - _draw: function() { - var uiSpinner = this.uiSpinner = this.element - .addClass( "ui-spinner-input" ) - .attr( "autocomplete", "off" ) - .wrap( this._uiSpinnerHtml() ) - .parent() - // add buttons - .append( this._buttonHtml() ); - - this.element.attr( "role", "spinbutton" ); - - // button bindings - this.buttons = uiSpinner.find( ".ui-spinner-button" ) - .attr( "tabIndex", -1 ) - .button() - .removeClass( "ui-corner-all" ); - - // IE 6 doesn't understand height: 50% for the buttons - // unless the wrapper has an explicit height - if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && - uiSpinner.height() > 0 ) { - uiSpinner.height( uiSpinner.height() ); - } - - // disable spinner if element was already disabled - if ( this.options.disabled ) { - this.disable(); - } - }, - - _keydown: function( event ) { - var options = this.options, - keyCode = $.ui.keyCode; - - switch ( event.keyCode ) { - case keyCode.UP: - this._repeat( null, 1, event ); - return true; - case keyCode.DOWN: - this._repeat( null, -1, event ); - return true; - case keyCode.PAGE_UP: - this._repeat( null, options.page, event ); - return true; - case keyCode.PAGE_DOWN: - this._repeat( null, -options.page, event ); - return true; - } - - return false; - }, - - _uiSpinnerHtml: function() { - return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"; - }, - - _buttonHtml: function() { - return "" + - "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" + - "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" + - "</a>" + - "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" + - "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" + - "</a>"; - }, - - _start: function( event ) { - if ( !this.spinning && this._trigger( "start", event ) === false ) { - return false; - } - - if ( !this.counter ) { - this.counter = 1; - } - this.spinning = true; - return true; - }, - - _repeat: function( i, steps, event ) { - i = i || 500; - - clearTimeout( this.timer ); - this.timer = this._delay(function() { - this._repeat( 40, steps, event ); - }, i ); - - this._spin( steps * this.options.step, event ); - }, - - _spin: function( step, event ) { - var value = this.value() || 0; - - if ( !this.counter ) { - this.counter = 1; - } - - value = this._adjustValue( value + step * this._increment( this.counter ) ); - - if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { - this._value( value ); - this.counter++; - } - }, - - _increment: function( i ) { - var incremental = this.options.incremental; - - if ( incremental ) { - return $.isFunction( incremental ) ? - incremental( i ) : - Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 ); - } - - return 1; - }, - - _precision: function() { - var precision = this._precisionOf( this.options.step ); - if ( this.options.min !== null ) { - precision = Math.max( precision, this._precisionOf( this.options.min ) ); - } - return precision; - }, - - _precisionOf: function( num ) { - var str = num.toString(), - decimal = str.indexOf( "." ); - return decimal === -1 ? 0 : str.length - decimal - 1; - }, - - _adjustValue: function( value ) { - var base, aboveMin, - options = this.options; - - // make sure we're at a valid step - // - find out where we are relative to the base (min or 0) - base = options.min !== null ? options.min : 0; - aboveMin = value - base; - // - round to the nearest step - aboveMin = Math.round(aboveMin / options.step) * options.step; - // - rounding is based on 0, so adjust back to our base - value = base + aboveMin; - - // fix precision from bad JS floating point math - value = parseFloat( value.toFixed( this._precision() ) ); - - // clamp the value - if ( options.max !== null && value > options.max) { - return options.max; - } - if ( options.min !== null && value < options.min ) { - return options.min; - } - - return value; - }, - - _stop: function( event ) { - if ( !this.spinning ) { - return; - } - - clearTimeout( this.timer ); - clearTimeout( this.mousewheelTimer ); - this.counter = 0; - this.spinning = false; - this._trigger( "stop", event ); - }, - - _setOption: function( key, value ) { - if ( key === "culture" || key === "numberFormat" ) { - var prevValue = this._parse( this.element.val() ); - this.options[ key ] = value; - this.element.val( this._format( prevValue ) ); - return; - } - - if ( key === "max" || key === "min" || key === "step" ) { - if ( typeof value === "string" ) { - value = this._parse( value ); - } - } - - this._super( key, value ); - - if ( key === "disabled" ) { - if ( value ) { - this.element.prop( "disabled", true ); - this.buttons.button( "disable" ); - } else { - this.element.prop( "disabled", false ); - this.buttons.button( "enable" ); - } - } - }, - - _setOptions: modifier(function( options ) { - this._super( options ); - this._value( this.element.val() ); - }), - - _parse: function( val ) { - if ( typeof val === "string" && val !== "" ) { - val = window.Globalize && this.options.numberFormat ? - Globalize.parseFloat( val, 10, this.options.culture ) : +val; - } - return val === "" || isNaN( val ) ? null : val; - }, - - _format: function( value ) { - if ( value === "" ) { - return ""; - } - return window.Globalize && this.options.numberFormat ? - Globalize.format( value, this.options.numberFormat, this.options.culture ) : - value; - }, - - _refresh: function() { - this.element.attr({ - "aria-valuemin": this.options.min, - "aria-valuemax": this.options.max, - // TODO: what should we do with values that can't be parsed? - "aria-valuenow": this._parse( this.element.val() ) - }); - }, - - // update the value without triggering change - _value: function( value, allowAny ) { - var parsed; - if ( value !== "" ) { - parsed = this._parse( value ); - if ( parsed !== null ) { - if ( !allowAny ) { - parsed = this._adjustValue( parsed ); - } - value = this._format( parsed ); - } - } - this.element.val( value ); - this._refresh(); - }, - - _destroy: function() { - this.element - .removeClass( "ui-spinner-input" ) - .prop( "disabled", false ) - .removeAttr( "autocomplete" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - this.uiSpinner.replaceWith( this.element ); - }, - - stepUp: modifier(function( steps ) { - this._stepUp( steps ); - }), - _stepUp: function( steps ) { - this._spin( (steps || 1) * this.options.step ); - }, - - stepDown: modifier(function( steps ) { - this._stepDown( steps ); - }), - _stepDown: function( steps ) { - this._spin( (steps || 1) * -this.options.step ); - }, - - pageUp: modifier(function( pages ) { - this._stepUp( (pages || 1) * this.options.page ); - }), - - pageDown: modifier(function( pages ) { - this._stepDown( (pages || 1) * this.options.page ); - }), - - value: function( newVal ) { - if ( !arguments.length ) { - return this._parse( this.element.val() ); - } - modifier( this._value ).call( this, newVal ); - }, - - widget: function() { - return this.uiSpinner; - } -}); - -}( jQuery ) ); - -(function( $, undefined ) { - -var tabId = 0, - rhash = /#.*$/; - -function getNextTabId() { - return ++tabId; -} - -function isLocal( anchor ) { - return anchor.hash.length > 1 && - anchor.href.replace( rhash, "" ) === - location.href.replace( rhash, "" ) - // support: Safari 5.1 - // Safari 5.1 doesn't encode spaces in window.location - // but it does encode spaces from anchors (#8777) - .replace( /\s/g, "%20" ); -} - -$.widget( "ui.tabs", { - version: "1.9.2", - delay: 300, - options: { - active: null, - collapsible: false, - event: "click", - heightStyle: "content", - hide: null, - show: null, - - // callbacks - activate: null, - beforeActivate: null, - beforeLoad: null, - load: null - }, - - _create: function() { - var that = this, - options = this.options, - active = options.active, - locationHash = location.hash.substring( 1 ); - - this.running = false; - - this.element - .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) - .toggleClass( "ui-tabs-collapsible", options.collapsible ) - // Prevent users from focusing disabled tabs via click - .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) { - if ( $( this ).is( ".ui-state-disabled" ) ) { - event.preventDefault(); - } - }) - // support: IE <9 - // Preventing the default action in mousedown doesn't prevent IE - // from focusing the element, so if the anchor gets focused, blur. - // We don't have to worry about focusing the previously focused - // element since clicking on a non-focusable element should focus - // the body anyway. - .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { - if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { - this.blur(); - } - }); - - this._processTabs(); - - if ( active === null ) { - // check the fragment identifier in the URL - if ( locationHash ) { - this.tabs.each(function( i, tab ) { - if ( $( tab ).attr( "aria-controls" ) === locationHash ) { - active = i; - return false; - } - }); - } - - // check for a tab marked active via a class - if ( active === null ) { - active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); - } - - // no active tab, set to false - if ( active === null || active === -1 ) { - active = this.tabs.length ? 0 : false; - } - } - - // handle numbers: negative, out of range - if ( active !== false ) { - active = this.tabs.index( this.tabs.eq( active ) ); - if ( active === -1 ) { - active = options.collapsible ? false : 0; - } - } - options.active = active; - - // don't allow collapsible: false and active: false - if ( !options.collapsible && options.active === false && this.anchors.length ) { - options.active = 0; - } - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - if ( $.isArray( options.disabled ) ) { - options.disabled = $.unique( options.disabled.concat( - $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { - return that.tabs.index( li ); - }) - ) ).sort(); - } - - // check for length avoids error when initializing empty list - if ( this.options.active !== false && this.anchors.length ) { - this.active = this._findActive( this.options.active ); - } else { - this.active = $(); - } - - this._refresh(); - - if ( this.active.length ) { - this.load( options.active ); - } - }, - - _getCreateEventData: function() { - return { - tab: this.active, - panel: !this.active.length ? $() : this._getPanelForTab( this.active ) - }; - }, - - _tabKeydown: function( event ) { - var focusedTab = $( this.document[0].activeElement ).closest( "li" ), - selectedIndex = this.tabs.index( focusedTab ), - goingForward = true; - - if ( this._handlePageNav( event ) ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - selectedIndex++; - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.LEFT: - goingForward = false; - selectedIndex--; - break; - case $.ui.keyCode.END: - selectedIndex = this.anchors.length - 1; - break; - case $.ui.keyCode.HOME: - selectedIndex = 0; - break; - case $.ui.keyCode.SPACE: - // Activate only, no collapsing - event.preventDefault(); - clearTimeout( this.activating ); - this._activate( selectedIndex ); - return; - case $.ui.keyCode.ENTER: - // Toggle (cancel delayed activation, allow collapsing) - event.preventDefault(); - clearTimeout( this.activating ); - // Determine if we should collapse or activate - this._activate( selectedIndex === this.options.active ? false : selectedIndex ); - return; - default: - return; - } - - // Focus the appropriate tab, based on which key was pressed - event.preventDefault(); - clearTimeout( this.activating ); - selectedIndex = this._focusNextTab( selectedIndex, goingForward ); - - // Navigating with control key will prevent automatic activation - if ( !event.ctrlKey ) { - // Update aria-selected immediately so that AT think the tab is already selected. - // Otherwise AT may confuse the user by stating that they need to activate the tab, - // but the tab will already be activated by the time the announcement finishes. - focusedTab.attr( "aria-selected", "false" ); - this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); - - this.activating = this._delay(function() { - this.option( "active", selectedIndex ); - }, this.delay ); - } - }, - - _panelKeydown: function( event ) { - if ( this._handlePageNav( event ) ) { - return; - } - - // Ctrl+up moves focus to the current tab - if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { - event.preventDefault(); - this.active.focus(); - } - }, - - // Alt+page up/down moves focus to the previous/next tab (and activates) - _handlePageNav: function( event ) { - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { - this._activate( this._focusNextTab( this.options.active - 1, false ) ); - return true; - } - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { - this._activate( this._focusNextTab( this.options.active + 1, true ) ); - return true; - } - }, - - _findNextTab: function( index, goingForward ) { - var lastTabIndex = this.tabs.length - 1; - - function constrain() { - if ( index > lastTabIndex ) { - index = 0; - } - if ( index < 0 ) { - index = lastTabIndex; - } - return index; - } - - while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { - index = goingForward ? index + 1 : index - 1; - } - - return index; - }, - - _focusNextTab: function( index, goingForward ) { - index = this._findNextTab( index, goingForward ); - this.tabs.eq( index ).focus(); - return index; - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - if ( key === "disabled" ) { - // don't use the widget factory's disabled handling - this._setupDisabled( value ); - return; - } - - this._super( key, value); - - if ( key === "collapsible" ) { - this.element.toggleClass( "ui-tabs-collapsible", value ); - // Setting collapsible: false while collapsed; open first panel - if ( !value && this.options.active === false ) { - this._activate( 0 ); - } - } - - if ( key === "event" ) { - this._setupEvents( value ); - } - - if ( key === "heightStyle" ) { - this._setupHeightStyle( value ); - } - }, - - _tabId: function( tab ) { - return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId(); - }, - - _sanitizeSelector: function( hash ) { - return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; - }, - - refresh: function() { - var options = this.options, - lis = this.tablist.children( ":has(a[href])" ); - - // get disabled tabs from class attribute from HTML - // this will get converted to a boolean if needed in _refresh() - options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { - return lis.index( tab ); - }); - - this._processTabs(); - - // was collapsed or no tabs - if ( options.active === false || !this.anchors.length ) { - options.active = false; - this.active = $(); - // was active, but active tab is gone - } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { - // all remaining tabs are disabled - if ( this.tabs.length === options.disabled.length ) { - options.active = false; - this.active = $(); - // activate previous tab - } else { - this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); - } - // was active, active tab still exists - } else { - // make sure active index is correct - options.active = this.tabs.index( this.active ); - } - - this._refresh(); - }, - - _refresh: function() { - this._setupDisabled( this.options.disabled ); - this._setupEvents( this.options.event ); - this._setupHeightStyle( this.options.heightStyle ); - - this.tabs.not( this.active ).attr({ - "aria-selected": "false", - tabIndex: -1 - }); - this.panels.not( this._getPanelForTab( this.active ) ) - .hide() - .attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - - // Make sure one tab is in the tab order - if ( !this.active.length ) { - this.tabs.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active - .addClass( "ui-tabs-active ui-state-active" ) - .attr({ - "aria-selected": "true", - tabIndex: 0 - }); - this._getPanelForTab( this.active ) - .show() - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - } - }, - - _processTabs: function() { - var that = this; - - this.tablist = this._getList() - .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) - .attr( "role", "tablist" ); - - this.tabs = this.tablist.find( "> li:has(a[href])" ) - .addClass( "ui-state-default ui-corner-top" ) - .attr({ - role: "tab", - tabIndex: -1 - }); - - this.anchors = this.tabs.map(function() { - return $( "a", this )[ 0 ]; - }) - .addClass( "ui-tabs-anchor" ) - .attr({ - role: "presentation", - tabIndex: -1 - }); - - this.panels = $(); - - this.anchors.each(function( i, anchor ) { - var selector, panel, panelId, - anchorId = $( anchor ).uniqueId().attr( "id" ), - tab = $( anchor ).closest( "li" ), - originalAriaControls = tab.attr( "aria-controls" ); - - // inline tab - if ( isLocal( anchor ) ) { - selector = anchor.hash; - panel = that.element.find( that._sanitizeSelector( selector ) ); - // remote tab - } else { - panelId = that._tabId( tab ); - selector = "#" + panelId; - panel = that.element.find( selector ); - if ( !panel.length ) { - panel = that._createPanel( panelId ); - panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); - } - panel.attr( "aria-live", "polite" ); - } - - if ( panel.length) { - that.panels = that.panels.add( panel ); - } - if ( originalAriaControls ) { - tab.data( "ui-tabs-aria-controls", originalAriaControls ); - } - tab.attr({ - "aria-controls": selector.substring( 1 ), - "aria-labelledby": anchorId - }); - panel.attr( "aria-labelledby", anchorId ); - }); - - this.panels - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .attr( "role", "tabpanel" ); - }, - - // allow overriding how to find the list for rare usage scenarios (#7715) - _getList: function() { - return this.element.find( "ol,ul" ).eq( 0 ); - }, - - _createPanel: function( id ) { - return $( "<div>" ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .data( "ui-tabs-destroy", true ); - }, - - _setupDisabled: function( disabled ) { - if ( $.isArray( disabled ) ) { - if ( !disabled.length ) { - disabled = false; - } else if ( disabled.length === this.anchors.length ) { - disabled = true; - } - } - - // disable tabs - for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { - if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { - $( li ) - .addClass( "ui-state-disabled" ) - .attr( "aria-disabled", "true" ); - } else { - $( li ) - .removeClass( "ui-state-disabled" ) - .removeAttr( "aria-disabled" ); - } - } - - this.options.disabled = disabled; - }, - - _setupEvents: function( event ) { - var events = { - click: function( event ) { - event.preventDefault(); - } - }; - if ( event ) { - $.each( event.split(" "), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - }); - } - - this._off( this.anchors.add( this.tabs ).add( this.panels ) ); - this._on( this.anchors, events ); - this._on( this.tabs, { keydown: "_tabKeydown" } ); - this._on( this.panels, { keydown: "_panelKeydown" } ); - - this._focusable( this.tabs ); - this._hoverable( this.tabs ); - }, - - _setupHeightStyle: function( heightStyle ) { - var maxHeight, overflow, - parent = this.element.parent(); - - if ( heightStyle === "fill" ) { - // IE 6 treats height like minHeight, so we need to turn off overflow - // in order to get a reliable height - // we use the minHeight support test because we assume that only - // browsers that don't support minHeight will treat height as minHeight - if ( !$.support.minHeight ) { - overflow = parent.css( "overflow" ); - parent.css( "overflow", "hidden"); - } - maxHeight = parent.height(); - this.element.siblings( ":visible" ).each(function() { - var elem = $( this ), - position = elem.css( "position" ); - - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - }); - if ( overflow ) { - parent.css( "overflow", overflow ); - } - - this.element.children().not( this.panels ).each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.panels.each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.panels.each(function() { - maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); - }).height( maxHeight ); - } - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - anchor = $( event.currentTarget ), - tab = anchor.closest( "li" ), - clickedIsActive = tab[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : this._getPanelForTab( tab ), - toHide = !active.length ? $() : this._getPanelForTab( active ), - eventData = { - oldTab: active, - oldPanel: toHide, - newTab: collapsing ? $() : tab, - newPanel: toShow - }; - - event.preventDefault(); - - if ( tab.hasClass( "ui-state-disabled" ) || - // tab is already loading - tab.hasClass( "ui-tabs-loading" ) || - // can't switch durning an animation - this.running || - // click on active header, but not collapsible - ( clickedIsActive && !options.collapsible ) || - // allow canceling activation - ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { - return; - } - - options.active = collapsing ? false : this.tabs.index( tab ); - - this.active = clickedIsActive ? $() : tab; - if ( this.xhr ) { - this.xhr.abort(); - } - - if ( !toHide.length && !toShow.length ) { - $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); - } - - if ( toShow.length ) { - this.load( this.tabs.index( tab ), event ); - } - this._toggle( event, eventData ); - }, - - // handles show/hide for selecting tabs - _toggle: function( event, eventData ) { - var that = this, - toShow = eventData.newPanel, - toHide = eventData.oldPanel; - - this.running = true; - - function complete() { - that.running = false; - that._trigger( "activate", event, eventData ); - } - - function show() { - eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); - - if ( toShow.length && that.options.show ) { - that._show( toShow, that.options.show, complete ); - } else { - toShow.show(); - complete(); - } - } - - // start out by hiding, then showing, then completing - if ( toHide.length && this.options.hide ) { - this._hide( toHide, this.options.hide, function() { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - show(); - }); - } else { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - toHide.hide(); - show(); - } - - toHide.attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - eventData.oldTab.attr( "aria-selected", "false" ); - // If we're switching tabs, remove the old tab from the tab order. - // If we're opening from collapsed state, remove the previous tab from the tab order. - // If we're collapsing, then keep the collapsing tab in the tab order. - if ( toShow.length && toHide.length ) { - eventData.oldTab.attr( "tabIndex", -1 ); - } else if ( toShow.length ) { - this.tabs.filter(function() { - return $( this ).attr( "tabIndex" ) === 0; - }) - .attr( "tabIndex", -1 ); - } - - toShow.attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - eventData.newTab.attr({ - "aria-selected": "true", - tabIndex: 0 - }); - }, - - _activate: function( index ) { - var anchor, - active = this._findActive( index ); - - // trying to activate the already active panel - if ( active[ 0 ] === this.active[ 0 ] ) { - return; - } - - // trying to collapse, simulate a click on the current active header - if ( !active.length ) { - active = this.active; - } - - anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; - this._eventHandler({ - target: anchor, - currentTarget: anchor, - preventDefault: $.noop - }); - }, - - _findActive: function( index ) { - return index === false ? $() : this.tabs.eq( index ); - }, - - _getIndex: function( index ) { - // meta-function to give users option to provide a href string instead of a numerical index. - if ( typeof index === "string" ) { - index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); - } - - return index; - }, - - _destroy: function() { - if ( this.xhr ) { - this.xhr.abort(); - } - - this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); - - this.tablist - .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) - .removeAttr( "role" ); - - this.anchors - .removeClass( "ui-tabs-anchor" ) - .removeAttr( "role" ) - .removeAttr( "tabIndex" ) - .removeData( "href.tabs" ) - .removeData( "load.tabs" ) - .removeUniqueId(); - - this.tabs.add( this.panels ).each(function() { - if ( $.data( this, "ui-tabs-destroy" ) ) { - $( this ).remove(); - } else { - $( this ) - .removeClass( "ui-state-default ui-state-active ui-state-disabled " + - "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) - .removeAttr( "tabIndex" ) - .removeAttr( "aria-live" ) - .removeAttr( "aria-busy" ) - .removeAttr( "aria-selected" ) - .removeAttr( "aria-labelledby" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "role" ); - } - }); - - this.tabs.each(function() { - var li = $( this ), - prev = li.data( "ui-tabs-aria-controls" ); - if ( prev ) { - li.attr( "aria-controls", prev ); - } else { - li.removeAttr( "aria-controls" ); - } - }); - - this.panels.show(); - - if ( this.options.heightStyle !== "content" ) { - this.panels.css( "height", "" ); - } - }, - - enable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === false ) { - return; - } - - if ( index === undefined ) { - disabled = false; - } else { - index = this._getIndex( index ); - if ( $.isArray( disabled ) ) { - disabled = $.map( disabled, function( num ) { - return num !== index ? num : null; - }); - } else { - disabled = $.map( this.tabs, function( li, num ) { - return num !== index ? num : null; - }); - } - } - this._setupDisabled( disabled ); - }, - - disable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === true ) { - return; - } - - if ( index === undefined ) { - disabled = true; - } else { - index = this._getIndex( index ); - if ( $.inArray( index, disabled ) !== -1 ) { - return; - } - if ( $.isArray( disabled ) ) { - disabled = $.merge( [ index ], disabled ).sort(); - } else { - disabled = [ index ]; - } - } - this._setupDisabled( disabled ); - }, - - load: function( index, event ) { - index = this._getIndex( index ); - var that = this, - tab = this.tabs.eq( index ), - anchor = tab.find( ".ui-tabs-anchor" ), - panel = this._getPanelForTab( tab ), - eventData = { - tab: tab, - panel: panel - }; - - // not remote - if ( isLocal( anchor[ 0 ] ) ) { - return; - } - - this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); - - // support: jQuery <1.8 - // jQuery <1.8 returns false if the request is canceled in beforeSend, - // but as of 1.8, $.ajax() always returns a jqXHR object. - if ( this.xhr && this.xhr.statusText !== "canceled" ) { - tab.addClass( "ui-tabs-loading" ); - panel.attr( "aria-busy", "true" ); - - this.xhr - .success(function( response ) { - // support: jQuery <1.8 - // http://bugs.jquery.com/ticket/11778 - setTimeout(function() { - panel.html( response ); - that._trigger( "load", event, eventData ); - }, 1 ); - }) - .complete(function( jqXHR, status ) { - // support: jQuery <1.8 - // http://bugs.jquery.com/ticket/11778 - setTimeout(function() { - if ( status === "abort" ) { - that.panels.stop( false, true ); - } - - tab.removeClass( "ui-tabs-loading" ); - panel.removeAttr( "aria-busy" ); - - if ( jqXHR === that.xhr ) { - delete that.xhr; - } - }, 1 ); - }); - } - }, - - // TODO: Remove this function in 1.10 when ajaxOptions is removed - _ajaxSettings: function( anchor, event, eventData ) { - var that = this; - return { - url: anchor.attr( "href" ), - beforeSend: function( jqXHR, settings ) { - return that._trigger( "beforeLoad", event, - $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) ); - } - }; - }, - - _getPanelForTab: function( tab ) { - var id = $( tab ).attr( "aria-controls" ); - return this.element.find( this._sanitizeSelector( "#" + id ) ); - } -}); - -// DEPRECATED -if ( $.uiBackCompat !== false ) { - - // helper method for a lot of the back compat extensions - $.ui.tabs.prototype._ui = function( tab, panel ) { - return { - tab: tab, - panel: panel, - index: this.anchors.index( tab ) - }; - }; - - // url method - $.widget( "ui.tabs", $.ui.tabs, { - url: function( index, url ) { - this.anchors.eq( index ).attr( "href", url ); - } - }); - - // TODO: Remove _ajaxSettings() method when removing this extension - // ajaxOptions and cache options - $.widget( "ui.tabs", $.ui.tabs, { - options: { - ajaxOptions: null, - cache: false - }, - - _create: function() { - this._super(); - - var that = this; - - this._on({ tabsbeforeload: function( event, ui ) { - // tab is already cached - if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) { - event.preventDefault(); - return; - } - - ui.jqXHR.success(function() { - if ( that.options.cache ) { - $.data( ui.tab[ 0 ], "cache.tabs", true ); - } - }); - }}); - }, - - _ajaxSettings: function( anchor, event, ui ) { - var ajaxOptions = this.options.ajaxOptions; - return $.extend( {}, ajaxOptions, { - error: function( xhr, status ) { - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - ajaxOptions.error( - xhr, status, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] ); - } - catch ( error ) {} - } - }, this._superApply( arguments ) ); - }, - - _setOption: function( key, value ) { - // reset cache if switching from cached to not cached - if ( key === "cache" && value === false ) { - this.anchors.removeData( "cache.tabs" ); - } - this._super( key, value ); - }, - - _destroy: function() { - this.anchors.removeData( "cache.tabs" ); - this._super(); - }, - - url: function( index ){ - this.anchors.eq( index ).removeData( "cache.tabs" ); - this._superApply( arguments ); - } - }); - - // abort method - $.widget( "ui.tabs", $.ui.tabs, { - abort: function() { - if ( this.xhr ) { - this.xhr.abort(); - } - } - }); - - // spinner - $.widget( "ui.tabs", $.ui.tabs, { - options: { - spinner: "<em>Loading…</em>" - }, - _create: function() { - this._super(); - this._on({ - tabsbeforeload: function( event, ui ) { - // Don't react to nested tabs or tabs that don't use a spinner - if ( event.target !== this.element[ 0 ] || - !this.options.spinner ) { - return; - } - - var span = ui.tab.find( "span" ), - html = span.html(); - span.html( this.options.spinner ); - ui.jqXHR.complete(function() { - span.html( html ); - }); - } - }); - } - }); - - // enable/disable events - $.widget( "ui.tabs", $.ui.tabs, { - options: { - enable: null, - disable: null - }, - - enable: function( index ) { - var options = this.options, - trigger; - - if ( index && options.disabled === true || - ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) !== -1 ) ) { - trigger = true; - } - - this._superApply( arguments ); - - if ( trigger ) { - this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - } - }, - - disable: function( index ) { - var options = this.options, - trigger; - - if ( index && options.disabled === false || - ( $.isArray( options.disabled ) && $.inArray( index, options.disabled ) === -1 ) ) { - trigger = true; - } - - this._superApply( arguments ); - - if ( trigger ) { - this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - } - } - }); - - // add/remove methods and events - $.widget( "ui.tabs", $.ui.tabs, { - options: { - add: null, - remove: null, - tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>" - }, - - add: function( url, label, index ) { - if ( index === undefined ) { - index = this.anchors.length; - } - - var doInsertAfter, panel, - options = this.options, - li = $( options.tabTemplate - .replace( /#\{href\}/g, url ) - .replace( /#\{label\}/g, label ) ), - id = !url.indexOf( "#" ) ? - url.replace( "#", "" ) : - this._tabId( li ); - - li.addClass( "ui-state-default ui-corner-top" ).data( "ui-tabs-destroy", true ); - li.attr( "aria-controls", id ); - - doInsertAfter = index >= this.tabs.length; - - // try to find an existing element before creating a new one - panel = this.element.find( "#" + id ); - if ( !panel.length ) { - panel = this._createPanel( id ); - if ( doInsertAfter ) { - if ( index > 0 ) { - panel.insertAfter( this.panels.eq( -1 ) ); - } else { - panel.appendTo( this.element ); - } - } else { - panel.insertBefore( this.panels[ index ] ); - } - } - panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ).hide(); - - if ( doInsertAfter ) { - li.appendTo( this.tablist ); - } else { - li.insertBefore( this.tabs[ index ] ); - } - - options.disabled = $.map( options.disabled, function( n ) { - return n >= index ? ++n : n; - }); - - this.refresh(); - if ( this.tabs.length === 1 && options.active === false ) { - this.option( "active", 0 ); - } - - this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; - }, - - remove: function( index ) { - index = this._getIndex( index ); - var options = this.options, - tab = this.tabs.eq( index ).remove(), - panel = this._getPanelForTab( tab ).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - // We check for more than 2 tabs, because if there are only 2, - // then when we remove this tab, there will only be one tab left - // so we don't need to detect which tab to activate. - if ( tab.hasClass( "ui-tabs-active" ) && this.anchors.length > 2 ) { - this._activate( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); - } - - options.disabled = $.map( - $.grep( options.disabled, function( n ) { - return n !== index; - }), - function( n ) { - return n >= index ? --n : n; - }); - - this.refresh(); - - this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) ); - return this; - } - }); - - // length method - $.widget( "ui.tabs", $.ui.tabs, { - length: function() { - return this.anchors.length; - } - }); - - // panel ids (idPrefix option + title attribute) - $.widget( "ui.tabs", $.ui.tabs, { - options: { - idPrefix: "ui-tabs-" - }, - - _tabId: function( tab ) { - var a = tab.is( "li" ) ? tab.find( "a[href]" ) : tab; - a = a[0]; - return $( a ).closest( "li" ).attr( "aria-controls" ) || - a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF\-]/g, "" ) || - this.options.idPrefix + getNextTabId(); - } - }); - - // _createPanel method - $.widget( "ui.tabs", $.ui.tabs, { - options: { - panelTemplate: "<div></div>" - }, - - _createPanel: function( id ) { - return $( this.options.panelTemplate ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .data( "ui-tabs-destroy", true ); - } - }); - - // selected option - $.widget( "ui.tabs", $.ui.tabs, { - _create: function() { - var options = this.options; - if ( options.active === null && options.selected !== undefined ) { - options.active = options.selected === -1 ? false : options.selected; - } - this._super(); - options.selected = options.active; - if ( options.selected === false ) { - options.selected = -1; - } - }, - - _setOption: function( key, value ) { - if ( key !== "selected" ) { - return this._super( key, value ); - } - - var options = this.options; - this._super( "active", value === -1 ? false : value ); - options.selected = options.active; - if ( options.selected === false ) { - options.selected = -1; - } - }, - - _eventHandler: function() { - this._superApply( arguments ); - this.options.selected = this.options.active; - if ( this.options.selected === false ) { - this.options.selected = -1; - } - } - }); - - // show and select event - $.widget( "ui.tabs", $.ui.tabs, { - options: { - show: null, - select: null - }, - _create: function() { - this._super(); - if ( this.options.active !== false ) { - this._trigger( "show", null, this._ui( - this.active.find( ".ui-tabs-anchor" )[ 0 ], - this._getPanelForTab( this.active )[ 0 ] ) ); - } - }, - _trigger: function( type, event, data ) { - var tab, panel, - ret = this._superApply( arguments ); - - if ( !ret ) { - return false; - } - - if ( type === "beforeActivate" ) { - tab = data.newTab.length ? data.newTab : data.oldTab; - panel = data.newPanel.length ? data.newPanel : data.oldPanel; - ret = this._super( "select", event, { - tab: tab.find( ".ui-tabs-anchor" )[ 0], - panel: panel[ 0 ], - index: tab.closest( "li" ).index() - }); - } else if ( type === "activate" && data.newTab.length ) { - ret = this._super( "show", event, { - tab: data.newTab.find( ".ui-tabs-anchor" )[ 0 ], - panel: data.newPanel[ 0 ], - index: data.newTab.closest( "li" ).index() - }); - } - return ret; - } - }); - - // select method - $.widget( "ui.tabs", $.ui.tabs, { - select: function( index ) { - index = this._getIndex( index ); - if ( index === -1 ) { - if ( this.options.collapsible && this.options.selected !== -1 ) { - index = this.options.selected; - } else { - return; - } - } - this.anchors.eq( index ).trigger( this.options.event + this.eventNamespace ); - } - }); - - // cookie option - (function() { - - var listId = 0; - - $.widget( "ui.tabs", $.ui.tabs, { - options: { - cookie: null // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } - }, - _create: function() { - var options = this.options, - active; - if ( options.active == null && options.cookie ) { - active = parseInt( this._cookie(), 10 ); - if ( active === -1 ) { - active = false; - } - options.active = active; - } - this._super(); - }, - _cookie: function( active ) { - var cookie = [ this.cookie || - ( this.cookie = this.options.cookie.name || "ui-tabs-" + (++listId) ) ]; - if ( arguments.length ) { - cookie.push( active === false ? -1 : active ); - cookie.push( this.options.cookie ); - } - return $.cookie.apply( null, cookie ); - }, - _refresh: function() { - this._super(); - if ( this.options.cookie ) { - this._cookie( this.options.active, this.options.cookie ); - } - }, - _eventHandler: function() { - this._superApply( arguments ); - if ( this.options.cookie ) { - this._cookie( this.options.active, this.options.cookie ); - } - }, - _destroy: function() { - this._super(); - if ( this.options.cookie ) { - this._cookie( null, this.options.cookie ); - } - } - }); - - })(); - - // load event - $.widget( "ui.tabs", $.ui.tabs, { - _trigger: function( type, event, data ) { - var _data = $.extend( {}, data ); - if ( type === "load" ) { - _data.panel = _data.panel[ 0 ]; - _data.tab = _data.tab.find( ".ui-tabs-anchor" )[ 0 ]; - } - return this._super( type, event, _data ); - } - }); - - // fx option - // The new animation options (show, hide) conflict with the old show callback. - // The old fx option wins over show/hide anyway (always favor back-compat). - // If a user wants to use the new animation API, they must give up the old API. - $.widget( "ui.tabs", $.ui.tabs, { - options: { - fx: null // e.g. { height: "toggle", opacity: "toggle", duration: 200 } - }, - - _getFx: function() { - var hide, show, - fx = this.options.fx; - - if ( fx ) { - if ( $.isArray( fx ) ) { - hide = fx[ 0 ]; - show = fx[ 1 ]; - } else { - hide = show = fx; - } - } - - return fx ? { show: show, hide: hide } : null; - }, - - _toggle: function( event, eventData ) { - var that = this, - toShow = eventData.newPanel, - toHide = eventData.oldPanel, - fx = this._getFx(); - - if ( !fx ) { - return this._super( event, eventData ); - } - - that.running = true; - - function complete() { - that.running = false; - that._trigger( "activate", event, eventData ); - } - - function show() { - eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); - - if ( toShow.length && fx.show ) { - toShow - .animate( fx.show, fx.show.duration, function() { - complete(); - }); - } else { - toShow.show(); - complete(); - } - } - - // start out by hiding, then showing, then completing - if ( toHide.length && fx.hide ) { - toHide.animate( fx.hide, fx.hide.duration, function() { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - show(); - }); - } else { - eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); - toHide.hide(); - show(); - } - } - }); -} - -})( jQuery ); - -(function( $ ) { - -var increments = 0; - -function addDescribedBy( elem, id ) { - var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); - describedby.push( id ); - elem - .data( "ui-tooltip-id", id ) - .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); -} - -function removeDescribedBy( elem ) { - var id = elem.data( "ui-tooltip-id" ), - describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), - index = $.inArray( id, describedby ); - if ( index !== -1 ) { - describedby.splice( index, 1 ); - } - - elem.removeData( "ui-tooltip-id" ); - describedby = $.trim( describedby.join( " " ) ); - if ( describedby ) { - elem.attr( "aria-describedby", describedby ); - } else { - elem.removeAttr( "aria-describedby" ); - } -} - -$.widget( "ui.tooltip", { - version: "1.9.2", - options: { - content: function() { - return $( this ).attr( "title" ); - }, - hide: true, - // Disabled elements have inconsistent behavior across browsers (#8661) - items: "[title]:not([disabled])", - position: { - my: "left top+15", - at: "left bottom", - collision: "flipfit flip" - }, - show: true, - tooltipClass: null, - track: false, - - // callbacks - close: null, - open: null - }, - - _create: function() { - this._on({ - mouseover: "open", - focusin: "open" - }); - - // IDs of generated tooltips, needed for destroy - this.tooltips = {}; - // IDs of parent tooltips where we removed the title attribute - this.parents = {}; - - if ( this.options.disabled ) { - this._disable(); - } - }, - - _setOption: function( key, value ) { - var that = this; - - if ( key === "disabled" ) { - this[ value ? "_disable" : "_enable" ](); - this.options[ key ] = value; - // disable element style changes - return; - } - - this._super( key, value ); - - if ( key === "content" ) { - $.each( this.tooltips, function( id, element ) { - that._updateContent( element ); - }); - } - }, - - _disable: function() { - var that = this; - - // close open tooltips - $.each( this.tooltips, function( id, element ) { - var event = $.Event( "blur" ); - event.target = event.currentTarget = element[0]; - that.close( event, true ); - }); - - // remove title attributes to prevent native tooltips - this.element.find( this.options.items ).andSelf().each(function() { - var element = $( this ); - if ( element.is( "[title]" ) ) { - element - .data( "ui-tooltip-title", element.attr( "title" ) ) - .attr( "title", "" ); - } - }); - }, - - _enable: function() { - // restore title attributes - this.element.find( this.options.items ).andSelf().each(function() { - var element = $( this ); - if ( element.data( "ui-tooltip-title" ) ) { - element.attr( "title", element.data( "ui-tooltip-title" ) ); - } - }); - }, - - open: function( event ) { - var that = this, - target = $( event ? event.target : this.element ) - // we need closest here due to mouseover bubbling, - // but always pointing at the same event target - .closest( this.options.items ); - - // No element to show a tooltip for or the tooltip is already open - if ( !target.length || target.data( "ui-tooltip-id" ) ) { - return; - } - - if ( target.attr( "title" ) ) { - target.data( "ui-tooltip-title", target.attr( "title" ) ); - } - - target.data( "ui-tooltip-open", true ); - - // kill parent tooltips, custom or native, for hover - if ( event && event.type === "mouseover" ) { - target.parents().each(function() { - var parent = $( this ), - blurEvent; - if ( parent.data( "ui-tooltip-open" ) ) { - blurEvent = $.Event( "blur" ); - blurEvent.target = blurEvent.currentTarget = this; - that.close( blurEvent, true ); - } - if ( parent.attr( "title" ) ) { - parent.uniqueId(); - that.parents[ this.id ] = { - element: this, - title: parent.attr( "title" ) - }; - parent.attr( "title", "" ); - } - }); - } - - this._updateContent( target, event ); - }, - - _updateContent: function( target, event ) { - var content, - contentOption = this.options.content, - that = this, - eventType = event ? event.type : null; - - if ( typeof contentOption === "string" ) { - return this._open( event, target, contentOption ); - } - - content = contentOption.call( target[0], function( response ) { - // ignore async response if tooltip was closed already - if ( !target.data( "ui-tooltip-open" ) ) { - return; - } - // IE may instantly serve a cached response for ajax requests - // delay this call to _open so the other call to _open runs first - that._delay(function() { - // jQuery creates a special event for focusin when it doesn't - // exist natively. To improve performance, the native event - // object is reused and the type is changed. Therefore, we can't - // rely on the type being correct after the event finished - // bubbling, so we set it back to the previous value. (#8740) - if ( event ) { - event.type = eventType; - } - this._open( event, target, response ); - }); - }); - if ( content ) { - this._open( event, target, content ); - } - }, - - _open: function( event, target, content ) { - var tooltip, events, delayedShow, - positionOption = $.extend( {}, this.options.position ); - - if ( !content ) { - return; - } - - // Content can be updated multiple times. If the tooltip already - // exists, then just update the content and bail. - tooltip = this._find( target ); - if ( tooltip.length ) { - tooltip.find( ".ui-tooltip-content" ).html( content ); - return; - } - - // if we have a title, clear it to prevent the native tooltip - // we have to check first to avoid defining a title if none exists - // (we don't want to cause an element to start matching [title]) - // - // We use removeAttr only for key events, to allow IE to export the correct - // accessible attributes. For mouse events, set to empty string to avoid - // native tooltip showing up (happens only when removing inside mouseover). - if ( target.is( "[title]" ) ) { - if ( event && event.type === "mouseover" ) { - target.attr( "title", "" ); - } else { - target.removeAttr( "title" ); - } - } - - tooltip = this._tooltip( target ); - addDescribedBy( target, tooltip.attr( "id" ) ); - tooltip.find( ".ui-tooltip-content" ).html( content ); - - function position( event ) { - positionOption.of = event; - if ( tooltip.is( ":hidden" ) ) { - return; - } - tooltip.position( positionOption ); - } - if ( this.options.track && event && /^mouse/.test( event.type ) ) { - this._on( this.document, { - mousemove: position - }); - // trigger once to override element-relative positioning - position( event ); - } else { - tooltip.position( $.extend({ - of: target - }, this.options.position ) ); - } - - tooltip.hide(); - - this._show( tooltip, this.options.show ); - // Handle tracking tooltips that are shown with a delay (#8644). As soon - // as the tooltip is visible, position the tooltip using the most recent - // event. - if ( this.options.show && this.options.show.delay ) { - delayedShow = setInterval(function() { - if ( tooltip.is( ":visible" ) ) { - position( positionOption.of ); - clearInterval( delayedShow ); - } - }, $.fx.interval ); - } - - this._trigger( "open", event, { tooltip: tooltip } ); - - events = { - keyup: function( event ) { - if ( event.keyCode === $.ui.keyCode.ESCAPE ) { - var fakeEvent = $.Event(event); - fakeEvent.currentTarget = target[0]; - this.close( fakeEvent, true ); - } - }, - remove: function() { - this._removeTooltip( tooltip ); - } - }; - if ( !event || event.type === "mouseover" ) { - events.mouseleave = "close"; - } - if ( !event || event.type === "focusin" ) { - events.focusout = "close"; - } - this._on( true, target, events ); - }, - - close: function( event ) { - var that = this, - target = $( event ? event.currentTarget : this.element ), - tooltip = this._find( target ); - - // disabling closes the tooltip, so we need to track when we're closing - // to avoid an infinite loop in case the tooltip becomes disabled on close - if ( this.closing ) { - return; - } - - // only set title if we had one before (see comment in _open()) - if ( target.data( "ui-tooltip-title" ) ) { - target.attr( "title", target.data( "ui-tooltip-title" ) ); - } - - removeDescribedBy( target ); - - tooltip.stop( true ); - this._hide( tooltip, this.options.hide, function() { - that._removeTooltip( $( this ) ); - }); - - target.removeData( "ui-tooltip-open" ); - this._off( target, "mouseleave focusout keyup" ); - // Remove 'remove' binding only on delegated targets - if ( target[0] !== this.element[0] ) { - this._off( target, "remove" ); - } - this._off( this.document, "mousemove" ); - - if ( event && event.type === "mouseleave" ) { - $.each( this.parents, function( id, parent ) { - $( parent.element ).attr( "title", parent.title ); - delete that.parents[ id ]; - }); - } - - this.closing = true; - this._trigger( "close", event, { tooltip: tooltip } ); - this.closing = false; - }, - - _tooltip: function( element ) { - var id = "ui-tooltip-" + increments++, - tooltip = $( "<div>" ) - .attr({ - id: id, - role: "tooltip" - }) - .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + - ( this.options.tooltipClass || "" ) ); - $( "<div>" ) - .addClass( "ui-tooltip-content" ) - .appendTo( tooltip ); - tooltip.appendTo( this.document[0].body ); - if ( $.fn.bgiframe ) { - tooltip.bgiframe(); - } - this.tooltips[ id ] = element; - return tooltip; - }, - - _find: function( target ) { - var id = target.data( "ui-tooltip-id" ); - return id ? $( "#" + id ) : $(); - }, - - _removeTooltip: function( tooltip ) { - tooltip.remove(); - delete this.tooltips[ tooltip.attr( "id" ) ]; - }, - - _destroy: function() { - var that = this; - - // close open tooltips - $.each( this.tooltips, function( id, element ) { - // Delegate to close method to handle common cleanup - var event = $.Event( "blur" ); - event.target = event.currentTarget = element[0]; - that.close( event, true ); - - // Remove immediately; destroying an open tooltip doesn't use the - // hide animation - $( "#" + id ).remove(); - - // Restore the title - if ( element.data( "ui-tooltip-title" ) ) { - element.attr( "title", element.data( "ui-tooltip-title" ) ); - element.removeData( "ui-tooltip-title" ); - } - }); - } -}); - -}( jQuery ) ); diff --git a/unittests/example_labfolder_data/static/js/labfolder-global.js b/unittests/example_labfolder_data/static/js/labfolder-global.js deleted file mode 100644 index 0e69b6a2..00000000 --- a/unittests/example_labfolder_data/static/js/labfolder-global.js +++ /dev/null @@ -1,81 +0,0 @@ -$(document).ready(function(){ - Global.init(); -}); - -var Global = { - - init: function(){ - var globalData = $("#global_data"); - - // firstLogin - this.firstLogin = (globalData.attr("data-firstlogin") == "true") ? true : false; - - // currentUser - this.userShowHiddenItems = (globalData.attr("data-user-show-hidden-items") == "true") ? true : false; - this.userId = globalData.attr("data-user-id"); - this.userProfilePictureHash = globalData.attr("data-user-profilePictureHash"); - this.userFirstName = globalData.attr("data-user-firstName"); - this.userLastName = globalData.attr("data-user-lastName"); - this.userProfileComplete = (globalData.attr("data-user-profileComplete") == "true") ? true : false; - this.orderASC = (globalData.attr("data-user-orderASC") == "true" ) ? true : false; - - // currentProject - this.projectId = globalData.attr("data-project-id"); - this.projectIsTemplate = (globalData.attr("data-project-is-template") == "true") ? true : false; - this.projectIsHidden = (globalData.attr("data-project-is-hidden") == "true") ? true : false; - - // currentGroup - this.groupId = globalData.attr("data-group-id"); - this.groupType = globalData.attr("data-group-type"); - this.groupSettingsPreventDeleteProject = (globalData.attr("data-group-settings-prevent-delete-project") == "true") ? true : false; - - // currentGroupMemberAdminLevels - this.groupMemberAdminLevels = []; - var groupMemberAdminLevelsStr = globalData.attr("data-group-member-admin-levels"); - if(groupMemberAdminLevelsStr) { - var arr = groupMemberAdminLevelsStr.split(","); - for(var i=0; i<arr.length; i++) { - var trimmed = $.trim(arr[i]); - if(trimmed != "") { - this.groupMemberAdminLevels.push(trimmed); - } - } - } - - this.installedApps = []; - var installedAppsStr = globalData.attr("data-installed-apps"); - if(installedAppsStr) { - var arr = installedAppsStr.split(","); - for(var i=0; i<arr.length; i++) { - var trimmed = $.trim(arr[i]); - if(trimmed != "") { - this.installedApps.push(trimmed); - } - } - } - - this.buildNumber = globalData.attr("data-build-number"); - - this.viewname = $("#data_element").attr("data-viewname"); - - }, - - isGroupAdmin: function(subgroupId) { - for (var i = 0; i < this.groupMemberAdminLevels.length; i++) { - if(this.groupMemberAdminLevels[i] == subgroupId) { - return true; - } - } - return false; - }, - - isAppInstalled: function(appKey) { - for (var i = 0; i < this.installedApps.length; i++) { - if(this.installedApps[i] == appKey) { - return true; - } - } - return false; - } - -} diff --git a/unittests/example_labfolder_data/static/js/tree.js b/unittests/example_labfolder_data/static/js/tree.js deleted file mode 100644 index 180c8600..00000000 --- a/unittests/example_labfolder_data/static/js/tree.js +++ /dev/null @@ -1,505 +0,0 @@ -function initTreelineButtonsElnProjects(treeId) { - initTreelineMoreOptionsDeleteFolder(treeId, "/eln/workspace/{id}/isEmpty", "/eln/workspace/{id}/delete"); -} - -function initTreelineButtonsTextTemplates(treeId) { - initTreelineMoreOptionsDeleteFolder(treeId, "/eln/workspace/{id}/isEmpty", "/eln/workspace/{id}/delete"); -} - -var TreeElement = { - - createNew: function(item, elType, group, callback) { - - var saveCallback = function(formData) { - var formObj = convertFormArrayToObject(formData); - TreeElement.saveNew(item, elType, formObj, callback); - }; - - var isTemplate = (elType == "TEMPLATE"); - var itemName = isTemplate ? "template" : "project"; - - var options = { - templateName: "jsTemplate_workspace_create_project_dialog", - treeId: "project_popup", - treeUrl: "/eln/workspace/treeInPopup", - template: isTemplate, - showTreeFoldersOnly: true, - treeFolderSelectable: true, - treeItemSelectable: false, - selectedTreelineCallback: function(formData){ - saveCallback(formData); - } - }; - - if(item == "item"){ - openSelectTreelineDialog("Create " + itemName, options); - - }else if(item == "folder"){ - options.templateName= "jsTemplate_workspace_create_folder_dialog"; - openSelectTreelineDialog("Create folder", options); - } - }, - - saveNew: function(item, elType, formObj, fCallback){ - - var formData = { - name: formObj.name, - groupId: formObj.selectedTreelineGroupId, - parentId: formObj.selectedTreelineObjectId, - csrfToken: getCSRFToken(), - type: elType - }; - - var callback; - - var postUrl; - - if(item == "item"){ - - postUrl = "/eln/workspace/createProject"; - - callback = function(data, textStatus, jqXHR){ - - if(data.status == 0) { - if (data.dataObj.groupId > 0 && data.dataObj.shareable) { - Group.projects.shareEdit(data.dataObj.id, data.dataObj.groupId); - - } else if(fCallback) { - fCallback(data); - - } else { - Dialog.close(); - location.reload(true); - } - - } else { - Dialog.showError(data.errorMessageList); - } - - } - } - else if(item == "folder"){ - - postUrl = "/eln/workspace/createFolder"; - - callback = function(data, textStatus, jqXHR){ - - if(data.status == 0) { - - Dialog.close(); - - var itemName = (elType == "TEMPLATE") ? "templates" : "projects"; - - var targetFolder = $("#treeline_eln_" + itemName +"_" + formObj.selectedTreelineGroupId + "_" + formObj.selectedTreelineObjectId).next(); - - var shareSettings = ""; - if(data.dataObj.shareable) { - shareSettings = "<div class='more_options_item buttonShareSettings'>" + - "<span aria-hidden='true' class='icon-conf'></span> Share settings" + - "</div>"; - } - - var newFolder = $("<a id='treeline_eln_" + itemName + "_" + formObj.selectedTreelineGroupId + "_" - + data.dataObj.id + "' data-groupid='" + formObj.selectedTreelineGroupId + "' " - + "data-objectid='" + data.dataObj.id + "' class='treeline is_folder is_open_folder'>") - .append("<span class='updateTS'>"+ data.dataObj.createTS + "</span>") - .append("<div class='tree_button more_options in_tree'>" - +"<button class='more_options_button_tree'><span aria-hidden='true' class='wheel-img'></span></button>" - +"<div class='more_options_panel in_tree' style='display: none;'>" - - +"<span class='menu_arrow-img'></span>" - +"<ul>" - +"<li class='more_options_item buttonRename'>Rename folder<span class='edit-img'></span></li>" - +"<li class='more_options_item treelineButtonDeleteFolder'>Delete folder<span class='trash_dark-img'></span></li>" - +"</ul>" - +"</div>" - +"</div>") - .append("<span class='folder_dn-img'></span>") - .append("<span class='name'> " + formObj.name + "</span>"); - - makeDroppable(newFolder); - makeDraggable(newFolder); - - var newChildren = $("<div class='treeline_children'><div class='treeline_children_empty'>empty folder</div></div>"); - newFolder.after(newChildren).hide(); - - targetFolder.append(newFolder).children(".treeline_children_empty").slideUp(300,function(){ - this.remove(); - }); - - newFolder.eq(0).css("background", "rgb(236, 240, 243)"); - - newFolder.show(300, function() { - $(newFolder.parents(".treeline_children").siblings(".is_folder")).each(function(){ - openTreelineFolder($(this)); - }); - newFolder.eq(0).css("overflow", "visible"); - setTimeout(function(){ - // TODO we should have exactly 1 main element in all pages - // in all projects page we have #eln_main_content - // in group projects page we have #eln_project_content - $("#eln_main_content, #eln_project_content").animate({ - scrollTop: $(newFolder).offset().top-200 - }, 500); - },500); - }); - - } else { - Dialog.showError(data.errorMessageList); - } - } - } - - $.post(postUrl, formData, function(data, textStatus, jqXHR){ - callback(data, textStatus, jqXHR); - }); - - } -} - - - -function initTreelineMoreOptionsDeleteFolder(treeId, isEmptyUrl, deleteUrl) { - $("body").on("click", ".treelineButtonDeleteFolder", function(){ - var treeline = $(this).closest("a.treeline"); - var objectId = treeline.attr("data-objectId"); - - var isEmptyUrlReplaced = isEmptyUrl.replace("{id}", objectId); - $.get(isEmptyUrlReplaced, {}, function(data, textStatus, jqXHR){ - if(data.status == 0) { - if(data.dataObj == true) { - - var templateData = { treeline_name: treeline.find("span.name").text() }; - var content = $.jsTemplate("jsTemplate_basic_delete_folder_dialog", templateData); - - var confirmButtonCallback = function() { - var deleteUrlReplaced = deleteUrl.replace("{id}", objectId); - $.post(deleteUrlReplaced, {csrfToken: getCSRFToken()}, function(data, textStatus, jqXHR){ - if(data.status == 0) { - var parentLine = treeline.parent(); - treeline.next().andSelf().slideUp(300, function(){ - this.remove(); - if(parentLine.children().length == 0){ - var emptyChildren = $("<div class='treeline_children_empty' style='display:none'>empty folder</div>"); - parentLine.append(emptyChildren); - emptyChildren.slideDown(300); - } - }); - Dialog.close(); - } else { - Dialog.showError(data.errorMessageList); - } - }); - }; - Dialog.confirm("Delete folder", content, {text: "Delete", callback: confirmButtonCallback}); - - } else { - Dialog.alert("Delete folder"); - Dialog.showError("This folder is not empty. Please delete all of its content first, then you can delete the folder itself"); - } - } else { - return ; - } - }); - - $(".more_options_panel").hide(); - return false; - }); -} - - -function selectTreeline(treeId, groupId, objectId) { - $("#tree_" + treeId + " input[name=selectedTreelineGroupId]").val(groupId); - $("#tree_" + treeId + " input[name=selectedTreelineObjectId]").val(objectId); - $("#tree_" + treeId + " .treeline").removeClass("selected"); - $("#treeline_" + treeId + "_" + groupId + "_" + objectId).addClass("selected"); -} - - - -function openSelectTreelineDialog(dialogTitle, options) { - - var content = $.jsTemplate(options.templateName, null); - - var confirmButtonCallback = function() { - var groupId = $("#tree_" + options.treeId + " input[name=selectedTreelineGroupId]").val(); - var objectId = $("#tree_" + options.treeId + " input[name=selectedTreelineObjectId]").val(); - - if(groupId == "" || objectId == "") { - if(dialogTitle == "Use template"){ - - Dialog.showError("Please select a template that you would like to use"); - - } else if(dialogTitle == "Save as new template"){ - - Dialog.showError("Please select a template folder"); - - }else if(dialogTitle == "Create a new entry"){ - - setTimeout(function(){Dialog.showError("Please select a project");}, 300); - } - - } else { - var formData = $("#my_popup_content form").serializeArray(); - options.selectedTreelineCallback(formData); - } - }; - - var loadedCallback = function() { - $.get(options.treeUrl, - { - treeId: options.treeId, - template: options.template, - showTreeFoldersOnly: options.showTreeFoldersOnly, - treeFolderSelectable: options.treeFolderSelectable, - treeItemSelectable: options.treeItemSelectable - }, - function(data, textStatus, jqXHR){ - var selectTree = $(data); - - $("#my_popup_content .spinner").fadeOut(300, function(){ - $("#my_popup_content .treeInPopupContainer").html(selectTree).slideDown(300, function(){ - var firstLine = $("#tree_project_popup a").first(); - selectTreeline(options.treeId, firstLine.attr("data-groupid"), firstLine.attr("data-objectid")); - Dialog.center(); - initTreelineFolders(options.treeId); - }); - }); - } - ); - - $("#my_popup_content input:first").focus(); - $("#my_popup_content form").submit(function(){ - confirmButtonCallback(); - return false; - }); - - }; - - Dialog.confirm(dialogTitle, content, {text: dialogTitle, callback: confirmButtonCallback}, {}, {}, loadedCallback); -} - -function moveProject(objectId, groupId, parentId){ - $.post("/eln/workspace/" + objectId + "/move", - { - "csrfToken": getCSRFToken(), - "parentId": parentId - }, - function(data){ - if(data.status != 0) { - Dialog.showError(data.errorMessageList); - } - } - ); -} - -function bindTreeUI(){ - //Hacky hack to fix jquery bug in 1.8.2 that adds overflow hidden when animating hide and show - $('body').on('mouseover', '.treeline, .treeline_children', function(){ - if($(this).css('overflow') == "hidden" ) $(this).css("overflow", "visible"); - }); - - var droppableScope = $("a.is_folder"); - makeDroppable(droppableScope); - - var draggableScope = $("a.is_folder, a.is_item").not($("[data-objectid='0']")); - makeDraggable(draggableScope); -} - -function makeDroppable(elements){ - - elements.droppable({ - accept: function(el){ - if(el.hasClass("is_item")){ - return (el.attr("data-groupid") == $(this).attr("data-groupid")); - } - else { - var notOwnChild = (el.next().find($(this)).length == 0); - if(el.hasClass("is_folder") && notOwnChild) return (el.attr("data-groupid") == $(this).attr("data-groupid")); - } - }, - activeClass: "droppable_folder", - drop: function(event, ui){ - - var el = this; - var siblings = $(el).next().children("a"); - var inserted = false; - var originSiblings = ui.draggable.siblings("a").length; - var parent = ui.draggable.parent(); - - for(var i = 0; i < siblings.length; i++){ - - if(ui.draggable.hasClass("is_item")){ - if(siblings.eq(i).hasClass("is_folder")){ - ui.draggable.hide(300,function(){ - siblings.eq(i).before(ui.draggable.show(300)); - }); - inserted = true; - break; - } else if(siblings.eq(i).hasClass("is_item")){ - if(ui.draggable.find("span.name").text().trim().toLowerCase() < siblings.eq(i).find("span.name").text().trim().toLowerCase()){ - ui.draggable.hide(300,function(){ - siblings.eq(i).before(ui.draggable.show(300)); - }); - inserted = true; - break; - } - } - } else if(ui.draggable.hasClass("is_folder")){ - if(siblings.eq(i).hasClass("is_folder")){ - if(ui.draggable.find("span.name").text().trim().toLowerCase() < siblings.eq(i).find("span.name").text().trim().toLowerCase()){ - ui.draggable.next().andSelf().hide(300,function(){ - siblings.eq(i).before(ui.draggable.next().andSelf()); - if (ui.draggable.hasClass("is_open_folder")){ - ui.draggable.next().andSelf().show(300); - } - else ui.draggable.show(300); - }); - inserted = true; - break; - } - } - } - } - - if(!inserted){ - if(ui.draggable.hasClass("is_folder")){ - ui.draggable.next().andSelf().hide(300,function(){ - $(el).next().append(ui.draggable.next().andSelf()); - if (ui.draggable.hasClass("is_open_folder")){ - ui.draggable.next().andSelf().show(300); - } - else ui.draggable.show(300); - }); - } - else if(ui.draggable.hasClass("is_item")){ - ui.draggable.hide(300,function(){ - $(el).next().append(ui.draggable.show(300)); - }); - } - } - - if(originSiblings == 0){ - parent.append("<div class='treeline_children_empty'>empty folder</div>"); - } - - $(el).next().children(".treeline_children_empty").hide("fast", function(){ - $(this).remove(); - }); - - var objectId = ui.draggable.attr("data-objectid"); - var groupId = ui.draggable.attr("data-groupid"); - var parentId = $(el).attr("data-objectid"); - - moveProject(objectId, groupId, parentId); - - }, - hoverClass: "hover_droppable_folder" - }); -} - -function makeDraggable(elements){ - - elements.draggable({ - appendTo: '.eln_scroll-y', - cursorAt: { bottom: 15, left: 45 }, - distance: 25, - revert: "invalid", - revertDuration: 200, - helper: function(){ - var helper = $(this).clone(); - helper.addClass("dragging_helper").css({ - "height": "auto", - "line-height": "0", - "color": "#69bfee" - }).find(".tree_button, span.updateTS").remove(); - return helper; - }, - drag: function(event, ui){ - $(this).css("z-index", 20); - }, - stop: function(event, ui){ - - $(this).next().andSelf().css({ - 'position': 'relative', - 'top': '', - 'left': '', - 'z-index': '' - }); - - $(this).next().css('position', ''); - - $(".hover_droppable_folder").removeClass("hover_droppable_folder"); - } - }); -} - -function getCookieNameForTree(el) { - var treeId = el.parents(".tree_top_level").attr("data-treeid"); - return "tree_" + treeId + "_open_folders"; -} - -function initTreelineFolders(treeId) { - var cookieName = "tree_" + treeId + "_open_folders"; - var curValue = getCookieValue(cookieName); - if(curValue) { - var arr = curValue.split(","); - for(var i=0; i<arr.length; i++) { - var treeNode = $("#treeline_" + treeId + "_" + arr[i] + ".is_closed_folder"); - var treeNodeChildren = treeNode.next(".treeline_children"); - treeNode.removeClass("is_closed_folder").addClass("is_open_folder"); - treeNodeChildren.css("display", "block"); - } - } - - $("a.is_closed_folder").children("span.folder_dn-img").removeClass("folder_dn-img").addClass("folder_up-img"); - $("a.is_open_folder").children("span.folder_up-img").removeClass("folder_up-img").addClass("folder_dn-img"); -} - -function openTreelineFolder(treeNode) { - var treelineId = treeNode.attr("data-groupId") + "_" + treeNode.attr("data-objectId"); - var treeNodeChildren = treeNode.next(); - - if(treeNode.hasClass("is_closed_folder")){ - treeNodeChildren.slideDown(); - treeNode.removeClass("is_closed_folder").addClass("is_open_folder"); - treeNode.find("span.icon-arrow_right").removeClass("icon-arrow_right").addClass("icon-arrow_down"); - } -} - -$(document).ready(function() { - - if(Global.viewname == "WORKSPACE_INDEX") { - var treeId = "eln_projects"; - initTreelineFolders(treeId); - initTreelineButtonsElnProjects(treeId); - bindTreeUI(); - } else if(Global.viewname == "TEMPLATE_INDEX") { - var treeId = "eln_templates"; - initTreelineFolders(treeId); - initTreelineButtonsTextTemplates(treeId); - bindTreeUI(); - } - - $("body").on("click", "a.is_folder", function(event){ - - if($(event.target).hasClass("icon-conf_drop") || $(event.target).hasClass("default_button")) { - return; - } - - var treeNode = $(this); - var treeNodeChildren = treeNode.next(); - - if(treeNode.hasClass("is_closed_folder")) { - treeNodeChildren.slideDown(); - treeNode.removeClass("is_closed_folder").addClass("is_open_folder"); - treeNode.find("span.folder_up-img").removeClass("folder_up-img").addClass("folder_dn-img"); - } else { - treeNodeChildren.slideUp(); - treeNode.removeClass("is_open_folder").addClass("is_closed_folder"); - treeNode.find("span.folder_dn-img").removeClass("folder_dn-img").addClass("folder_up-img"); - } - }); - -}); - diff --git a/unittests/example_labfolder_data/templates.html b/unittests/example_labfolder_data/templates.html deleted file mode 100644 index 34037cc3..00000000 --- a/unittests/example_labfolder_data/templates.html +++ /dev/null @@ -1,135 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> - <meta name="apple-mobile-web-app-capable" content="yes"> - <meta name="apple-mobile-web-app-status-bar-style" - content="black-translucent"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Templates</title> - <link rel="shortcut icon" type="image/x-icon" - href="static/img/favicon2.ico" /> - - <script - src="static/js/jquery-1.8.2.min.js" - type="text/javascript"></script> - - <script src="static/js/tree.js" - type="text/javascript"></script> - - <!-- This must be the first labfolder JS file included --> - <script - src="static/js/labfolder-global.js?13fcc6eeb30608bb104f4b234c2fa3fd86699ffe" - type="text/javascript"></script> - - <link rel="stylesheet" type="text/css" - href="static/css/eln_layout.css" /> - - <link rel="stylesheet" type="text/css" - href="static/css/pixel_icon.css" /> - - <link rel="stylesheet" type="text/css" - href="static/css/tree.css" /> - - <link rel="stylesheet" type="text/css" - href="static/css/notebook.css" /> - -</head> -<body> -<div class="body_bg"></div> -<div class="eln_header eln_row"> - <div class="headerbar_top"> - <a href="/eln/"><span class="logo-img"></span></a> - <header> - <span aria-hidden="true" class="manage_s-img"></span> Templates - </header> - <nav> - <div class="nav_top"> - <ul> - <li><a href="projects.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Projects</p> - </button> - </a></li> - </ul> - </div> - </nav> - </div> - -</div> -<div class="action_bar clearfix"></div> -<div id="data_element" data-viewname="WORKSPACE_INDEX"></div> -<div id="eln_main_content" - class="eln_main_content eln_row eln_scroll-y"> - <div class="eln_main_content_box templates-list"> - <div class="headers"> - <div class="owner">Owner</div> - <div class="update">Last Modified</div> - <div class="created">Created</div> - </div> - <div class="tree_my_eln_projects tree_top_level" data-treeid="eln_projects"> - <a id="treeline_eln_projects_0_0" - data-groupid="0" - data-objectid="0" - data-ownerid="{{ownerId}}" - class="treeline is_folder ui-droppable is_closed_folder"> - <span class="updateTS"></span> - <span class="folder_up-img"></span> - <span class="name">My private templates</span> - <span class="details"> - <span class="box-owner"> - <label>Owner:</label> - - -</span> -<span class="box-last-update"> - <label>Last update:</label> - -</span> - - </span> - </a> - <div class="treeline_children"style="overflow: hidden; display: none;"><a id="treeline_eln_projects" data-id="118219" data-parentId="0" data-userId="30003" data-groupId="0" data-name="template2" data-folder="false" data-template="true" data-createTS="22.10.2019 15:54" data-hidden="false" data-shareable="false" data-owner-profilePictureHash="null" data-owner-tutorial="1" data-owner-zoneId="Europe/Berlin" data-owner-id="30003" data-owner-firstname="max" data-owner-lastname="muster" data-owner-email="max.muster@posteo.de" data-numberOfBlocks="1" data-lastEditedTS="22.10.2019 16:45" data-adminUserIds="[]" data-adminOrOwner="true" class="treeline is_item ui-draggable" href="./templates/My private templates_0/118219_template2/index.html"> - <span class="updateTS">22.10.2019 15:54</span> - <span class="project_s-img"></span> - <span class="name">template2</span> - <span class="details"> - <span class="box-owner"> - <label>Owner:</label> - max - muster -</span> -<span class="box-last-update"> - <label>Last update:</label> - 22.10.2019 16:45 -</span> - - </span> -</a> -<div class="treeline_children"style="overflow: hidden; display: none;"></div> -<a id="treeline_eln_projects" data-id="118218" data-parentId="0" data-userId="30003" data-groupId="0" data-name="test_template" data-folder="false" data-template="true" data-createTS="22.10.2019 15:54" data-hidden="false" data-shareable="false" data-owner-profilePictureHash="null" data-owner-tutorial="1" data-owner-zoneId="Europe/Berlin" data-owner-id="30003" data-owner-firstname="max" data-owner-lastname="muster" data-owner-email="max.muster@posteo.de" data-numberOfBlocks="1" data-lastEditedTS="22.10.2019 16:47" data-adminUserIds="[]" data-adminOrOwner="true" class="treeline is_item ui-draggable" href="./templates/My private templates_0/118218_test_template/index.html"> - <span class="updateTS">22.10.2019 15:54</span> - <span class="project_s-img"></span> - <span class="name">test_template</span> - <span class="details"> - <span class="box-owner"> - <label>Owner:</label> - max - muster -</span> -<span class="box-last-update"> - <label>Last update:</label> - 22.10.2019 16:47 -</span> - - </span> -</a> -<div class="treeline_children"style="overflow: hidden; display: none;"></div> -</div> -</div> - - </div> -</div> -</body> -</html> diff --git a/unittests/example_labfolder_data/templates/My private templates_0/118218_test_template/index.html b/unittests/example_labfolder_data/templates/My private templates_0/118218_test_template/index.html deleted file mode 100644 index 0fb347c6..00000000 --- a/unittests/example_labfolder_data/templates/My private templates_0/118218_test_template/index.html +++ /dev/null @@ -1,437 +0,0 @@ -<html> -<head> - <style type="text/css"> - @charset "UTF-8"; - [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak, .ng-hide:not(.ng-hide-animate) { - display: none !important; - } - - ng\:form { - display: block; - } - </style> - - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> - <meta name="apple-mobile-web-app-capable" content="yes"> - <meta name="apple-mobile-web-app-status-bar-style" - content="black-translucent"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - - - <title>Notebook</title> - - - <link rel="shortcut icon" type="image/x-icon" - href="../../../static/img/favicon2.ico"> - - <script src="../../../static/js/jquery-1.8.2.min.js" - type="text/javascript"></script> - <style type="text/css"></style> - - - <!-- This must be the first labfolder JS file included --> - <script - src="../../../static/js/labfolder-global.js?no-build-number" - type="text/javascript"></script> - - <link rel="stylesheet" type="text/css" - href="../../../static/css/export-table-element.css"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/jquery-ui.css"> - - <link rel="stylesheet" type="text/css" - href="../../../static/css/data-elements.css?no-build-number"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/combined.css?no-build-number"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/export-entry-footer.css"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/redactor.css"/> - - <script type="text/javascript"> - function getTemplateText(className) { - return $("#jsTemplate_jsText").find(".jstext_" + className).text(); - } - - $(document).ready(function () { - // expand tags and custom dates container on hover - $(".entry_menu_less").hover( - function () { - if (!$(this).children(":first").hasClass("entry_name_menu")) { - $(this).addClass('entry_menu_more'); - $(this).children(":first").addClass('show_list_more'); - if ($(this).children(":first").hasClass("entry_tags")) { - $(".entry_tags").css("height", "auto"); - } - } - }, - function () { - if (!$(this).children(":first").hasClass("entry_name_menu")) { - $(this).removeClass('entry_menu_more'); - $(this).children(":first").removeClass('show_list_more'); - if ($(this).children(":first").hasClass("entry_tags")) { - $(".entry_tags").css("height", "100%"); - } - } - } - ); - - //selects the table sheet according to click - $(".sheet_tab").click(function () { - if ($(this).hasClass('selected') === false) { - var previous = $(this).siblings(".selected"); - var previousElementId = previous.data("elementid"); - var previousSheetIndex = previous.data("sheetidx"); - previous.removeClass("selected"); - - var targetElementId = $(this).data("elementid"); - var targetSheetIndex = $(this).data("sheetidx"); - $(this).addClass("selected"); - - $("#table_" + targetElementId + "_" + targetSheetIndex).css("display", "block"); - $("#table_" + previousElementId + "_" + previousSheetIndex).css("display", "none"); - } - }); - }); - </script> - - <script src="../../../static/js/jquery-ui.js" - type="text/javascript"></script> -</head> - -<body> -<div class="body_bg"></div> -<div id="global_data"></div> -<div class="eln_header eln_row"> - <div class="headerbar_top"> - <a href="/eln/"><span class="logo-img"></span></a> - <header> - <span class="notebook_s-img"></span> Notebook - </header> - <nav> - <div class="nav_top"> - <ul> - <li><a href="../../../projects.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Projects</p> - </button> - </a></li> - <li><a href="../../../templates.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Templates</p> - </button> - </a></li> - </ul> - </div> - </nav> - </div> - - -</div> -<div class="ng-scope"> - <div class="action_bar clearfix ng-scope"> - <div class="plus_btn_wrap"> - <div class="plus_btn_hover"> - <div class="add_dropdown more_options_menu" style="display: none;"> - <ul> - </ul> - </div> - </div> - </div> - <div class="action_menu_wrap"> - <div class="filter_wrap list_horizontal"></div> - </div> - </div> - <div id="eln_project_content" - class="eln_project_content eln_row eln_scroll-y ng-scope" data-id="118218" data-parentId="0" data-userId="30003" data-groupId="0" data-name="test_template" data-folder="false" data-template="true" data-createTS="22.10.2019 15:54" data-hidden="false" data-shareable="false" data-owner-profilePictureHash="null" data-owner-tutorial="1" data-owner-zoneId="Europe/Berlin" data-owner-id="30003" data-owner-firstname="max" data-owner-lastname="muster" data-owner-email="max.muster@posteo.de" data-numberOfBlocks="1" data-lastEditedTS="22.10.2019 16:47" data-adminUserIds="[]" data-adminOrOwner="true" > - <div id="epb_container"><div data-id="4625193"data-blockId="4624722"data-elnProjectId="118218"data-sourceId="0"data-userAction="2"data-groupId="0"data-hidden="false"data-readOnly="false"data-versionTS="22.10.2019 18:47"data-createTS="22.10.2019 17:54"data-signHash="null"data-signHashDescription=""data-signHashVersion="null"data-signTS="null"data-witnessTS="null"data-title="null"data-blockNumber="1"data-totalBlocksInProject="1"data-projectName="test_template"data-projectReferenceId="null"data-signBiometricsDocId="null"data-witnessBiometricsDocId="null"data-referenced="false"> - <div class="epb_header_container"> - <div class="epb_header clearfix" style="display: block;"> - - <div class="entry_container"> - <header class="entry_header"> - <div class="entry_author"> - <figure> - <span class="avatar-img"></span> - <img ng-src=""> - </figure> - - <div class="author_name"> - <div class="author_firstname ng-binding">max</div> - <div class="author_lastname ng-binding">muster</div> - </div> - </div> - <div class="entry_menu_less entry_title_wrap ng-scope"> - <div class="entry_name_menu has_tooltip"> - <ul> - <li> - <div style="display:none">Entry {{entryNumber}}/{{totalEntries}}:</div> - <div>Template:</div> - </li> - <li> - <div style="display:none" class="entry_title ng-binding">{{entryTitle}}</div> - <div>test_template</div> - </li> - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown entry_name"> - <div class="close_entry_menu"> - <span class="cancel_entry_title close_box-img"></span> - </div> - <ul> - <li><label>Entry name</label> <input - class="entry_name_input ng-pristine ng-untouched ng-valid" - type="text" data-title="" value=""></li> - <li><label>located in project</label> <select - class="ng-pristine ng-untouched ng-valid"> - <option - value="0">tableproject - </option> - <option value="1" selected="selected">a project</option> - </select></li> - <li> - <div class="save_entry_menu"> - <span class="cancel_dropdown cancel_entry_title grey_link" - ng-click="cancel()">cancel</span> - <button class="save_entry_title btn_on_grey" ng-click="save()">save</button> - </div> - </li> - </ul> - </div> - </div> - - <div class="entry_menus"> - <ul> - <li class="entry_menu_less ng-scope" - ng-controller="EntryDateController"> - <div class="entry_menu_list has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <ul> - <li><span>created:</span> <span class="ng-binding">22.10.2019 17:54</span> - </li> - <li><span>modified</span> <span class="ng-binding">22.10.2019 18:47</span> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li> - <span>todo</span> - <span class=\"ng-binding\">24.10.2019</span> -</li> - - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown" - ng-mouseenter="activateElement($event)"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <ul class="entry_dates"> - <li><label>Dates</label></li> - <li> - <div class="date_key"> - <input type="text" value="created" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.createTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <li> - <div class="date_key"> - <input type="text" value="modified" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.versionTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li style="overflow: visible;"> - <div class="date_key"> - - <div class="selectize-control single ng-valid" - ng-keyup="updateInput($select.search)" - reset-search-input="false" ng-model="dateKeyInput.selected" - theme="selectize" style="min-width: 120px;"> - <div class="selectize-input" - ng-class="{'focus': $select.open, 'disabled': $select.disabled, 'selectize-focus' : $select.focus}" - ng-click="$select.activate()"> - <div - ng-hide="$select.searchEnabled && ($select.open || $select.isEmpty())" - class="ui-select-match ng-hide" ng-transclude="" - placeholder="Custom date" - ng-keydown="inputKeydown($event)"> - <span class="ng-binding ng-scope"></span> - </div> - <input type="text" autocomplete="off" tabindex="-1" - class="ui-select-search ui-select-toggle ng-pristine ng-untouched ng-valid" - ng-click="$select.toggle($event)" - placeholder="Custom date" ng-model="$select.search" - ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" - ng-disabled="$select.disabled"> - </div> - <div ng-show="$select.open" - class="ui-select-choices selectize-dropdown single ng-scope ng-hide" - repeat="date in availableDates | filter: $select.search"> - <div - class="ui-select-choices-content selectize-dropdown-content"> - <div class="ui-select-choices-group optgroup"> - <div ng-show="$select.isGrouped" - class="ui-select-choices-group-label optgroup-header ng-binding ng-hide"></div> - <!-- ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">due date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">my date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - </div> - </div> - </div> - <input ng-disabled="$select.disabled" - class="ui-select-focusser ui-select-offscreen ng-scope" - type="text" aria-haspopup="true" role="button"> - </div> - </div> - - <div class="date_value"> - <input type="text" - class="entry_datepicker date_input ng-pristine ng-untouched ng-valid" - ng-model="dateValueInput" ng-keydown="inputKeydown($event)"> - </div> - </li> - </ul> - <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click="save()">save</button> - </div> - </div> - </li> - <li class="entry_menu_less ng-scope" - ng-controller="EntryTagsController"> - <div class="entry_tags has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <label>Create new tags by using commas</label> - <div class="token_input token_input_width"></div> - <div class="tags_input entry_tags_input" ng-click="focusInput()"> - - <!-- ngRepeat: tag in currentTokens --> - - <textarea class="token_input ng-pristine ng-untouched ng-valid" - ng-model="tagInput" ng-keydown="inputKeydown($event)"></textarea> - </div> - - <!-- <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click='fromViewModel()'>fromViewModel</button> - </div> --> - <h3 class="all_tags">All tags</h3> - <div class="tag_data_wrap"> - <div class="tag_register"> - <ul> - <li> - <ul class="my_tags"> - <!-- ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">demo</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">Entry</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">example</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - </ul> - </li> - </ul> - </div> - </div> - </div> - </li> - <li> - <div class="entry_options"> - <ul> - </ul> - </div> - </li> - </ul> - </div> - </header> - <div class="entry_toolbar"></div> - </div> - <div class="clear"></div> - </div> -</div> - - <div class="epb_content_wrap"> - <div class="epb_content_container"> - <div class="hdrop ui-droppable"></div> - <div class="dd_entry_table"> - <div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p><p>Ein Text-Element.</p></p> -</div> - - </div> - </div> - </div> -</div> - - </div> - </div> -</div> - - -</div></div> - <div id="epb_newer_blocks_panel"></div> - </div> -</div> -</body> -</html> diff --git a/unittests/example_labfolder_data/templates/My private templates_0/118219_template2/index.html b/unittests/example_labfolder_data/templates/My private templates_0/118219_template2/index.html deleted file mode 100644 index c21b3c1f..00000000 --- a/unittests/example_labfolder_data/templates/My private templates_0/118219_template2/index.html +++ /dev/null @@ -1,653 +0,0 @@ -<html> -<head> - <style type="text/css"> - @charset "UTF-8"; - [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak, .ng-hide:not(.ng-hide-animate) { - display: none !important; - } - - ng\:form { - display: block; - } - </style> - - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> - <meta name="apple-mobile-web-app-capable" content="yes"> - <meta name="apple-mobile-web-app-status-bar-style" - content="black-translucent"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - - - <title>Notebook</title> - - - <link rel="shortcut icon" type="image/x-icon" - href="../../../static/img/favicon2.ico"> - - <script src="../../../static/js/jquery-1.8.2.min.js" - type="text/javascript"></script> - <style type="text/css"></style> - - - <!-- This must be the first labfolder JS file included --> - <script - src="../../../static/js/labfolder-global.js?no-build-number" - type="text/javascript"></script> - - <link rel="stylesheet" type="text/css" - href="../../../static/css/export-table-element.css"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/jquery-ui.css"> - - <link rel="stylesheet" type="text/css" - href="../../../static/css/data-elements.css?no-build-number"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/combined.css?no-build-number"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/export-entry-footer.css"> - <link rel="stylesheet" type="text/css" - href="../../../static/css/redactor.css"/> - - <script type="text/javascript"> - function getTemplateText(className) { - return $("#jsTemplate_jsText").find(".jstext_" + className).text(); - } - - $(document).ready(function () { - // expand tags and custom dates container on hover - $(".entry_menu_less").hover( - function () { - if (!$(this).children(":first").hasClass("entry_name_menu")) { - $(this).addClass('entry_menu_more'); - $(this).children(":first").addClass('show_list_more'); - if ($(this).children(":first").hasClass("entry_tags")) { - $(".entry_tags").css("height", "auto"); - } - } - }, - function () { - if (!$(this).children(":first").hasClass("entry_name_menu")) { - $(this).removeClass('entry_menu_more'); - $(this).children(":first").removeClass('show_list_more'); - if ($(this).children(":first").hasClass("entry_tags")) { - $(".entry_tags").css("height", "100%"); - } - } - } - ); - - //selects the table sheet according to click - $(".sheet_tab").click(function () { - if ($(this).hasClass('selected') === false) { - var previous = $(this).siblings(".selected"); - var previousElementId = previous.data("elementid"); - var previousSheetIndex = previous.data("sheetidx"); - previous.removeClass("selected"); - - var targetElementId = $(this).data("elementid"); - var targetSheetIndex = $(this).data("sheetidx"); - $(this).addClass("selected"); - - $("#table_" + targetElementId + "_" + targetSheetIndex).css("display", "block"); - $("#table_" + previousElementId + "_" + previousSheetIndex).css("display", "none"); - } - }); - }); - </script> - - <script src="../../../static/js/jquery-ui.js" - type="text/javascript"></script> -</head> - -<body> -<div class="body_bg"></div> -<div id="global_data"></div> -<div class="eln_header eln_row"> - <div class="headerbar_top"> - <a href="/eln/"><span class="logo-img"></span></a> - <header> - <span class="notebook_s-img"></span> Notebook - </header> - <nav> - <div class="nav_top"> - <ul> - <li><a href="../../../projects.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Projects</p> - </button> - </a></li> - <li><a href="../../../templates.html"> - <button class="header_btn "> - <span class="desk-img"></span> - <p>Templates</p> - </button> - </a></li> - </ul> - </div> - </nav> - </div> - - -</div> -<div class="ng-scope"> - <div class="action_bar clearfix ng-scope"> - <div class="plus_btn_wrap"> - <div class="plus_btn_hover"> - <div class="add_dropdown more_options_menu" style="display: none;"> - <ul> - </ul> - </div> - </div> - </div> - <div class="action_menu_wrap"> - <div class="filter_wrap list_horizontal"></div> - </div> - </div> - <div id="eln_project_content" - class="eln_project_content eln_row eln_scroll-y ng-scope" data-id="118219" data-parentId="0" data-userId="30003" data-groupId="0" data-name="template2" data-folder="false" data-template="true" data-createTS="22.10.2019 15:54" data-hidden="false" data-shareable="false" data-owner-profilePictureHash="null" data-owner-tutorial="1" data-owner-zoneId="Europe/Berlin" data-owner-id="30003" data-owner-firstname="max" data-owner-lastname="muster" data-owner-email="max.muster@posteo.de" data-numberOfBlocks="1" data-lastEditedTS="22.10.2019 16:45" data-adminUserIds="[]" data-adminOrOwner="true" > - <div id="epb_container"><div data-id="4625184"data-blockId="4624724"data-elnProjectId="118219"data-sourceId="0"data-userAction="34"data-groupId="0"data-hidden="false"data-readOnly="false"data-versionTS="22.10.2019 18:45"data-createTS="22.10.2019 17:54"data-signHash="null"data-signHashDescription=""data-signHashVersion="null"data-signTS="null"data-witnessTS="null"data-title="null"data-blockNumber="1"data-totalBlocksInProject="1"data-projectName="template2"data-projectReferenceId="null"data-signBiometricsDocId="null"data-witnessBiometricsDocId="null"data-referenced="false"> - <div class="epb_header_container"> - <div class="epb_header clearfix" style="display: block;"> - - <div class="entry_container"> - <header class="entry_header"> - <div class="entry_author"> - <figure> - <span class="avatar-img"></span> - <img ng-src=""> - </figure> - - <div class="author_name"> - <div class="author_firstname ng-binding">max</div> - <div class="author_lastname ng-binding">muster</div> - </div> - </div> - <div class="entry_menu_less entry_title_wrap ng-scope"> - <div class="entry_name_menu has_tooltip"> - <ul> - <li> - <div style="display:none">Entry {{entryNumber}}/{{totalEntries}}:</div> - <div>Template:</div> - </li> - <li> - <div style="display:none" class="entry_title ng-binding">{{entryTitle}}</div> - <div>template2</div> - </li> - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown entry_name"> - <div class="close_entry_menu"> - <span class="cancel_entry_title close_box-img"></span> - </div> - <ul> - <li><label>Entry name</label> <input - class="entry_name_input ng-pristine ng-untouched ng-valid" - type="text" data-title="" value=""></li> - <li><label>located in project</label> <select - class="ng-pristine ng-untouched ng-valid"> - <option - value="0">tableproject - </option> - <option value="1" selected="selected">a project</option> - </select></li> - <li> - <div class="save_entry_menu"> - <span class="cancel_dropdown cancel_entry_title grey_link" - ng-click="cancel()">cancel</span> - <button class="save_entry_title btn_on_grey" ng-click="save()">save</button> - </div> - </li> - </ul> - </div> - </div> - - <div class="entry_menus"> - <ul> - <li class="entry_menu_less ng-scope" - ng-controller="EntryDateController"> - <div class="entry_menu_list has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <ul> - <li><span>created:</span> <span class="ng-binding">22.10.2019 17:54</span> - </li> - <li><span>modified</span> <span class="ng-binding">22.10.2019 18:45</span> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - - </ul> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown" - ng-mouseenter="activateElement($event)"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <ul class="entry_dates"> - <li><label>Dates</label></li> - <li> - <div class="date_key"> - <input type="text" value="created" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.createTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <li> - <div class="date_key"> - <input type="text" value="modified" disabled=""> - </div> - <div class="date_value"> - <input type="text" ng-value="parseDate(entry.versionTS)" - disabled="" value="18.02.2015"> - </div> - </li> - <!-- ngRepeat: date in currentDates | orderBy:predicate --> - <li style="overflow: visible;"> - <div class="date_key"> - - <div class="selectize-control single ng-valid" - ng-keyup="updateInput($select.search)" - reset-search-input="false" ng-model="dateKeyInput.selected" - theme="selectize" style="min-width: 120px;"> - <div class="selectize-input" - ng-class="{'focus': $select.open, 'disabled': $select.disabled, 'selectize-focus' : $select.focus}" - ng-click="$select.activate()"> - <div - ng-hide="$select.searchEnabled && ($select.open || $select.isEmpty())" - class="ui-select-match ng-hide" ng-transclude="" - placeholder="Custom date" - ng-keydown="inputKeydown($event)"> - <span class="ng-binding ng-scope"></span> - </div> - <input type="text" autocomplete="off" tabindex="-1" - class="ui-select-search ui-select-toggle ng-pristine ng-untouched ng-valid" - ng-click="$select.toggle($event)" - placeholder="Custom date" ng-model="$select.search" - ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" - ng-disabled="$select.disabled"> - </div> - <div ng-show="$select.open" - class="ui-select-choices selectize-dropdown single ng-scope ng-hide" - repeat="date in availableDates | filter: $select.search"> - <div - class="ui-select-choices-content selectize-dropdown-content"> - <div class="ui-select-choices-group optgroup"> - <div ng-show="$select.isGrouped" - class="ui-select-choices-group-label optgroup-header ng-binding ng-hide"></div> - <!-- ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">due date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - <div class="ui-select-choices-row ng-scope" - ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" - ng-repeat="date in $select.items" - ng-mouseenter="$select.setActiveItem(date)" - ng-click="$select.select(date)"> - <div class="option ui-select-choices-row-inner" - data-selectable="" uis-transclude-append=""> - <span ng-bind-html="date | highlight: $select.search" - class="ng-binding ng-scope">my date</span> - </div> - </div> - <!-- end ngRepeat: date in $select.items --> - </div> - </div> - </div> - <input ng-disabled="$select.disabled" - class="ui-select-focusser ui-select-offscreen ng-scope" - type="text" aria-haspopup="true" role="button"> - </div> - </div> - - <div class="date_value"> - <input type="text" - class="entry_datepicker date_input ng-pristine ng-untouched ng-valid" - ng-model="dateValueInput" ng-keydown="inputKeydown($event)"> - </div> - </li> - </ul> - <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click="save()">save</button> - </div> - </div> - </li> - <li class="entry_menu_less ng-scope" - ng-controller="EntryTagsController"> - <div class="entry_tags has_tooltip" - ng-class="{true: '', false: 'has_tooltip'}[entry.readOnly]"> - <i>No tags associated</i> - </div> - <div class="entry_menu_options"> - </div> - <div class="entry_dropdown"> - <div class="close_entry_menu"> - <span class="close_box-img" ng-click="cancel()"></span> - </div> - <label>Create new tags by using commas</label> - <div class="token_input token_input_width"></div> - <div class="tags_input entry_tags_input" ng-click="focusInput()"> - - <!-- ngRepeat: tag in currentTokens --> - - <textarea class="token_input ng-pristine ng-untouched ng-valid" - ng-model="tagInput" ng-keydown="inputKeydown($event)"></textarea> - </div> - - <!-- <div class="save_entry_menu"> - <span class="cancel_dropdown grey_link" ng-click="cancel()">cancel</span> - <button class="btn_on_grey" ng-click='fromViewModel()'>fromViewModel</button> - </div> --> - <h3 class="all_tags">All tags</h3> - <div class="tag_data_wrap"> - <div class="tag_register"> - <ul> - <li> - <ul class="my_tags"> - <!-- ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">demo</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">Entry</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - <li - ng-repeat="token in filteredValues = (availableTokens | filter:tagInput)" - class="ng-scope"><span - class="existing_tag ng-binding" - ng-class="{disabled: added(token), selected_tag: inputSelected(token)}" - ng-click="add(token)">example</span></li> - <!-- end ngRepeat: token in filteredValues = (availableTokens | filter:tagInput) --> - </ul> - </li> - </ul> - </div> - </div> - </div> - </li> - <li> - <div class="entry_options"> - <ul> - </ul> - </div> - </li> - </ul> - </div> - </header> - <div class="entry_toolbar"></div> - </div> - <div class="clear"></div> - </div> -</div> - - <div class="epb_content_wrap"> - <div class="epb_content_container"> - <div class="hdrop ui-droppable"></div> - <div class="dd_entry_table"> - <div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content redactor_editor"> - <p><p>Text ist hier</p></p> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" > - <div class="button_wrapper"></div> - <div class="notebook-element-content data-elements-container data-elements"> - <html><head></head><body><div class="data-element-wrap data-group-wrap"> - <svg class="data-element-icon data-group-icon" viewbox="0 0 67 64"> - <title>icon-vf-group-filled</title> - <path d="M32.119 39.613c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M0.952 39.019c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.275c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.138z"></path> - <path d="M29.502 36.996c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M49.487 11.063c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M19.39 10.587c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.427-1.071-1.903l-12.372-7.019z"></path> - <path d="M46.87 8.565c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M66.498 40.327c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M35.331 39.851c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0 0 0 0 0 0 0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.019z"></path> - <path d="M64 37.71c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595c0 0 0 0 0 0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - </svg> - - <div class="data-group-content display-mode"> - <div class="data-element-wrap data-group-header"> - <div class="data-element-display data-group-display"> - <span class="element-title">gruppe 1</span> - </div> - </div> - - <div class="data-group-children"> - <div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">foo</span> - <span class="element-quantity">: Angular Momentum: </span> - <span class="element-value ">20€ </span> - <span class="element-unit">kg/m<sup>2</sup> s<sup>-1</sup></span> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">bar</span> - <span class="element-quantity">: Fugacity: </span> - <span class="element-value ">12 </span> - <span class="element-unit">Pa</span> - </div> -</div> - - </div> - </div> -</div> -</body></html><html><head></head><body><div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title empty-value">⎵</span> - <span class="element-quantity">: Electric Displacement: </span> - <span class="element-value empty-value">⎵ </span> - <span class="element-unit">C/m<sup>2</sup></span> - </div> -</div> -</body></html><html><head></head><body><div class="data-element-wrap descriptive-element-wrap"> - <svg class="data-element-icon descriptive-element-icon" viewbox="0 0 64 64"> - <title>icon-dde</title> - <path d="M62.080 48.96h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.024-0.832-1.92-1.92-1.92z"></path> - <path d="M62.080 24.192h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - <path d="M37.504 0h-35.584c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h35.584c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - </svg> - - <div class="data-element-display descriptive-element-display"> - <span class="element-title">DE name: </span> - <span class="element-description ">fdgdfghgfdhgdfhh dfghdfghdfghfgh dfghdfgd</span> - </div> -</div> -</body></html><html><head></head><body><div class="data-element-wrap data-group-wrap"> - <svg class="data-element-icon data-group-icon" viewbox="0 0 67 64"> - <title>icon-vf-group-filled</title> - <path d="M32.119 39.613c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M0.952 39.019c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.275c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.138z"></path> - <path d="M29.502 36.996c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M49.487 11.063c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M19.39 10.587c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.427-1.071-1.903l-12.372-7.019z"></path> - <path d="M46.87 8.565c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M66.498 40.327c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M35.331 39.851c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0 0 0 0 0 0 0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.019z"></path> - <path d="M64 37.71c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595c0 0 0 0 0 0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - </svg> - - <div class="data-group-content display-mode"> - <div class="data-element-wrap data-group-header"> - <div class="data-element-display data-group-display"> - <span class="element-title">gruppe 2</span> - </div> - </div> - - <div class="data-group-children"> - <div class="data-element-wrap data-group-wrap"> - <svg class="data-element-icon data-group-icon" viewbox="0 0 67 64"> - <title>icon-vf-group-filled</title> - <path d="M32.119 39.613c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M0.952 39.019c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.275c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.138z"></path> - <path d="M29.502 36.996c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M49.487 11.063c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M19.39 10.587c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.427-1.071-1.903l-12.372-7.019z"></path> - <path d="M46.87 8.565c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595v0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - <path d="M66.498 40.327c0-0.238-0.119-0.476-0.357-0.595s-0.476-0.119-0.595 0l-12.372 7.138c-0.714 0.357-1.071 1.071-1.071 1.903v14.394c0 0.238 0.119 0.476 0.357 0.595s0.476 0.119 0.595 0l11.896-6.9c0.952-0.595 1.546-1.546 1.546-2.617v-13.918z"></path> - <path d="M35.331 39.851c-0.238-0.119-0.476-0.119-0.595 0-0.238 0.119-0.357 0.357-0.357 0.595v0 13.799c0 1.071 0.595 2.141 1.546 2.617l11.896 6.9c0 0 0 0 0 0 0.238 0.119 0.476 0.119 0.595 0 0.238-0.119 0.357-0.357 0.357-0.595v-14.394c0-0.714-0.357-1.428-1.071-1.903l-12.372-7.019z"></path> - <path d="M64 37.71c0.238-0.119 0.357-0.357 0.357-0.595s-0.119-0.476-0.357-0.595c0 0 0 0 0 0l-11.896-6.9c-0.952-0.595-2.141-0.595-3.093 0l-11.896 6.9c-0.238 0.119-0.357 0.357-0.357 0.595s0.119 0.476 0.357 0.595l12.372 7.138c0.714 0.357 1.428 0.357 2.141 0l12.372-7.138z"></path> - </svg> - - <div class="data-group-content display-mode"> - <div class="data-element-wrap data-group-header"> - <div class="data-element-display data-group-display"> - <span class="element-title">Untergruppe 2.1</span> - </div> - </div> - - <div class="data-group-children"> - <div class="data-element-wrap descriptive-element-wrap"> - <svg class="data-element-icon descriptive-element-icon" viewbox="0 0 64 64"> - <title>icon-dde</title> - <path d="M62.080 48.96h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.024-0.832-1.92-1.92-1.92z"></path> - <path d="M62.080 24.192h-60.16c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h60.16c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - <path d="M37.504 0h-35.584c-1.088 0-1.92 0.832-1.92 1.92v11.2c0 1.088 0.832 1.92 1.92 1.92h35.584c1.088 0 1.92-0.832 1.92-1.92v-11.2c0-1.088-0.832-1.92-1.92-1.92z"></path> - </svg> - - <div class="data-element-display descriptive-element-display"> - <span class="element-title">DE name 2 (desc): </span> - <span class="element-description empty-value">⎵</span> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">DE 2.1.1</span> - <span class="element-quantity">: Amount of substance: </span> - <span class="element-value ">20 </span> - <span class="element-unit">mol</span> - </div> -</div> - - </div> - </div> -</div> -<div class="data-element-wrap single-element-wrap"> - <svg class="data-element-icon single-element-icon" viewbox="0 0 67 64"> - <title>icon-vf-filled</title> - <path d="M59.413 20.587c0-0.427-0.213-0.853-0.64-1.067-0.32-0.213-0.853-0.213-1.173 0l-22.827 13.227c-1.173 0.747-1.92 2.027-1.92 3.413v26.453c0 0.427 0.213 0.853 0.64 1.067 0.32 0.213 0.853 0.213 1.173 0l21.867-12.8c1.707-1.067 2.88-2.88 2.88-4.907v-25.387z"></path> - <path d="M2.027 19.52c-0.32-0.213-0.853-0.213-1.173 0s-0.64 0.64-0.64 1.067v0 25.387c0 2.027 1.067 3.947 2.88 4.907l21.973 12.693c0 0 0 0 0 0 0.32 0.213 0.853 0.213 1.173 0s0.64-0.64 0.64-1.067v-26.347c0-1.387-0.747-2.667-1.92-3.413l-22.933-13.227z"></path> - <path d="M54.72 15.787c0.32-0.213 0.64-0.64 0.64-1.067s-0.213-0.853-0.64-1.067c0 0 0 0 0 0l-22.080-12.587c-1.707-1.067-3.947-1.067-5.653 0l-21.973 12.693c-0.32 0.213-0.64 0.64-0.64 1.067s0.213 0.853 0.64 1.067l22.827 13.227c1.173 0.747 2.667 0.747 3.947 0l22.933-13.333z"></path> - </svg> - - <div class="data-element-display single-element-display"> - <span class="element-title ">DE 2.2</span> - <span class="element-quantity">: Capacitance: </span> - <span class="element-value ">876x876x87 </span> - <span class="element-unit">µF</span> - </div> -</div> - - </div> - </div> -</div> -</body></html> -</div> - - </div> - </div> - </div> -</div> -<div class="dd_entry_table"> - <div class="dd_entry_row"> - <div class="dd_entry_cell ui-draggable dd_text_entry"> - <div class="dd_entry_cell_wrapper" {{elementMeta1}}> - <div class="button_wrapper"></div> - <div class="dd_entry_cell_content table-el-container"> - <div> - <div class="table-el-info"> - Your labfolder table is available for visualization as the following Excel file: - </div> - <div class="table-el-download"> - <a href="labfolder_table_4625184_3.xlsx"> - <svg class="table-el-icon" viewBox="0 0 475.1 402.5"> - <title>icon-table</title> - <path d="M461.7,14C452.7,5,442,0.5,429.4,0.5H45.7C33.1,0.5,22.4,5,13.4,14C4.5,22.9,0,33.7,0,46.2v310.6 c0,12.6,4.5,23.3,13.4,32.3c8.9,8.9,19.7,13.4,32.3,13.4h383.7c12.6,0,23.3-4.5,32.3-13.4c8.9-9,13.4-19.7,13.4-32.3V46.2 C475.1,33.7,470.6,22.9,461.7,14z M146.2,356.9c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7c-2.7,0-4.9-0.9-6.6-2.6 c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6 L146.2,356.9L146.2,356.9z M146.2,247.2c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7c-2.7,0-4.9-0.9-6.6-2.6 c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L146.2,247.2L146.2,247.2z M146.2,137.6c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H45.7 c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6H137c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L146.2,137.6L146.2,137.6z M292.4,356.9c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6h-91.4 c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6 c1.7,1.7,2.6,3.9,2.6,6.6L292.4,356.9L292.4,356.9L292.4,356.9z M292.4,247.2c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6 h-91.4c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.9-4.9,2.6-6.6c1.7-1.7,3.9-2.6,6.6-2.6h91.4 c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6L292.4,247.2L292.4,247.2z M292.4,137.6c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6h-91.4c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.9-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6L292.4,137.6L292.4,137.6z M438.5,356.9 c0,2.7-0.9,4.9-2.6,6.6c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V302c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V356.9z M438.5,247.2c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6v-54.8c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V247.2z M438.5,137.6c0,2.7-0.9,4.9-2.6,6.6 c-1.7,1.7-3.9,2.6-6.6,2.6H338c-2.7,0-4.9-0.9-6.6-2.6c-1.7-1.7-2.6-3.9-2.6-6.6V82.8c0-2.7,0.8-4.9,2.6-6.6 c1.7-1.7,3.9-2.6,6.6-2.6h91.4c2.7,0,4.9,0.9,6.6,2.6c1.7,1.7,2.6,3.9,2.6,6.6V137.6z"/> - </svg> - <div class="table-el-filename"> - labfolder_table_4625184_3.xlsx - </div> - </a> - </div> - </div> -</div> - - </div> - </div> - </div> -</div> - - </div> - </div> -</div> - - -</div></div> - <div id="epb_newer_blocks_panel"></div> - </div> -</div> -</body> -</html> diff --git a/unittests/example_labfolder_data/templates/My private templates_0/118219_template2/labfolder_table_4625184_3.xlsx b/unittests/example_labfolder_data/templates/My private templates_0/118219_template2/labfolder_table_4625184_3.xlsx deleted file mode 100644 index 83d3d8119085d311ceb5a54e56c5363351aa1c0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5564 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 JzW?F?{sqL?Yd`=1 -- GitLab From a4b2148750132a6e0ca580fb18737538685b8f62 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Wed, 27 Nov 2024 14:51:39 +0100 Subject: [PATCH 065/106] DOC: CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d070d8da..54b755a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bloxberg code snippets. These were just a proof of concept, untested and never used in production. - Labfolder converter. It was broken anyway, not used by anyone we know and there were no automated - tests. For the time being, it lives on in the `f-labfolder-converter` branch. + tests. For the time being, it lives on in the `f-labfolder-converter` branch, [issue 67](https://gitlab.com/linkahead/linkahead-advanced-user-tools/-/issues/67) is + there to coordinate resurrections efforts if someone needs it.. ### Fixed ### -- GitLab From ca946c6654d5b63ca3b2fd4cb776a9183d083701 Mon Sep 17 00:00:00 2001 From: Joscha Schmiedt <joscha@schmiedt.dev> Date: Wed, 27 Nov 2024 22:26:43 +0100 Subject: [PATCH 066/106] Fix UpdateCache default file path on Windows /tmp does not exist on Windows (issue #136) --- src/caosadvancedtools/cache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/caosadvancedtools/cache.py b/src/caosadvancedtools/cache.py index 749239fa..46564393 100644 --- a/src/caosadvancedtools/cache.py +++ b/src/caosadvancedtools/cache.py @@ -338,7 +338,7 @@ class UpdateCache(AbstractCache): return 3 def get_default_file_name(self): - return "/tmp/crawler_update_cache.db" + return os.path.join(tempfile.gettempdir(), "crawler_update_cache.db") @staticmethod def get_previous_version(cont): -- GitLab From f54451c885aa1213510a96520612f21be66071a1 Mon Sep 17 00:00:00 2001 From: Joscha Schmiedt <joscha@schmiedt.dev> Date: Wed, 27 Nov 2024 23:04:15 +0100 Subject: [PATCH 067/106] FIX: Make temporary paths Windows-compatible --- unittests/test_caosdbignore.py | 2 +- unittests/test_suppressKnown.py | 11 +++++------ unittests/test_utils.py | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/unittests/test_caosdbignore.py b/unittests/test_caosdbignore.py index c044a8e8..39839db4 100644 --- a/unittests/test_caosdbignore.py +++ b/unittests/test_caosdbignore.py @@ -44,7 +44,7 @@ class Linkaheadignore(unittest.TestCase): assert len(files) == 3 assert os.path.join(BASEDIR, "data", "datatypes.xlsx") in files assert os.path.join(BASEDIR, "data", "README.xlsx") in files - assert os.path.join(BASEDIR, "data", "Publications/Posters/2019-02-03_something/README.md") in files + assert os.path.join(BASEDIR, "data", "Publications", "Posters", "2019-02-03_something", "README.md") in files def test_regex(self): files = [r"/dies/ist/simple", r"/dies/eh(er)/nich?t"] diff --git a/unittests/test_suppressKnown.py b/unittests/test_suppressKnown.py index 6f87e842..d148a5a3 100644 --- a/unittests/test_suppressKnown.py +++ b/unittests/test_suppressKnown.py @@ -25,7 +25,7 @@ import logging import os import unittest -from tempfile import NamedTemporaryFile +from tempfile import NamedTemporaryFile, gettempdir from caosadvancedtools.suppressKnown import SuppressKnown @@ -40,7 +40,7 @@ class Record(object): class SupTestBasic(unittest.TestCase): def setUp(self): - self.db_file = "/tmp/test_suppress_msg_db_file.db" + self.db_file = os.path.join(gettempdir(), "test_suppress_msg_db_file_basic.db") self.basic = SuppressKnown(db_file=self.db_file) def test_msg(self): @@ -52,12 +52,12 @@ class SupTestBasic(unittest.TestCase): self.basic.filter(r) def tearDown(self): - os.remove(self.db_file) + pass class SupTestAdvanced(SupTestBasic): def setUp(self): - self.db_file = "/tmp/test_suppress_msg_db_file.db" + self.db_file = os.path.join(gettempdir(), "test_suppress_msg_db_file_advanced.db") self.basic = SuppressKnown(db_file=self.db_file) def test_logger(self): @@ -65,13 +65,12 @@ class SupTestAdvanced(SupTestBasic): The logging output is directed to a file which is then checked whether the output is as expected. """ - logfile = NamedTemporaryFile() + logfile = NamedTemporaryFile(delete=False, mode="w") logger = logging.getLogger() logger.addHandler(logging.FileHandler(logfile.name)) logger.setLevel(logging.DEBUG) sup = SuppressKnown(db_file=self.db_file) logger.addFilter(sup) - logger.info("hi", extra={"identifier": "5", 'category': "test"}) with open(logfile.name) as lf: log = lf.read() diff --git a/unittests/test_utils.py b/unittests/test_utils.py index 09688f97..c8134e3d 100644 --- a/unittests/test_utils.py +++ b/unittests/test_utils.py @@ -23,7 +23,7 @@ import logging import unittest from tempfile import NamedTemporaryFile - +import os import linkahead as db from caosadvancedtools.utils import (check_win_path, get_referenced_files, string_to_person, create_entity_link) @@ -47,7 +47,7 @@ class BaseMockUpTest(unittest.TestCase): connection._delegate_connection.resources.append( lambda **kwargs: MockUpResponse(200, {}, self.entities)) - self.logfile = NamedTemporaryFile() + self.logfile = NamedTemporaryFile(delete=False) logger = logging.getLogger() logger.addHandler(logging.FileHandler(self.logfile.name)) logger.setLevel(logging.DEBUG) @@ -77,7 +77,7 @@ class ReferencesBaseTest(BaseMockUpTest): files = get_referenced_files("test.npy", prefix=None, filename=None, location=None) self.assertEqual(len(files), 1) - self.assertEqual(files[0].path, "/some/path/test.npy") + self.assertEqual(os.path.join(files[0].path, "some", "path", "test.npy")) log = self.get_log() assert "FIND file which" in log assert "does not allow a search" not in log -- GitLab From 779b38178ecb3b0cc4ff65188a5f44c37d9d9c9d Mon Sep 17 00:00:00 2001 From: Joscha Schmiedt <joscha@schmiedt.dev> Date: Wed, 27 Nov 2024 23:04:33 +0100 Subject: [PATCH 068/106] TST: Skip sendmail test on Windows --- unittests/test_sss_helper.py | 5 +++-- unittests/test_utils.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/unittests/test_sss_helper.py b/unittests/test_sss_helper.py index c040f503..e1ce286d 100644 --- a/unittests/test_sss_helper.py +++ b/unittests/test_sss_helper.py @@ -2,7 +2,7 @@ import subprocess from email import message_from_file, policy from os import listdir, remove from os.path import abspath, dirname, exists, isfile, join - +import platform import linkahead as db from caosadvancedtools.serverside.helper import (NameCollector, get_data, get_file_via_download, @@ -85,7 +85,8 @@ def test_send_mail(): assert msg["Subject"] == "the subject" assert msg.get_content() == "hello!\n" - +# skip on windows (has no sendmail) +@mark.skipif(platform.system() == "Windows") def test_send_mail_error(): with raises(subprocess.CalledProcessError): send_mail("me@example.com", "you@example.com", "the subject", "hello!", diff --git a/unittests/test_utils.py b/unittests/test_utils.py index c8134e3d..aeae08e4 100644 --- a/unittests/test_utils.py +++ b/unittests/test_utils.py @@ -77,7 +77,7 @@ class ReferencesBaseTest(BaseMockUpTest): files = get_referenced_files("test.npy", prefix=None, filename=None, location=None) self.assertEqual(len(files), 1) - self.assertEqual(os.path.join(files[0].path, "some", "path", "test.npy")) + self.assertEqual(files[0].path, "/some/path/test.npy") log = self.get_log() assert "FIND file which" in log assert "does not allow a search" not in log -- GitLab From a555600ff6852d54f3c82d71a0ee4accd3d04345 Mon Sep 17 00:00:00 2001 From: Joscha Schmiedt <joscha@schmiedt.dev> Date: Wed, 27 Nov 2024 23:12:15 +0100 Subject: [PATCH 069/106] TST: Make dtype test more robust to default behavior changes --- unittests/test_table_importer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittests/test_table_importer.py b/unittests/test_table_importer.py index 0abc28bb..fc0d5f0e 100644 --- a/unittests/test_table_importer.py +++ b/unittests/test_table_importer.py @@ -196,8 +196,8 @@ class TableImporterTest(unittest.TestCase): [5678, 1, 2.0, 3, 'yes']], columns=['a', 'b', 'c', 'float', 'd']) # wrong datatypes before - assert df["a"].dtype == int - assert df["float"].dtype == int + assert df["a"].dtype != pd.StringDtype + assert df["float"].dtype != float # strict = False by default, so this shouldn't raise an error importer.check_datatype(df) # The types should be correct now. -- GitLab From 3e772c8eaca620749ac515eb02c5c97c6e49efb7 Mon Sep 17 00:00:00 2001 From: Joscha Schmiedt <joscha@schmiedt.dev> Date: Wed, 27 Nov 2024 23:20:30 +0100 Subject: [PATCH 070/106] TST: Skip logger test on Windows # TODO: this test is problematic on Windows due to the file being locked # by the logger. This is a known issue and should be fixed in the # future. # For now, the test is disabled on Windows. # See https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile --- unittests/test_suppressKnown.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/unittests/test_suppressKnown.py b/unittests/test_suppressKnown.py index d148a5a3..c3e65dbe 100644 --- a/unittests/test_suppressKnown.py +++ b/unittests/test_suppressKnown.py @@ -60,11 +60,17 @@ class SupTestAdvanced(SupTestBasic): self.db_file = os.path.join(gettempdir(), "test_suppress_msg_db_file_advanced.db") self.basic = SuppressKnown(db_file=self.db_file) + @unittest.skipIf(os.name == "nt", "Known issue on Windows, see https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile") def test_logger(self): """ The logging output is directed to a file which is then checked whether the output is as expected. """ + # TODO: this test is problematic on Windows due to the file being locked + # by the logger. This is a known issue and should be fixed in the + # future. + # For now, the test is disabled on Windows. + # See https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile logfile = NamedTemporaryFile(delete=False, mode="w") logger = logging.getLogger() logger.addHandler(logging.FileHandler(logfile.name)) -- GitLab From 10c547b82bbcf64239cca79daab45bfd6bfdc11f Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Thu, 28 Nov 2024 13:32:55 +0100 Subject: [PATCH 071/106] DOC: Document pip extras in README_SETUP.md and remove outdated dependencies section in favour of referring to setup.py --- README_SETUP.md | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/README_SETUP.md b/README_SETUP.md index 3a7f0197..0018f044 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -1,41 +1,40 @@ # Getting started ## Download -The recommended way is: +DOCThe recommended way to download is: ``` # Clone the repository: git clone 'https://gitlab.com/caosdb/caosdb-advanced-user-tools' ``` -## Dependencies -Dependencies will be installed automatically if you use the below described -procedure. -- `caosdb>=0.6.0` -- `openpyxl>=3.0.7` -- `xlrd>=1.2.0` -- `pandas>=1.2.0` -- `numpy>=1.17.3` +## Installation +`pip install . --user` -If you want to use the optional h5-crawler the following dependencies will be -installed additionally: -- `h5py>=3.3.0` +To test with tox: +`pip install tox --user` -For testing: -- `tox` +#### Additional dependencies +To install dependencies used by optional functionality, the following pip extras +keywords are defined: +- `test` for testing with pytest +- `doc` for building the documentation +- `dev` for code formatting +- `h5` for the h5-crawler +- `all` to install all optional dependencies -## Installation -- `pip install . --user` -- `pip install tox --user` +These extras can be installed using: `pip install .[KEYWORD] --user` -Optional h5-crawler: -- `pip install .[h5-crawler] --user` +A current list of the dependencies installed with this program as well as those installed with +the keywords can be found in `setup.py`s `setup_package()` method, in the `metadata` dictionary +entries `install_requires` and `extras_require`. ## Run Unit Tests - All tests: `tox` - One specific test with tox: `tox -- unittests/test_myusecase.py -k expression` -- Or even using only pytest: `pytest unittests/test_myusecase.py -k expression` +- Using only pytest: `pytest unittests` or for running only one test + `pytest unittests/test_myusecase.py -k expression` ## Run Integration Tests Locally @@ -60,12 +59,6 @@ with the Googly style (see link below). Build documentation in `build/` with `make doc`. -### Requirements ## - -- `sphinx` -- `sphinx-autoapi` -- `sphinx-rtd-theme` -- `recommonmark >= 0.6.0` ### How to contribute ### -- GitLab From 7bba25095ba8b46d0c35a2123b6951a94f6b87bd Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Thu, 28 Nov 2024 13:41:25 +0100 Subject: [PATCH 072/106] MNT: Typo --- README_SETUP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_SETUP.md b/README_SETUP.md index 0018f044..46d9f8ec 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -1,7 +1,7 @@ # Getting started ## Download -DOCThe recommended way to download is: +The recommended way to download is: ``` # Clone the repository: git clone 'https://gitlab.com/caosdb/caosdb-advanced-user-tools' -- GitLab From 48e55b6b5b965e3a8e078c55258a1f901be9a04b Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Thu, 28 Nov 2024 19:07:19 +0100 Subject: [PATCH 073/106] DOC: Update pip commands, and remove git link --- README_SETUP.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/README_SETUP.md b/README_SETUP.md index 46d9f8ec..e52885ff 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -1,20 +1,15 @@ # Getting started -## Download -The recommended way to download is: -``` -# Clone the repository: -git clone 'https://gitlab.com/caosdb/caosdb-advanced-user-tools' -``` - ## Installation -`pip install . --user` -To test with tox: -`pip install tox --user` +To install the advancedtools package, you can run: +`pip install caosadvancedtools` #### Additional dependencies +To test using tox, you also need to install tox: +`pip install tox` + To install dependencies used by optional functionality, the following pip extras keywords are defined: - `test` for testing with pytest @@ -23,7 +18,7 @@ keywords are defined: - `h5` for the h5-crawler - `all` to install all optional dependencies -These extras can be installed using: `pip install .[KEYWORD] --user` +These extras can be installed using: `pip install .[KEYWORD]` A current list of the dependencies installed with this program as well as those installed with the keywords can be found in `setup.py`s `setup_package()` method, in the `metadata` dictionary -- GitLab From 8fa476943f9e332e2516d9ccc5bebb76285cb6d0 Mon Sep 17 00:00:00 2001 From: Joscha Schmiedt <joscha@schmiedt.dev> Date: Mon, 2 Dec 2024 21:09:07 +0100 Subject: [PATCH 074/106] Add reason argument to skipped tests on Windows --- unittests/test_sss_helper.py | 2 +- unittests/test_suppressKnown.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unittests/test_sss_helper.py b/unittests/test_sss_helper.py index e1ce286d..8baab849 100644 --- a/unittests/test_sss_helper.py +++ b/unittests/test_sss_helper.py @@ -86,7 +86,7 @@ def test_send_mail(): assert msg.get_content() == "hello!\n" # skip on windows (has no sendmail) -@mark.skipif(platform.system() == "Windows") +@mark.skipif(platform.system() == "Windows", reason="no sendmail on Windows") def test_send_mail_error(): with raises(subprocess.CalledProcessError): send_mail("me@example.com", "you@example.com", "the subject", "hello!", diff --git a/unittests/test_suppressKnown.py b/unittests/test_suppressKnown.py index c3e65dbe..80af892d 100644 --- a/unittests/test_suppressKnown.py +++ b/unittests/test_suppressKnown.py @@ -60,7 +60,7 @@ class SupTestAdvanced(SupTestBasic): self.db_file = os.path.join(gettempdir(), "test_suppress_msg_db_file_advanced.db") self.basic = SuppressKnown(db_file=self.db_file) - @unittest.skipIf(os.name == "nt", "Known issue on Windows, see https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile") + @unittest.skipIf(os.name == "nt", reason="Known issue on Windows, see https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile") def test_logger(self): """ The logging output is directed to a file which is then checked whether -- GitLab From 91d3ec23737d82505385f25fea7f2144022f1a90 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Wed, 4 Dec 2024 16:03:28 +0100 Subject: [PATCH 075/106] ENH, TEST: More strict boolean parsing, more tests. --- .../table_json_conversion/convert.py | 4 +- .../data/simple_data_booleans.json | 47 ++++++++++++++++++ .../data/simple_data_booleans.xlsx | Bin 0 -> 9030 bytes .../data/simple_data_broken.xlsx | Bin 9133 -> 9299 bytes .../table_json_conversion/test_read_xlsx.py | 24 ++++++++- unittests/table_json_conversion/utils.py | 3 +- 6 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 unittests/table_json_conversion/data/simple_data_booleans.json create mode 100644 unittests/table_json_conversion/data/simple_data_booleans.xlsx diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index f775709a..b416fc29 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -480,9 +480,9 @@ class XLSXConverter: return value # booleans might be retrieved as an integer or formula if subschema.get('type') == 'boolean': - if value == 0 or isinstance(value, str) and 'false' in value.lower(): + if value == 0 or isinstance(value, str) and '=false()' == value.lower(): value = False - if value == 1 or isinstance(value, str) and 'true' in value.lower(): + if value == 1 or isinstance(value, str) and '=true()' == value.lower(): value = True jsonschema.validate(value, subschema) diff --git a/unittests/table_json_conversion/data/simple_data_booleans.json b/unittests/table_json_conversion/data/simple_data_booleans.json new file mode 100644 index 00000000..f7d452b3 --- /dev/null +++ b/unittests/table_json_conversion/data/simple_data_booleans.json @@ -0,0 +1,47 @@ +{ + "Training": [ + { + "date": "2023-01-01", + "url": "www.indiscale.com", + "coach": [ + { + "family_name": "Sky", + "given_name": "Max", + "Organisation": "ECB" + }, + { + "family_name": "Sky", + "given_name": "Min", + "Organisation": "ECB" + } + ], + "supervisor": { + "family_name": "Steve", + "given_name": "Stevie", + "Organisation": "IMF" + }, + "duration": 1.0, + "participants": 1, + "subjects": ["Math", "Physics"], + "remote": false + }, + { + "date": "2023-01-02", + "url": "www.indiscale.com", + "supervisor": { + "family_name": "Steve", + "given_name": "Stevie", + "Organisation": "IMF" + }, + "duration": 1.0, + "participants": 1, + "subjects": ["Math", "Physics"], + "remote": true + } + ], + "Person": [{ + "family_name": "Steve", + "given_name": "Stevie", + "Organisation": "IMF" + }] +} diff --git a/unittests/table_json_conversion/data/simple_data_booleans.xlsx b/unittests/table_json_conversion/data/simple_data_booleans.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6a67d7a8d6df76b7d88d0d575c6ed1c30b8f8363 GIT binary patch literal 9030 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 literal 0 HcmV?d00001 diff --git a/unittests/table_json_conversion/data/simple_data_broken.xlsx b/unittests/table_json_conversion/data/simple_data_broken.xlsx index a65d464a53459de73e41fd20d807899c44728cda..c75da9faaefcb7610d84e16dd6ff17dcd055b008 100644 GIT binary patch delta 5889 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 Q3ufdCc1{8z*58r;1tLbOssI20 delta 5626 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 L73(F#A1nU@4YxY~ diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index cd5d53dd..a34c046f 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -26,6 +26,7 @@ import os import re from types import SimpleNamespace +from typing import Optional import jsonschema import pytest @@ -41,7 +42,7 @@ def rfp(*pathcomponents): def convert_and_compare(xlsx_file: str, schema_file: str, known_good_file: str, - known_good_data: dict = None, strict: bool = False, + known_good_data: Optional[dict] = None, strict: bool = False, validate: bool = True) -> dict: """Convert an XLSX file and compare to a known result. @@ -77,6 +78,9 @@ def test_conversions(): schema_file=rfp("data/multiple_choice_schema.json"), known_good_file=rfp("data/multiple_choice_data.json"), strict=True) + convert_and_compare(xlsx_file=rfp("data/simple_data_booleans.xlsx"), + schema_file=rfp("data/simple_schema.json"), + known_good_file=rfp("data/simple_data_booleans.json")) with open(rfp("data/simple_data.json"), encoding="utf-8") as myfile: expected_datetime = json.load(myfile) @@ -126,24 +130,40 @@ def test_error_table(): assert "'There is no entry in the schema" in str(caught.value) assert "'Not an enum' is not one of [" in str(caught.value) # Correct Locations + matches = set() for line in str(caught.value).split('\n'): if "'Not a num' is not of type 'number'" in line: assert "J7" in line + matches.add("J7") if "'Yes a number?' is not of type 'number'" in line: assert "J8" in line + matches.add("J8") if "1.5 is not of type 'integer'" in line: assert "K7" in line + matches.add("K7") if "1.2345 is not of type 'integer'" in line: assert "K8" in line + matches.add("K8") if "'There is no entry in the schema" in line: assert "Column M" in line + matches.add("Col M") if "'Not an enum' is not one of [" in line: assert "G8" in line + matches.add("K8") + # The next two tests could potentially be removed in the future, once we evaluate formulas. + if "'=NOT(FALSE())' is not of type 'boolean'" in line: + assert "L9" in line + matches.add("L9") + if "'=NOT(TRUE())' is not of type 'boolean'" in line: + assert "L10" in line + matches.add("L10") + assert matches == {"J7", "J8", "K7", "K8", "Col M", "K8", "L9", "L10"} + # No additional errors assert str(caught.value).count("Malformed metadata: Cannot parse paths in worksheet") == 1 assert str(caught.value).count("There is no entry in the schema") == 1 assert str(caught.value).count("is not one of") == 1 - assert str(caught.value).count("is not of type") == 4 + assert str(caught.value).count("is not of type") == 6 # Check correct error message for completely unknown path with pytest.raises(jsonschema.ValidationError) as caught: convert.to_dict(xlsx=rfp("data/simple_data_broken_paths.xlsx"), diff --git a/unittests/table_json_conversion/utils.py b/unittests/table_json_conversion/utils.py index b95715f7..ac76fbea 100644 --- a/unittests/table_json_conversion/utils.py +++ b/unittests/table_json_conversion/utils.py @@ -58,7 +58,8 @@ Raise an assertion exception if they are not equal.""" "the other.") return assert isinstance(json1, list) and isinstance(json2, list), f"Is not a list, path: {path}" - assert len(json1) == len(json2), f"Lists must have equal length, path: {path}" + assert len(json1) == len(json2), (f"Lists must have equal length, path: {path}\n" + f"{json1}\n ---\n{json2}") for idx, (el1, el2) in enumerate(zip(json1, json2)): this_path = path + [idx] if isinstance(el1, dict): -- GitLab From 1c3710e205036c0afe93d108a865352ad157616c Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Fri, 6 Dec 2024 16:27:35 +0100 Subject: [PATCH 076/106] STY: autopep8'd --- unittests/test_sss_helper.py | 2 ++ unittests/test_table_importer.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/unittests/test_sss_helper.py b/unittests/test_sss_helper.py index 8baab849..caaf49d4 100644 --- a/unittests/test_sss_helper.py +++ b/unittests/test_sss_helper.py @@ -86,6 +86,8 @@ def test_send_mail(): assert msg.get_content() == "hello!\n" # skip on windows (has no sendmail) + + @mark.skipif(platform.system() == "Windows", reason="no sendmail on Windows") def test_send_mail_error(): with raises(subprocess.CalledProcessError): diff --git a/unittests/test_table_importer.py b/unittests/test_table_importer.py index fc0d5f0e..c1336ee5 100644 --- a/unittests/test_table_importer.py +++ b/unittests/test_table_importer.py @@ -196,7 +196,7 @@ class TableImporterTest(unittest.TestCase): [5678, 1, 2.0, 3, 'yes']], columns=['a', 'b', 'c', 'float', 'd']) # wrong datatypes before - assert df["a"].dtype != pd.StringDtype + assert df["a"].dtype != pd.StringDtype assert df["float"].dtype != float # strict = False by default, so this shouldn't raise an error importer.check_datatype(df) -- GitLab From 55124063ad05408c515d20428cdf52b2d6022614 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 13 Dec 2024 11:35:14 +0100 Subject: [PATCH 077/106] MNT: Remove unused imports --- src/caosadvancedtools/cfood.py | 3 +-- src/caosadvancedtools/crawler.py | 1 - src/caosadvancedtools/models/parser.py | 3 --- src/caosadvancedtools/pandoc_header_tools.py | 3 --- src/caosadvancedtools/table_converter.py | 1 - src/caosadvancedtools/utils.py | 1 - 6 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/caosadvancedtools/cfood.py b/src/caosadvancedtools/cfood.py index e79f0373..8ae01632 100644 --- a/src/caosadvancedtools/cfood.py +++ b/src/caosadvancedtools/cfood.py @@ -46,9 +46,8 @@ from abc import ABCMeta, abstractmethod from datetime import datetime import linkahead as db -from linkahead.common.models import Entity from linkahead.exceptions import (BadQueryError, EmptyUniqueQueryError, - QueryNotUniqueError, TransactionError) + QueryNotUniqueError) from .datamodel_problems import DataModelProblems from .guard import global_guard as guard diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index 7a840624..e5bdd142 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -41,7 +41,6 @@ match. This occurs in basically three steps: import logging import os -import subprocess import traceback import uuid from datetime import datetime diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index b1e3aa95..a33f37ca 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -36,11 +36,8 @@ Parents can be provided under the 'inherit_from_xxxx' keywords. The value needs to be a list with the names. Here, NO NEW entities can be defined. """ import argparse -import json -import re import sys from typing import List, Optional -from warnings import warn import jsonref import jsonschema diff --git a/src/caosadvancedtools/pandoc_header_tools.py b/src/caosadvancedtools/pandoc_header_tools.py index e0e62c8c..bf9b25a9 100644 --- a/src/caosadvancedtools/pandoc_header_tools.py +++ b/src/caosadvancedtools/pandoc_header_tools.py @@ -30,10 +30,7 @@ # D. Hornung 2019-02 # T. Fitschen 2019-02 -import argparse -import glob import os -import re import yaml diff --git a/src/caosadvancedtools/table_converter.py b/src/caosadvancedtools/table_converter.py index 2f0d4cc9..bfbf6296 100644 --- a/src/caosadvancedtools/table_converter.py +++ b/src/caosadvancedtools/table_converter.py @@ -25,7 +25,6 @@ import re import sys import linkahead as db -import numpy as np import pandas as pd diff --git a/src/caosadvancedtools/utils.py b/src/caosadvancedtools/utils.py index 9a0342e9..3e1e6992 100644 --- a/src/caosadvancedtools/utils.py +++ b/src/caosadvancedtools/utils.py @@ -25,7 +25,6 @@ import logging import os -import pathlib import linkahead as db from linkahead.exceptions import TransactionError -- GitLab From 57712195b27f78e15094ccb118dfd5e807d1880f Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 13 Dec 2024 11:38:18 +0100 Subject: [PATCH 078/106] MNT: Move main into method --- src/caosadvancedtools/collect_datamodel.py | 6 +++++- src/caosadvancedtools/export_related.py | 6 +++++- src/caosadvancedtools/import_from_xml.py | 6 +++++- src/caosadvancedtools/models/parser.py | 6 +++++- src/caosadvancedtools/table_converter.py | 7 +++++-- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/caosadvancedtools/collect_datamodel.py b/src/caosadvancedtools/collect_datamodel.py index 1c37bab0..f485aec6 100644 --- a/src/caosadvancedtools/collect_datamodel.py +++ b/src/caosadvancedtools/collect_datamodel.py @@ -112,7 +112,7 @@ def compare(directory): print("{} is missing in the existing properties".format(p)) -if __name__ == "__main__": +def main(): p = get_parser() args = p.parse_args() @@ -121,3 +121,7 @@ if __name__ == "__main__": if args.compare: compare(args.compare) + + +if __name__ == "__main__": + main() diff --git a/src/caosadvancedtools/export_related.py b/src/caosadvancedtools/export_related.py index 1ac6d2cb..72484a30 100755 --- a/src/caosadvancedtools/export_related.py +++ b/src/caosadvancedtools/export_related.py @@ -149,8 +149,12 @@ def defineParser(): return parser -if __name__ == "__main__": +def main(): parser = defineParser() args = parser.parse_args() export_related_to(args.id, directory=args.directory) + + +if __name__ == "__main__": + main() diff --git a/src/caosadvancedtools/import_from_xml.py b/src/caosadvancedtools/import_from_xml.py index 7bc9f018..23ea79c1 100755 --- a/src/caosadvancedtools/import_from_xml.py +++ b/src/caosadvancedtools/import_from_xml.py @@ -122,8 +122,12 @@ def defineParser(): return parser -if __name__ == "__main__": +def main(): parser = defineParser() args = parser.parse_args() import_xml(args.file, args.rerun) + + +if __name__ == "__main__": + main() diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index a33f37ca..7b91891f 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -1016,7 +1016,7 @@ class JsonSchemaParser(Parser): return returns -if __name__ == "__main__": +def main(): parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawTextHelpFormatter) parser.add_argument("data_model", @@ -1039,3 +1039,7 @@ if __name__ == "__main__": print(model) if args.sync: model.sync_data_model(noquestion=args.noquestion) + + +if __name__ == "__main__": + main() diff --git a/src/caosadvancedtools/table_converter.py b/src/caosadvancedtools/table_converter.py index bfbf6296..c5fcb969 100644 --- a/src/caosadvancedtools/table_converter.py +++ b/src/caosadvancedtools/table_converter.py @@ -98,8 +98,7 @@ def from_table(spreadsheet, recordtype): return records -if __name__ == "__main__": - +def main(): p = argparse.ArgumentParser() p.add_argument("-f", "--filename", help="The excel filename") p.add_argument("--auth-token") @@ -110,3 +109,7 @@ if __name__ == "__main__": recordtype = "Experiment" from_tsv(arg.filename, recordtype) + + +if __name__ == "__main__": + main() \ No newline at end of file -- GitLab From 36951518ed6f16fc2e76bb1533335a11629b85de Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 13 Dec 2024 11:52:00 +0100 Subject: [PATCH 079/106] MNT: Specify encodings when opening file --- src/caosadvancedtools/collect_datamodel.py | 8 ++++---- src/caosadvancedtools/crawler.py | 2 +- src/caosadvancedtools/export_related.py | 2 +- src/caosadvancedtools/import_from_xml.py | 4 ++-- src/caosadvancedtools/loadFiles.py | 4 ++-- src/caosadvancedtools/models/parser.py | 4 ++-- src/caosadvancedtools/pandoc_header_tools.py | 10 +++++----- src/caosadvancedtools/table_export.py | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/caosadvancedtools/collect_datamodel.py b/src/caosadvancedtools/collect_datamodel.py index f485aec6..bb69a03d 100644 --- a/src/caosadvancedtools/collect_datamodel.py +++ b/src/caosadvancedtools/collect_datamodel.py @@ -62,9 +62,9 @@ def store(directory, xml=False): rts, ps = get_dm() os.makedirs(directory, exist_ok=True) - with open(os.path.join(directory, "recordtypes.txt"), "w") as fi: + with open(os.path.join(directory, "recordtypes.txt"), "w", encoding="utf-8") as fi: fi.write(",".join([el[1] for el in rts])) - with open(os.path.join(directory, "properties.txt"), "w") as fi: + with open(os.path.join(directory, "properties.txt"), "w", encoding="utf-8") as fi: fi.write(",".join([el[1] for el in ps])) if xml: @@ -75,10 +75,10 @@ def store(directory, xml=False): def load_dm(directory): - with open(os.path.join(directory, "recordtypes.txt"), "r") as fi: + with open(os.path.join(directory, "recordtypes.txt"), "r", encoding="utf-8") as fi: text = fi.read() rts = [el.strip() for el in text.split(",")] - with open(os.path.join(directory, "properties.txt"), "r") as fi: + with open(os.path.join(directory, "properties.txt"), "r", encoding="utf-8") as fi: text = fi.read() ps = [el.strip() for el in text.split(",")] diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index e5bdd142..9b960d57 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -599,7 +599,7 @@ ____________________\n""".format(i+1, len(pending_changes)) + str(el[3])) randname = os.path.basename(os.path.abspath(directory)) filepath = os.path.abspath(os.path.join(directory, filename)) filename = os.path.join(randname, filename) - with open(filepath, "w") as f: + with open(filepath, "w", encoding="utf-8") as f: f.write(form) return filename diff --git a/src/caosadvancedtools/export_related.py b/src/caosadvancedtools/export_related.py index 72484a30..d25381f9 100755 --- a/src/caosadvancedtools/export_related.py +++ b/src/caosadvancedtools/export_related.py @@ -128,7 +128,7 @@ def export(cont, directory="."): xml = etree.tounicode(cont.to_xml( local_serialization=True), pretty_print=True) - with open(os.path.join(directory, "linkahead_data.xml"), "w") as fi: + with open(os.path.join(directory, "linkahead_data.xml"), "w", encoding="utf-8") as fi: fi.write(xml) diff --git a/src/caosadvancedtools/import_from_xml.py b/src/caosadvancedtools/import_from_xml.py index 23ea79c1..4f9bba99 100755 --- a/src/caosadvancedtools/import_from_xml.py +++ b/src/caosadvancedtools/import_from_xml.py @@ -39,7 +39,7 @@ from caosadvancedtools.models.data_model import DataModel def create_dummy_file(text="Please ask the administrator for this file."): tmpfile = NamedTemporaryFile(delete=False) tmpfile.close() - with open(tmpfile.name, "w") as tm: + with open(tmpfile.name, "w", encoding="utf-8") as tm: tm.write(text) return tmpfile.name @@ -51,7 +51,7 @@ def import_xml(filename, rerun=False, interactive=True): rerun: boolean; if true, files are not inserted as paths would conflict. """ cont = db.Container() - with open(filename) as fi: + with open(filename, encoding="utf-8") as fi: cont = cont.from_xml(fi.read()) tmpfile = create_dummy_file() diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index c9258afa..8e3b466f 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -90,9 +90,9 @@ def combine_ignore_files(caosdbignore: str, localignore: str, dirname=None) -> s tmp = NamedTemporaryFile(delete=False, mode="w", dir=dirname, prefix=".caosdbignore") - with open(caosdbignore, "r") as base: + with open(caosdbignore, "r", encoding="utf-8") as base: tmp.write(base.read()) - with open(localignore, "r") as local: + with open(localignore, "r", encoding="utf-8") as local: tmp.write(local.read()) tmp.close() return tmp.name diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 7b91891f..f6e142db 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -247,7 +247,7 @@ debug : bool, optional out : data_model.DataModel The created DataModel """ - with open(filename, 'r') as outfile: + with open(filename, 'r', encoding="utf-8") as outfile: ymlmodel = yaml.load(outfile, Loader=SafeLineLoader) return self._create_model_from_dict(ymlmodel, existing_model=existing_model) @@ -731,7 +731,7 @@ class JsonSchemaParser(Parser): # @author Florian Spreckelsen # @date 2022-02-17 # @review Timm Fitschen 2023-05-25 - with open(filename, 'r') as schema_file: + with open(filename, 'r', encoding="utf-8") as schema_file: model_dict = jsonref.load(schema_file) return self._create_model_from_dict(model_dict, top_level_recordtype=top_level_recordtype) diff --git a/src/caosadvancedtools/pandoc_header_tools.py b/src/caosadvancedtools/pandoc_header_tools.py index bf9b25a9..a6879565 100644 --- a/src/caosadvancedtools/pandoc_header_tools.py +++ b/src/caosadvancedtools/pandoc_header_tools.py @@ -103,7 +103,7 @@ it is not at the beginning, it must be preceded by a blank line. if not os.path.exists(filename): raise MetadataFileMissing(filename) - with open(filename) as f: + with open(filename, encoding="utf-8") as f: textlines = f.readlines() state = 0 @@ -168,7 +168,7 @@ def save_header(filename, header_data): if os.path.isdir(filename): filename = os.path.join(filename, "README.md") - with open(filename) as f: + with open(filename, encoding="utf-8") as f: textlines = f.readlines() while textlines[header_data[0]] != "...\n": @@ -181,7 +181,7 @@ def save_header(filename, header_data): default_flow_style=False, allow_unicode=True)) - with open(filename, "w") as f: + with open(filename, "w", encoding="utf-8") as f: f.writelines(textlines) @@ -199,7 +199,7 @@ def add_header(filename, header_dict=None): filename = os.path.join(filename, "README.md") if os.path.exists(filename): - with open(filename) as f: + with open(filename, encoding="utf-8") as f: textlines = f.readlines() else: textlines = "" @@ -211,7 +211,7 @@ def add_header(filename, header_dict=None): default_flow_style=False, allow_unicode=True) + "...\n" - with open(filename, "w") as f: + with open(filename, "w", encoding="utf-8") as f: f.write(localheader) f.writelines(textlines) diff --git a/src/caosadvancedtools/table_export.py b/src/caosadvancedtools/table_export.py index 00e644e4..9b821394 100644 --- a/src/caosadvancedtools/table_export.py +++ b/src/caosadvancedtools/table_export.py @@ -123,7 +123,7 @@ class BaseTableExporter(object): self.export_dict = export_dict else: try: - with open(export_dict) as tmp: + with open(export_dict, encoding="utf-8") as tmp: self.export_dict = json.load(tmp) except BaseException: raise ValueError( -- GitLab From 40961b1dd1fa61772dee63858f68983dfe09f9d8 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 13 Dec 2024 12:01:10 +0100 Subject: [PATCH 080/106] MNT: Fix various pylint errors: - Remove unnecessary pass, init without effect, unused variables - Update use of deprecated methods - Fix used exception not matching documentation - Ignore logging-fstring-interpolation, variant of logging-format-interpolation --- pylintrc | 1 + src/caosadvancedtools/cache.py | 6 ------ src/caosadvancedtools/cfood.py | 1 - src/caosadvancedtools/crawler.py | 4 ++-- src/caosadvancedtools/import_from_xml.py | 2 +- src/caosadvancedtools/loadFiles.py | 2 +- src/caosadvancedtools/models/parser.py | 2 +- src/caosadvancedtools/scifolder/withreadme.py | 4 ++-- src/caosadvancedtools/table_converter.py | 2 +- src/caosadvancedtools/utils.py | 1 - src/caosadvancedtools/webui_formatter.py | 2 +- 11 files changed, 10 insertions(+), 17 deletions(-) diff --git a/pylintrc b/pylintrc index 1be7cd8d..e95afc90 100644 --- a/pylintrc +++ b/pylintrc @@ -19,4 +19,5 @@ init-hook= disable= fixme, logging-format-interpolation, + logging-fstring-interpolation, logging-not-lazy, diff --git a/src/caosadvancedtools/cache.py b/src/caosadvancedtools/cache.py index 46564393..5fc1ec3c 100644 --- a/src/caosadvancedtools/cache.py +++ b/src/caosadvancedtools/cache.py @@ -94,7 +94,6 @@ class AbstractCache(ABC): Increase this variable, when changes to the cache tables are made. """ - pass @abstractmethod def create_cache(self): @@ -102,14 +101,12 @@ class AbstractCache(ABC): Provide an overloaded function here that creates the cache in the most recent version. """ - pass @abstractmethod def get_default_file_name(self): """ Supply a default file name for the cache here. """ - pass def check_cache(self): """ @@ -192,9 +189,6 @@ class IdentifiableCache(AbstractCache): def get_default_file_name(self): return "caosdb_identifiable_cache.db" - def __init__(self, db_file=None, force_creation=False): - super().__init__(db_file, force_creation) - def create_cache(self): """ Create a new SQLITE cache file in self.db_file. diff --git a/src/caosadvancedtools/cfood.py b/src/caosadvancedtools/cfood.py index 8ae01632..4647a576 100644 --- a/src/caosadvancedtools/cfood.py +++ b/src/caosadvancedtools/cfood.py @@ -208,7 +208,6 @@ class AbstractCFood(object, metaclass=ABCMeta): To be overwritten by subclasses """ - pass def attach(self, item): self.attached_items.append(item) diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index 9b960d57..dfc5351c 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -487,8 +487,8 @@ ____________________\n""".format(i+1, len(pending_changes)) + str(el[3])) logger.error(err_msg) logger.error('Crawler finished with Datamodel Errors') elif errors_occured: - msg = "There were fatal errors during execution, please " - "contact the system administrator!" + msg = ("There were fatal errors during execution, please contact " + "the system administrator!") if self.debug_file: msg += "\nPlease provide the following path:\n{}".format( diff --git a/src/caosadvancedtools/import_from_xml.py b/src/caosadvancedtools/import_from_xml.py index 4f9bba99..540091b0 100755 --- a/src/caosadvancedtools/import_from_xml.py +++ b/src/caosadvancedtools/import_from_xml.py @@ -94,7 +94,7 @@ def import_xml(filename, rerun=False, interactive=True): if not rerun: for _, el in enumerate(files.values()): - r = el.insert(unique=False) + el.insert(unique=False) else: for _, el in enumerate(files.values()): el.id = None diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index 8e3b466f..56d50e4d 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -122,7 +122,7 @@ def compile_file_list(caosdbignore: str, localpath: str) -> list[str]: current_ignore = caosdbignore non_ignored_files = [] ignore_files: list[tuple[str, str]] = [] - for root, dirs, files in os.walk(localpath): + for root, _, files in os.walk(localpath): # remove local ignore files that do no longer apply to the current subtree (branch switch) while len(ignore_files) > 0 and not root.startswith(ignore_files[-1][0]): os.remove(ignore_files[-1][1]) diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index f6e142db..1cd1fe6e 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -633,7 +633,7 @@ debug : bool, optional """ - for key, value in self.model.items(): + for _, value in self.model.items(): if isinstance(value, db.Property): dtype = value.datatype diff --git a/src/caosadvancedtools/scifolder/withreadme.py b/src/caosadvancedtools/scifolder/withreadme.py index 94280b80..faab94cb 100644 --- a/src/caosadvancedtools/scifolder/withreadme.py +++ b/src/caosadvancedtools/scifolder/withreadme.py @@ -156,8 +156,8 @@ class WithREADME(object): for f in sublist] if len(flat_list) == 0: - LOGGER.warn("ATTENTION: the field {} does not reference any " - "known files".format(field.key)) + LOGGER.warning(f"ATTENTION: the field {field.key} does not" + " reference any known files") self.attached_filenames.extend(flat_list) # pylint: disable=no-member diff --git a/src/caosadvancedtools/table_converter.py b/src/caosadvancedtools/table_converter.py index c5fcb969..16f27476 100644 --- a/src/caosadvancedtools/table_converter.py +++ b/src/caosadvancedtools/table_converter.py @@ -73,7 +73,7 @@ def from_table(spreadsheet, recordtype): """ parses a pandas DataFrame to a list of records """ records = db.Container() - for idx, row in spreadsheet.iterrows(): + for _, row in spreadsheet.iterrows(): rec = db.Record() rec.add_parent(name=recordtype) diff --git a/src/caosadvancedtools/utils.py b/src/caosadvancedtools/utils.py index 3e1e6992..0d73f962 100644 --- a/src/caosadvancedtools/utils.py +++ b/src/caosadvancedtools/utils.py @@ -235,7 +235,6 @@ def find_records_that_reference_ids(referenced_ids, rt="", step_size=50): record_ids.update([exp.id for exp in exps]) except Exception as e: print(e) - pass index += step_size diff --git a/src/caosadvancedtools/webui_formatter.py b/src/caosadvancedtools/webui_formatter.py index c3c5381d..43ebbe06 100644 --- a/src/caosadvancedtools/webui_formatter.py +++ b/src/caosadvancedtools/webui_formatter.py @@ -92,4 +92,4 @@ class WebUI_Formatter(logging.Formatter): return wrap_bootstrap_alert("<b>CRITICAL ERROR:</b> " + text, kind="danger") else: - raise Exception("unknown level") + raise RuntimeError("unknown level") -- GitLab From 433160cf8143d4ef0dccdc0c88ff060bb514dfcd Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 13 Dec 2024 15:39:36 +0100 Subject: [PATCH 081/106] MNT: Replace dict default values with None and update in method body --- src/caosadvancedtools/crawler.py | 4 +++- src/caosadvancedtools/models/parser.py | 10 ++++++++-- src/caosadvancedtools/table_importer.py | 5 +++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index dfc5351c..7b5251af 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -66,7 +66,7 @@ def separated(text): return "-"*60 + "\n" + text -def apply_list_of_updates(to_be_updated, update_flags={}, +def apply_list_of_updates(to_be_updated, update_flags=None, update_cache=None, run_id=None): """Updates the `to_be_updated` Container, i.e., pushes the changes to LinkAhead after removing possible duplicates. If a chace is provided, uauthorized @@ -86,6 +86,8 @@ def apply_list_of_updates(to_be_updated, update_flags={}, Id with which the pending updates are cached. Only meaningful if `update_cache` is provided. Default is None. """ + if update_flags is None: + update_flags = {} if len(to_be_updated) == 0: return diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 1cd1fe6e..b97e507e 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -162,7 +162,7 @@ debug : bool, optional def parse_model_from_json_schema( filename: str, top_level_recordtype: bool = True, - types_for_missing_array_items: dict = {}, + types_for_missing_array_items: dict = None, ignore_unspecified_array_items: bool = False, existing_model: Optional[dict] = None ): @@ -204,6 +204,9 @@ def parse_model_from_json_schema( about the limitations of the current implementation. """ + if types_for_missing_array_items is None: + types_for_missing_array_items = {} + if existing_model is not None: raise NotImplementedError("Adding to an existing model is not implemented yet.") @@ -706,8 +709,11 @@ class JsonSchemaParser(Parser): # @date 2022-02-17 # @review Timm Fitschen 2023-05-25 - def __init__(self, types_for_missing_array_items={}, ignore_unspecified_array_items=False): + def __init__(self, types_for_missing_array_items=None, + ignore_unspecified_array_items=False): super().__init__() + if types_for_missing_array_items is None: + types_for_missing_array_items = {} self.types_for_missing_array_items = types_for_missing_array_items self.ignore_unspecified_array_items = ignore_unspecified_array_items diff --git a/src/caosadvancedtools/table_importer.py b/src/caosadvancedtools/table_importer.py index cd1b206f..b3977b39 100755 --- a/src/caosadvancedtools/table_importer.py +++ b/src/caosadvancedtools/table_importer.py @@ -110,8 +110,7 @@ def date_converter(val, fmt="%Y-%m-%d"): return datetime_converter(val, fmt=fmt).date() -def incomplete_date_converter(val, fmts={"%Y-%m-%d": "%Y-%m-%d", - "%Y-%m": "%Y-%m", "%Y": "%Y"}): +def incomplete_date_converter(val, fmts=None): """ if the value is already a datetime, it is returned otherwise it converts it using format string @@ -124,6 +123,8 @@ def incomplete_date_converter(val, fmts={"%Y-%m-%d": "%Y-%m-%d", keys are the formats into which the input value is tried to be converted, values are the possible input formats. """ + if fmts is None: + fmts = {"%Y-%m-%d": "%Y-%m-%d", "%Y-%m": "%Y-%m", "%Y": "%Y"} for to, fro in fmts.items(): try: -- GitLab From 80031cfd69d6670a8adf6e720764e7be94aaa50a Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 13 Dec 2024 15:41:52 +0100 Subject: [PATCH 082/106] MNT: Move attribute definitions into init --- src/caosadvancedtools/crawler.py | 1 + src/caosadvancedtools/example_cfood.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index 7b5251af..639eb741 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -170,6 +170,7 @@ class Crawler(object): self.abort_on_exception = abort_on_exception self.update_cache = UpdateCache() self.filterKnown = SuppressKnown() + self.run_id = None advancedtoolslogger = logging.getLogger("caosadvancedtools") # TODO this seems to be a bad idea. What if the handler was not added diff --git a/src/caosadvancedtools/example_cfood.py b/src/caosadvancedtools/example_cfood.py index 45984998..43a558fd 100644 --- a/src/caosadvancedtools/example_cfood.py +++ b/src/caosadvancedtools/example_cfood.py @@ -31,6 +31,10 @@ class ExampleCFood(AbstractFileCFood): return (r".*/(?P<species>[^/]+)/" r"(?P<date>\d{4}-\d{2}-\d{2})/README.md") + def __init__(self, crawled_path, *args, **kwargs): + super().__init__(crawled_path, *args, **kwargs) + self.experiment = None + def create_identifiables(self): self.experiment = db.Record() self.experiment.add_parent(name="Experiment") -- GitLab From 6028bbb4e61113c2f06dc8ee2e14e83714b90fb2 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Fri, 13 Dec 2024 15:42:38 +0100 Subject: [PATCH 083/106] MNT: Fix various pylint warnings --- src/caosadvancedtools/crawler.py | 2 +- src/caosadvancedtools/utils.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index 639eb741..4214fd9e 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -357,7 +357,7 @@ class Crawler(object): except BaseException: pass logger.debug("Failed during execution of {}!".format( - Cfood.__name__)) + cfood.__name__)) logger.debug(traceback.format_exc()) logger.debug(e) remove_cfoods.append(cfood) diff --git a/src/caosadvancedtools/utils.py b/src/caosadvancedtools/utils.py index 0d73f962..43ecb3f2 100644 --- a/src/caosadvancedtools/utils.py +++ b/src/caosadvancedtools/utils.py @@ -32,9 +32,8 @@ from linkahead.exceptions import TransactionError logger = logging.getLogger(__name__) -def set_log_level(level): - logger = logging.getLogger(__name__) - logger.setLevel(level=logging.DEBUG) +def set_log_level(level=logging.DEBUG): + logger.setLevel(level=level) def replace_path_prefix(path, old_prefix, new_prefix): -- GitLab From 7c5928e09cc7e488d03680c2327c1825f848f6c1 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Sat, 14 Dec 2024 18:57:23 +0100 Subject: [PATCH 084/106] MNT: Replace BaseException with Exception where catching system errors does not seem necessary --- integrationtests/test_base_table_exporter_integration.py | 2 +- integrationtests/test_cache.py | 2 +- integrationtests/test_crawler_basics.py | 2 +- src/caosadvancedtools/crawler.py | 4 ++-- src/caosadvancedtools/export_related.py | 2 +- src/caosadvancedtools/table_export.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/integrationtests/test_base_table_exporter_integration.py b/integrationtests/test_base_table_exporter_integration.py index 286c4ac3..0dbfc7e7 100644 --- a/integrationtests/test_base_table_exporter_integration.py +++ b/integrationtests/test_base_table_exporter_integration.py @@ -82,7 +82,7 @@ def setup_module(): """Clear all test entities""" try: db.execute_query("FIND ENTITY Test*").delete() - except BaseException: + except Exception: pass diff --git a/integrationtests/test_cache.py b/integrationtests/test_cache.py index 13470b8b..7724cfb4 100644 --- a/integrationtests/test_cache.py +++ b/integrationtests/test_cache.py @@ -67,7 +67,7 @@ class CacheTest(unittest.TestCase): print(db.execute_query("FIND entity with id="+str(rec.id), unique=True)) try: print(db.execute_query("FIND Record "+str(rec.id), unique=True)) - except BaseException: + except Exception: print("Query does not work as expected") update.insert(cont, run_id) assert len(update.get_updates(run_id)) == 1 diff --git a/integrationtests/test_crawler_basics.py b/integrationtests/test_crawler_basics.py index 04eb5459..67317f32 100644 --- a/integrationtests/test_crawler_basics.py +++ b/integrationtests/test_crawler_basics.py @@ -114,7 +114,7 @@ class CrawlerTest(unittest.TestCase): for el in [self.rec1, self.rec2, self.rec3]: try: el.delete() - except BaseException: + except Exception: pass diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index 4214fd9e..ad2536c2 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -322,7 +322,7 @@ class Crawler(object): except Exception as e: try: DataModelProblems.evaluate_exception(e) - except BaseException: + except Exception: pass logger.debug("Failed during execution of {}!".format( Cfood.__name__)) @@ -354,7 +354,7 @@ class Crawler(object): except Exception as e: try: DataModelProblems.evaluate_exception(e) - except BaseException: + except Exception: pass logger.debug("Failed during execution of {}!".format( cfood.__name__)) diff --git a/src/caosadvancedtools/export_related.py b/src/caosadvancedtools/export_related.py index d25381f9..2114f388 100755 --- a/src/caosadvancedtools/export_related.py +++ b/src/caosadvancedtools/export_related.py @@ -118,7 +118,7 @@ def export(cont, directory="."): try: el.download(target) print("Downloaded:", target) - except BaseException: + except Exception: print("Failed download of:", target) invert_ids(cont) diff --git a/src/caosadvancedtools/table_export.py b/src/caosadvancedtools/table_export.py index 9b821394..78830b19 100644 --- a/src/caosadvancedtools/table_export.py +++ b/src/caosadvancedtools/table_export.py @@ -125,7 +125,7 @@ class BaseTableExporter(object): try: with open(export_dict, encoding="utf-8") as tmp: self.export_dict = json.load(tmp) - except BaseException: + except Exception: raise ValueError( "export_dict must be either a dictionary" " or the path to a json file.") -- GitLab From 198eecbf0bc29eefeecfb4bcc4b322b56fc6da90 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Sun, 15 Dec 2024 19:58:35 +0100 Subject: [PATCH 085/106] ENH: XLSXConverter now checks the paths in the given workbook for validity: - New method XLSXConverter._check_path_validity() called in __init__ - New test with test data containing various incorrect paths - Updated tests and test data to reflect new behaviour --- CHANGELOG.md | 1 + .../table_json_conversion/convert.py | 115 +++++++++++++++--- .../data/simple_data_broken.xlsx | Bin 9299 -> 9126 bytes .../data/simple_data_broken_paths_2.xlsx | Bin 0 -> 8838 bytes .../table_json_conversion/test_read_xlsx.py | 75 ++++++++---- 5 files changed, 149 insertions(+), 42 deletions(-) create mode 100644 unittests/table_json_conversion/data/simple_data_broken_paths_2.xlsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a118d98..6628f1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### - Yaml data model parser adds data types of properties of record types and other attributes which fixes https://gitlab.indiscale.com/caosdb/customers/f-fit/management/-/issues/58 +- `XLSXConverter` now checks path validity before parsing the worksheet. ### Security ### diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index b416fc29..370dc85d 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -182,16 +182,107 @@ class XLSXConverter: self._workbook = load_workbook(xlsx) self._schema = read_or_dict(schema) self._defining_path_index = xlsx_utils.get_defining_paths(self._workbook) - try: - self._check_columns(fail_fast=strict) - except KeyError as e: - raise jsonschema.ValidationError(f"Malformed metadata: Cannot parse paths. " - f"Unknown path: '{e.args[1]}' in sheet '{e.args[0]}'." - ) from e + self._check_path_validity() + self._check_columns(fail_fast=strict) self._handled_sheets: set[str] = set() self._result: dict = {} self._errors: dict = {} + def _check_path_validity(self): + """ + Method to check the workbook paths for completeness and correctness, + and raises a jsonschema.ValidationError containing information on all + faulty paths if any are found. + + If this method does not raise an error, this does not mean the workbook + is formatted correctly, only that the contained paths are complete and + can be found in the schema. + """ + # Setup + error_message = ["There were errors during path validation:"] + only_warnings = True + for sheetname in self._workbook.sheetnames: + sheet = self._workbook[sheetname] + error_message.append(f"\nIn sheet {sheetname}:") + + # Collect path information and filter out information column + row_i_col_type = xlsx_utils.get_column_type_row_index(sheet) + path_rows = xlsx_utils.get_path_rows(sheet) + paths = [] + for col_i, col in enumerate(sheet.iter_cols()): + col_type = col[row_i_col_type].value + path = [col[row_i].value for row_i in path_rows + if col[row_i].value not in [None, '']] + if col_type == 'COL_TYPE': + continue + paths.append((col_type, path, col_i, col)) + + # Check paths + for col_type, path, col_i, col in paths: + # No column type set + if col_type in [None, '']: + if len(path) == 0: # Likely a comment column + # Check whether the column has any visible content + content_in_column = False + for cell in col: + visible_content = ''.join(str(cell.value)).split() + if cell.value is not None and visible_content != '': + content_in_column = True + # If yes - might be an error but is not forbidden, so warn + if content_in_column: + m = (f"Warning:\tIn column {_column_id_to_chars(col_i)} " + f"there is no column metadata set. This column " + f"will be ignored during parsing.") + error_message.append(m) + continue + else: # Path is set but no column type + only_warnings = False + m = (f"ERROR:\t\tIn column {_column_id_to_chars(col_i)} " + f"the column type is missing.") + error_message.append(m) + # No continue - even if column type is missing, we can check path + if len(path) == 0: # Column type is set but no path + only_warnings = False + m = (f"ERROR:\t\tIn column {_column_id_to_chars(col_i)} " + f"the path is missing.") + error_message.append(m) + continue + # Check path is in schema + try: + subschema = xlsx_utils.get_subschema(path, self._schema) + schema_type = subschema.get('type', None) + if schema_type is None and 'enum' in subschema: + schema_type = 'enum' + if schema_type is None and 'anyOf' in subschema: + schema_type = 'anyOf' + if schema_type == 'array': # Check item type instead + schema_type = subschema.get('items', {}).get('type', None) + if schema_type in ['object', 'array', None]: + m = (f"Warning:\tIn column {_column_id_to_chars(col_i)} " + f"the path may be incomplete.") + error_message.append(m) + except KeyError as e: + only_warnings = False + m = (f"ERROR:\t\tIn column {_column_id_to_chars(col_i)} " + f"parsing of the path '{'.'.join(path)}' fails " + f"on the path component {str(e)}.\n\t\t\t" + f"This likely means the path is incomplete or not " + f"present in the schema.") + error_message.append(m) + + # Cleanup if no errors were found + if error_message[-1] == f"\nIn sheet {sheetname}:": + error_message.pop(-1) + + # Determine whether error / warning / nothing should be raised + if error_message == ["There were errors during path validation:"]: + return + error_message = '\n'.join(error_message) + if only_warnings: + warn(error_message) + else: + raise jsonschema.ValidationError(error_message) + def to_dict(self, validate: bool = False, collect_errors: bool = True) -> dict: """Convert the xlsx contents to a dict. @@ -375,13 +466,6 @@ class XLSXConverter: value = self._validate_and_convert(value, path) _set_in_nested(mydict=data, path=path, value=value, prefix=parent, skip=1) continue - elif sheet.cell(col_type_row+1, col_idx+1).value is None: - mess = (f"\nNo metadata configured for column " - f"'{_column_id_to_chars(col_idx)}' in worksheet " - f"'{sheet.title}'.\n") - if mess not in warns: - print(mess, file=sys.stderr) - warns.append(mess) # Prevent multiple instances of same warning except (ValueError, KeyError, jsonschema.ValidationError) as e: # Append error for entire column only once if isinstance(e, KeyError) and 'column' in str(e): @@ -460,10 +544,7 @@ class XLSXConverter: """ if value is None: return value - try: - subschema = self._get_subschema(path) - except KeyError as e: - raise KeyError("There is no entry in the schema that corresponds to this column.") from e + subschema = self._get_subschema(path) # Array handling only if schema says it's an array. if subschema.get("type") == "array": array_type = subschema["items"]["type"] diff --git a/unittests/table_json_conversion/data/simple_data_broken.xlsx b/unittests/table_json_conversion/data/simple_data_broken.xlsx index c75da9faaefcb7610d84e16dd6ff17dcd055b008..1e61cf108365d8e825c97742924c8ffc7b9643c1 100644 GIT binary patch delta 6665 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 RLi|n(Wdk##hSUF9^FJjEIWGVJ delta 6895 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 QK~%5=R#IF+=0EfP4`Yv`?*IS* diff --git a/unittests/table_json_conversion/data/simple_data_broken_paths_2.xlsx b/unittests/table_json_conversion/data/simple_data_broken_paths_2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..14bdbaaa5bcdf3e5541e8cfbddc68505e35f11f2 GIT binary patch literal 8838 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 KGbMlg_5T2YAW^3P literal 0 HcmV?d00001 diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index a34c046f..2a81cdc8 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -105,7 +105,8 @@ def test_missing_columns(): with pytest.warns(UserWarning) as caught: convert.to_dict(xlsx=rfp("data/simple_data_missing.xlsx"), schema=rfp("data/simple_schema.json")) - assert str(caught.pop().message) == "Missing column: Training.coach.given_name" + messages = {str(w.message) for w in caught} + assert "Missing column: Training.coach.given_name" in messages with pytest.warns(UserWarning) as caught: convert.to_dict(xlsx=rfp("data/multiple_choice_data_missing.xlsx"), schema=rfp("data/multiple_choice_schema.json")) @@ -122,12 +123,10 @@ def test_error_table(): convert.to_dict(xlsx=rfp("data/simple_data_broken.xlsx"), schema=rfp("data/simple_schema.json")) # Correct Errors - assert "Malformed metadata: Cannot parse paths in worksheet 'Person'." in str(caught.value) assert "'Not a num' is not of type 'number'" in str(caught.value) assert "'Yes a number?' is not of type 'number'" in str(caught.value) assert "1.5 is not of type 'integer'" in str(caught.value) assert "1.2345 is not of type 'integer'" in str(caught.value) - assert "'There is no entry in the schema" in str(caught.value) assert "'Not an enum' is not one of [" in str(caught.value) # Correct Locations matches = set() @@ -144,9 +143,6 @@ def test_error_table(): if "1.2345 is not of type 'integer'" in line: assert "K8" in line matches.add("K8") - if "'There is no entry in the schema" in line: - assert "Column M" in line - matches.add("Col M") if "'Not an enum' is not one of [" in line: assert "G8" in line matches.add("K8") @@ -157,33 +153,62 @@ def test_error_table(): if "'=NOT(TRUE())' is not of type 'boolean'" in line: assert "L10" in line matches.add("L10") - assert matches == {"J7", "J8", "K7", "K8", "Col M", "K8", "L9", "L10"} + assert matches == {"J7", "J8", "K7", "K8", "K8", "L9", "L10"} # No additional errors - assert str(caught.value).count("Malformed metadata: Cannot parse paths in worksheet") == 1 - assert str(caught.value).count("There is no entry in the schema") == 1 assert str(caught.value).count("is not one of") == 1 assert str(caught.value).count("is not of type") == 6 - # Check correct error message for completely unknown path - with pytest.raises(jsonschema.ValidationError) as caught: - convert.to_dict(xlsx=rfp("data/simple_data_broken_paths.xlsx"), - schema=rfp("data/simple_schema.json")) - assert ("Malformed metadata: Cannot parse paths. Unknown path: 'There' in sheet 'Person'." - == str(caught.value)) -def test_additional_column(): +def test_malformed_paths(): with pytest.raises(jsonschema.ValidationError) as caught: - convert.to_dict(xlsx=rfp("data/simple_data_broken.xlsx"), + convert.to_dict(xlsx=rfp("data/simple_data_broken_paths_2.xlsx"), schema=rfp("data/simple_schema.json")) - # Correct Error - assert "no entry in the schema that corresponds to this column" in str(caught.value) - # Correct Location - for line in str(caught.value).split('\n'): - if "no entry in the schema that corresponds to this column" in line: - assert " M " in line - # No additional column errors - assert str(caught.value).count("no entry in the schema that corresponds to this column") == 1 + message_lines = str(caught.value).lower().split('\n') + expected_errors = { + 'person': {'c': "column type is missing", + 'd': "parsing of the path", + 'e': "path may be incomplete"}, + 'training': {'c': "path is missing", + 'd': "column type is missing", + 'e': "path may be incomplete", + 'f': "parsing of the path", + 'g': "path may be incomplete", + 'h': "parsing of the path", + 'i': "parsing of the path"}, + 'training.coach': {'f': "no column metadata set"}} + current_sheet = None + for line in message_lines: + if 'in sheet' in line: + current_sheet = line.replace('in sheet ', '').replace(':', '') + continue + if 'in column' in line: + for column, expected_error in expected_errors[current_sheet].items(): + if f'in column {column}' in line: + assert expected_error in line + expected_errors[current_sheet].pop(column) + break + for _, errors_left in expected_errors.items(): + assert len(errors_left) == 0 + + +def test_empty_columns(): + with pytest.warns(UserWarning) as caught: + try: + convert.to_dict(xlsx=rfp("data/simple_data_broken.xlsx"), + schema=rfp("data/simple_schema.json")) + except jsonschema.ValidationError: + pass # Errors are checked in test_error_table + messages = {str(w.message).lower() for w in caught} + expected_warnings = {"column h": "no column metadata"} + for message in messages: + for column, warning in list(expected_warnings.items()): + if column in message: + assert warning in message + expected_warnings.pop(column) + else: + assert warning not in message + assert len(expected_warnings) == 0 def test_faulty_foreign(): -- GitLab From 22bfe2f225dc3b178ca92fc2096229b9060835e6 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Sun, 15 Dec 2024 20:02:13 +0100 Subject: [PATCH 086/106] MNT: Remove variables now unused --- src/caosadvancedtools/table_json_conversion/convert.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index 370dc85d..87427cf8 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -407,7 +407,6 @@ class XLSXConverter: If True, do not fail with unresolvable foreign definitions, but collect all errors. """ row_type_column = xlsx_utils.get_row_type_column_index(sheet) - col_type_row = xlsx_utils.get_column_type_row_index(sheet) foreign_columns = xlsx_utils.get_foreign_key_columns(sheet) foreign_column_paths = {col.index: col.path for col in foreign_columns.values()} data_columns = xlsx_utils.get_data_columns(sheet) @@ -430,7 +429,6 @@ class XLSXConverter: # entries: dict[str, list[SimpleNamespace]] = {} exceptions = [] - warns = [] col_names = {} for row_idx, row in enumerate(sheet.iter_rows(values_only=True)): # Skip non-data rows -- GitLab From fa86a04e8adbd9fcf19e573d309537a7881d0457 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:17:54 +0100 Subject: [PATCH 087/106] MNT: Ignore errors in unused files soon to be deprecated --- src/caosadvancedtools/cfood.py | 15 ++++++++---- src/caosadvancedtools/crawler.py | 27 +++++++++++++--------- src/caosadvancedtools/structure_mapping.py | 5 ++++ 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/caosadvancedtools/cfood.py b/src/caosadvancedtools/cfood.py index 4647a576..9424134e 100644 --- a/src/caosadvancedtools/cfood.py +++ b/src/caosadvancedtools/cfood.py @@ -52,6 +52,11 @@ from linkahead.exceptions import (BadQueryError, EmptyUniqueQueryError, from .datamodel_problems import DataModelProblems from .guard import global_guard as guard +# The pylint warnings triggered in this file are ignored, as this code is +# assumed to be deprecated in the near future. Should this change, they need +# to be reevaluated. + + ENTITIES = {} PROPERTIES = {} RECORDS = {} @@ -183,7 +188,7 @@ class AbstractCFood(object, metaclass=ABCMeta): """ @classmethod - def match_item(cls, item): + def match_item(cls, item): # pylint: disable=unused-argument """ Matches an item found by the crawler against this class. Returns True if the item shall be treated by this class, i.e. if this class matches the item. @@ -215,7 +220,7 @@ class AbstractCFood(object, metaclass=ABCMeta): # TODO looking for should `attach` the files itsself. This would allow to # group them right away and makes it unnecessary to check matches later # again. - def looking_for(self, item): + def looking_for(self, item): # pylint: disable=unused-argument """ returns True if item can be added to this CFood. @@ -351,7 +356,7 @@ class AbstractFileCFood(AbstractCFood): raise NotImplementedError() @classmethod - def match_item(cls, path): + def match_item(cls, path): # pylint: disable=arguments-renamed """ Matches the regular expression of this class against file names Parameters @@ -365,7 +370,7 @@ class AbstractFileCFood(AbstractCFood): # TODO looking for should `attach` the files itsself. This would allow to # group them right away and makes it unnecessary to check matches later # again. - def looking_for(self, crawled_file): + def looking_for(self, crawled_file): # pylint: disable=arguments-renamed """ returns True if crawled_file can be added to this CFood. @@ -744,7 +749,7 @@ def assure_has_property(entity, name, value, to_be_updated=None, def assure_property_is(entity, name, value, datatype=None, to_be_updated=None, - force=False): + force=False): # pylint: disable=unused-argument """ Checks whether `entity` has a Property `name` with the given value. diff --git a/src/caosadvancedtools/crawler.py b/src/caosadvancedtools/crawler.py index ad2536c2..7b66440f 100644 --- a/src/caosadvancedtools/crawler.py +++ b/src/caosadvancedtools/crawler.py @@ -59,6 +59,11 @@ from .serverside.helper import send_mail as main_send_mail from .suppressKnown import SuppressKnown from .utils import create_entity_link +# The pylint warnings triggered in this file are ignored, as this code is +# assumed to be deprecated in the near future. Should this change, they need +# to be reevaluated. + + logger = logging.getLogger(__name__) @@ -133,7 +138,7 @@ def apply_list_of_updates(to_be_updated, update_flags=None, ) logger.debug(traceback.format_exc()) logger.debug(e) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught DataModelProblems.evaluate_exception(e) @@ -222,7 +227,7 @@ class Crawler(object): new_cont = db.Container.from_xml(new) ids = [] tmp = db.Container() - update_incomplete = False + update_incomplete = False # pylint: disable=unused-variable # remove duplicate entities for el in new_cont: if el.id not in ids: @@ -231,13 +236,13 @@ class Crawler(object): else: update_incomplete = True new_cont = tmp - if new_cont[0].version: + if new_cont[0].version: # pylint: disable=no-member valids = db.Container() nonvalids = db.Container() for ent in new_cont: remote_ent = db.Entity(id=ent.id).retrieve() - if ent.version == remote_ent.version: + if ent.version == remote_ent.version: # pylint: disable=no-member valids.append(ent) else: update_incomplete = True @@ -319,10 +324,10 @@ class Crawler(object): logger.debug(e) # TODO: Generally: in which cases should exceptions be raised? When is # errors_occured set to True? The expected behavior must be documented. - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught try: DataModelProblems.evaluate_exception(e) - except Exception: + except Exception: # pylint: disable=broad-exception-caught pass logger.debug("Failed during execution of {}!".format( Cfood.__name__)) @@ -351,10 +356,10 @@ class Crawler(object): logger.info("Cannot access {}. However, it might be needed for" " the correct execution".format(e.filename)) remove_cfoods.append(cfood) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught try: DataModelProblems.evaluate_exception(e) - except Exception: + except Exception: # pylint: disable=broad-exception-caught pass logger.debug("Failed during execution of {}!".format( cfood.__name__)) @@ -444,10 +449,10 @@ class Crawler(object): except DataInconsistencyError as e: logger.debug(traceback.format_exc()) logger.debug(e) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught try: DataModelProblems.evaluate_exception(e) - except Exception: + except Exception: # pylint: disable=broad-exception-caught pass logger.info("Failed during execution of {}!".format( cfood.__class__.__name__)) @@ -682,7 +687,7 @@ carefully and if the changes are ok, click on the following link: guard.safe_insert(missing, unique=False, flags={"force-missing-obligatory": "ignore"}) inserted.append(ent) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught DataModelProblems.evaluate_exception(e) if len(existing) > 0: info = "Identified the following existing entities:\n" diff --git a/src/caosadvancedtools/structure_mapping.py b/src/caosadvancedtools/structure_mapping.py index bf446c2a..aac051a1 100644 --- a/src/caosadvancedtools/structure_mapping.py +++ b/src/caosadvancedtools/structure_mapping.py @@ -25,6 +25,10 @@ from linkahead.common.utils import uuid from .cfood import (assure_has_description, assure_has_parent, assure_property_is) +# The pylint warnings triggered in this file are ignored, as this code is +# assumed to be deprecated in the near future. Should this change, they need +# to be reevaluated. + class EntityMapping(object): """ @@ -42,6 +46,7 @@ class EntityMapping(object): if target._cuid is None: target._cuid = str(uuid()) self.to_existing[str(target._cuid)] = existing + target._cuid = str(uuid()) # pylint: disable=protected-access self.to_target[existing.id] = target -- GitLab From 65ca9fba590339629efb78b5c22ebbee432b5f1c Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:23:58 +0100 Subject: [PATCH 088/106] MNT: Use new Entity getters --- src/caosadvancedtools/models/data_model.py | 2 +- src/caosadvancedtools/structure_mapping.py | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 92afb7eb..6bc91c22 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -296,7 +296,7 @@ class DataModel(dict): if parent.name in visited_parents: continue visited_parents.add(parent.name) - parent_importance = importances.get(parent._flags.get("inheritance"), 999) + parent_importance = importances.get(parent.flags.get("inheritance"), 999) if parent.name in self: deep_parent = self.get_deep(parent.name, # visited_props=visited_props, visited_parents=visited_parents diff --git a/src/caosadvancedtools/structure_mapping.py b/src/caosadvancedtools/structure_mapping.py index aac051a1..aba47058 100644 --- a/src/caosadvancedtools/structure_mapping.py +++ b/src/caosadvancedtools/structure_mapping.py @@ -43,10 +43,9 @@ class EntityMapping(object): self.to_target = {} def add(self, target, existing): - if target._cuid is None: - target._cuid = str(uuid()) - self.to_existing[str(target._cuid)] = existing + if target.cuid is None: target._cuid = str(uuid()) # pylint: disable=protected-access + self.to_existing[str(target.cuid)] = existing self.to_target[existing.id] = target @@ -108,11 +107,11 @@ def update_structure(em, updating: db.Container, target_structure: db.Record): A record which may have references to other records. Must be a DAG. """ - if target_structure._cuid in em.to_existing: + if target_structure.cuid in em.to_existing: update_matched_entity(em, updating, target_structure, - em.to_existing[target_structure._cuid]) + em.to_existing[target_structure.cuid]) for prop in target_structure.get_properties(): if prop.is_reference(server_retrieval=True): @@ -139,8 +138,8 @@ def update_matched_entity(em, updating, target_record, existing_record): # check for remaining property types if isinstance(prop.value, db.Entity): - if prop.value._cuid in em.to_existing: - value = em.to_existing[prop.value._cuid].id + if prop.value.cuid in em.to_existing: + value = em.to_existing[prop.value.cuid].id else: value = prop.value.id else: -- GitLab From b767a8c141de04906c4db5b695ae2e901b303545 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:27:08 +0100 Subject: [PATCH 089/106] MNT: Add 'from e' to all orphaned 'raise's --- src/caosadvancedtools/cfood.py | 4 ++-- src/caosadvancedtools/pandoc_header_tools.py | 2 +- src/caosadvancedtools/table_export.py | 8 ++++---- src/caosadvancedtools/table_importer.py | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/caosadvancedtools/cfood.py b/src/caosadvancedtools/cfood.py index 9424134e..d2e30de5 100644 --- a/src/caosadvancedtools/cfood.py +++ b/src/caosadvancedtools/cfood.py @@ -693,7 +693,7 @@ def assure_has_property(entity, name, value, to_be_updated=None, try: compare_time = datetime.fromisoformat(el.value) - except ValueError: + except ValueError as e: # special case of wrong iso format # time zone tmp = el.value.split("+") @@ -711,7 +711,7 @@ def assure_has_property(entity, name, value, to_be_updated=None, ms = '.' + tmp[1] + '0'*(6-len(tmp[1])) else: raise ValueError( - "invalid millisecond format in {}".format(el.value)) + "invalid millisecond format in {}".format(el.value)) from e else: ms = "" tmp = tmp[0] + ms + tz_str diff --git a/src/caosadvancedtools/pandoc_header_tools.py b/src/caosadvancedtools/pandoc_header_tools.py index a6879565..fec27cdb 100644 --- a/src/caosadvancedtools/pandoc_header_tools.py +++ b/src/caosadvancedtools/pandoc_header_tools.py @@ -141,7 +141,7 @@ it is not at the beginning, it must be preceded by a blank line. try: yaml_part = yaml.load("\n".join(headerlines), Loader=yaml.BaseLoader) except yaml.scanner.ScannerError as e: - raise ParseErrorsInHeader(filename, e) + raise ParseErrorsInHeader(filename, e) from e # except yaml.error.MarkedYAMLError as e: # raise NoValidHeader(filename) if not isinstance(yaml_part, dict): diff --git a/src/caosadvancedtools/table_export.py b/src/caosadvancedtools/table_export.py index 78830b19..1805419b 100644 --- a/src/caosadvancedtools/table_export.py +++ b/src/caosadvancedtools/table_export.py @@ -125,10 +125,10 @@ class BaseTableExporter(object): try: with open(export_dict, encoding="utf-8") as tmp: self.export_dict = json.load(tmp) - except Exception: + except Exception as e: raise ValueError( "export_dict must be either a dictionary" - " or the path to a json file.") + " or the path to a json file.") from e self.record = record self._check_sanity_of_export_dict() self.raise_error_if_missing = raise_error_if_missing @@ -159,7 +159,7 @@ class BaseTableExporter(object): logger.debug(exc) errmssg = "Empty or invalid query '{}' for entry {}".format( q, e) - raise TableExportError(errmssg) + raise TableExportError(errmssg) from exc if val is not None: self.info[e] = val @@ -189,7 +189,7 @@ class BaseTableExporter(object): errmssg += ", nor does record {} have a property of that name".format( self.record.id) errmssg += "." - raise TableExportError(errmssg) + raise TableExportError(errmssg) from exc if self.missing: errmssg = "The following mandatory entries are missing:\n" diff --git a/src/caosadvancedtools/table_importer.py b/src/caosadvancedtools/table_importer.py index b3977b39..b061092e 100755 --- a/src/caosadvancedtools/table_importer.py +++ b/src/caosadvancedtools/table_importer.py @@ -497,7 +497,7 @@ class XLSImporter(TableImporter): str(e)), extra={'identifier': str(filename), 'category': "inconsistency"}) - raise DataInconsistencyError(*e.args) + raise DataInconsistencyError(*e.args) from e if len(xls_file.sheet_names) > 1: # Multiple sheets is the default now. Only show in debug @@ -515,7 +515,7 @@ class XLSImporter(TableImporter): "Cannot parse {}.\n{}".format(filename, e), extra={'identifier': str(filename), 'category': "inconsistency"}) - raise DataInconsistencyError(*e.args) + raise DataInconsistencyError(*e.args) from e df = self.check_dataframe(df, filename) @@ -537,7 +537,7 @@ class CSVImporter(TableImporter): "Cannot parse {}.\n{}".format(filename, ve), extra={'identifier': str(filename), 'category': "inconsistency"}) - raise DataInconsistencyError(*ve.args) + raise DataInconsistencyError(*ve.args) from ve except TypeError as te: # Iterate through the columns and rows to identify # problematic cells with wrong types. @@ -577,7 +577,7 @@ class CSVImporter(TableImporter): for err in error_list: msg += f" * column \"{err[0]}\": Expected \"{err[1]}\" but found \"{err[2]}\".\n" msg += '\n' - raise DataInconsistencyError(msg) + raise DataInconsistencyError(msg) from te df = self.check_dataframe(df, filename) -- GitLab From 4c88ff22717e87856cfb3f195fe88e2a4812fd6a Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:29:42 +0100 Subject: [PATCH 090/106] MNT: Use specific exception types instead of Exception --- src/caosadvancedtools/cfood.py | 3 ++- src/caosadvancedtools/models/parser.py | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/caosadvancedtools/cfood.py b/src/caosadvancedtools/cfood.py index d2e30de5..0eb82632 100644 --- a/src/caosadvancedtools/cfood.py +++ b/src/caosadvancedtools/cfood.py @@ -572,6 +572,7 @@ def assure_parents_are(entity, parents, to_be_updated=None, the new parents and the old ones are discarded. Note that parent matching occurs based on names. + If a parent does not have a name, a ValueError is raised. If the list to_be_updated is supplied, the entity is added to the list in order to indicate, that the entity `entity` should be updated. @@ -586,7 +587,7 @@ def assure_parents_are(entity, parents, to_be_updated=None, for i, e in enumerate(parents): if isinstance(e, db.Entity): if e.name is None: - raise Exception("Entity should have name") + raise ValueError("Entity should have name") else: parents[i] = db.Entity(name=e) diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index b97e507e..52552bd3 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -286,6 +286,12 @@ debug : bool, optional existing_model : dict, optional An existing model to which the created model shall be added. + Raises + ------ + ValueError + If model_dict is not a dict, model_dict["extern"] contains an + unknown entry, or there is an unknown entry in model_dict. + Returns ------- out : data_model.DataModel @@ -320,7 +326,7 @@ debug : bool, optional f"FIND {role} WITH name=\"{name}\"", unique=True) break else: - raise Exception("Did not find {}".format(name)) + raise ValueError("Did not find {}".format(name)) ymlmodel.pop("extern") -- GitLab From b236f79a16567a5a6616cae28a0d61fe13257434 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:35:59 +0100 Subject: [PATCH 091/106] MNT: Ignore pylint error where the current code seems the best solution: - In export_related.py export() we do not care which Exception is raised & need to continue - In import_from_xml.py import_xml() the File from which the _checksum is deleted is created within this method - In table_export.py BaseTableExporter.collect_information(), the method called by _call_find_function is not set, so determining which exceptions may be raised is difficult - table_importer.py TSVImporter.read_file() only exists for backward compatibility --- src/caosadvancedtools/export_related.py | 2 +- src/caosadvancedtools/import_from_xml.py | 2 +- src/caosadvancedtools/table_export.py | 2 +- src/caosadvancedtools/table_importer.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/caosadvancedtools/export_related.py b/src/caosadvancedtools/export_related.py index 2114f388..c7f25c90 100755 --- a/src/caosadvancedtools/export_related.py +++ b/src/caosadvancedtools/export_related.py @@ -118,7 +118,7 @@ def export(cont, directory="."): try: el.download(target) print("Downloaded:", target) - except Exception: + except Exception: # pylint: disable=broad-exception-caught print("Failed download of:", target) invert_ids(cont) diff --git a/src/caosadvancedtools/import_from_xml.py b/src/caosadvancedtools/import_from_xml.py index 540091b0..7eeafa67 100755 --- a/src/caosadvancedtools/import_from_xml.py +++ b/src/caosadvancedtools/import_from_xml.py @@ -63,7 +63,7 @@ def import_xml(filename, rerun=False, interactive=True): for el in cont: if isinstance(el, db.File): - el._checksum = None + el._checksum = None # pylint: disable=protected-access target = os.path.join("downloads", el.path[1:]) if os.path.exists(target): diff --git a/src/caosadvancedtools/table_export.py b/src/caosadvancedtools/table_export.py index 1805419b..32191530 100644 --- a/src/caosadvancedtools/table_export.py +++ b/src/caosadvancedtools/table_export.py @@ -172,7 +172,7 @@ class BaseTableExporter(object): self.info[e] = val else: self._append_missing(e, d) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self._append_missing(e, d) logger.error(exc) # last resort: check if record has e as property: diff --git a/src/caosadvancedtools/table_importer.py b/src/caosadvancedtools/table_importer.py index b061092e..c2cb0250 100755 --- a/src/caosadvancedtools/table_importer.py +++ b/src/caosadvancedtools/table_importer.py @@ -585,5 +585,5 @@ class CSVImporter(TableImporter): class TSVImporter(CSVImporter): - def read_file(self, filename, **kwargs): + def read_file(self, filename, **kwargs): # pylint: disable=arguments-differ return super().read_file(filename, sep="\t", **kwargs) -- GitLab From 3c4042a48585ad4dc4277d73f0ea1e73c1fc0437 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:38:17 +0100 Subject: [PATCH 092/106] MNT: Fix assorted simple pylint errors --- src/caosadvancedtools/loadFiles.py | 4 +--- src/caosadvancedtools/pandoc_header_tools.py | 2 -- src/caosadvancedtools/suppressKnown.py | 1 + src/caosadvancedtools/utils.py | 4 ++-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/caosadvancedtools/loadFiles.py b/src/caosadvancedtools/loadFiles.py index 56d50e4d..f29bdd9e 100755 --- a/src/caosadvancedtools/loadFiles.py +++ b/src/caosadvancedtools/loadFiles.py @@ -375,9 +375,7 @@ exclude is given preference over include. logger.addHandler(logging.StreamHandler(stream=sys.stdout)) logger.setLevel(logging.INFO) - con = db.get_connection() - con.timeout = float(args.timeout) - con._login() + db.configure_connection(timeout=float(args.timeout)) loadpath( path=args.path, diff --git a/src/caosadvancedtools/pandoc_header_tools.py b/src/caosadvancedtools/pandoc_header_tools.py index fec27cdb..a0191e5a 100644 --- a/src/caosadvancedtools/pandoc_header_tools.py +++ b/src/caosadvancedtools/pandoc_header_tools.py @@ -107,12 +107,10 @@ it is not at the beginning, it must be preceded by a blank line. textlines = f.readlines() state = 0 - found_0 = -1 found_1 = -1 found_2 = -1 for i, line in enumerate(textlines): if len(line) == 1 and state in {-1, 0}: - found_0 = i state = 0 continue if line.rstrip() == "---" and state == 0: diff --git a/src/caosadvancedtools/suppressKnown.py b/src/caosadvancedtools/suppressKnown.py index 1b31de7e..aada4ef6 100644 --- a/src/caosadvancedtools/suppressKnown.py +++ b/src/caosadvancedtools/suppressKnown.py @@ -28,6 +28,7 @@ class SuppressKnown(logging.Filter): """ def __init__(self, db_file=None): + super().__init__() if db_file: self.db_file = db_file else: diff --git a/src/caosadvancedtools/utils.py b/src/caosadvancedtools/utils.py index 43ecb3f2..f64900c0 100644 --- a/src/caosadvancedtools/utils.py +++ b/src/caosadvancedtools/utils.py @@ -27,7 +27,7 @@ import logging import os import linkahead as db -from linkahead.exceptions import TransactionError +from linkahead.exceptions import TransactionError, BadQueryError logger = logging.getLogger(__name__) @@ -232,7 +232,7 @@ def find_records_that_reference_ids(referenced_ids, rt="", step_size=50): [str(el) for el in subset])) exps = db.execute_query(q_string) record_ids.update([exp.id for exp in exps]) - except Exception as e: + except (TransactionError, BadQueryError) as e: print(e) index += step_size -- GitLab From 34439a1b2103ff8531b743b6b9796c16feacaa37 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:39:27 +0100 Subject: [PATCH 093/106] MNT: Fix pandoc_header_tools.get_header() name collision --- CHANGELOG.md | 2 ++ src/caosadvancedtools/pandoc_header_tools.py | 37 ++++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a118d98..825358c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `h5` instead of `h5-crawler` - `dev`, `doc`, `test` and `all` are new, they install the dependencies for developing, testing, documentation and everything. +- The `pandoc_header_tools.get_header()` parameter `add_header` has been renamed to `add_header_to_file` + to resolve a name collision. ### Deprecated ### diff --git a/src/caosadvancedtools/pandoc_header_tools.py b/src/caosadvancedtools/pandoc_header_tools.py index a0191e5a..88cdbc19 100644 --- a/src/caosadvancedtools/pandoc_header_tools.py +++ b/src/caosadvancedtools/pandoc_header_tools.py @@ -68,31 +68,30 @@ description: """ -def get_header(filename, add_header=False): - """Open an md file identified by filename and read out the yaml -header. +def get_header(filename, add_header_to_file=False): + """Open an md file identified by filename and read out the yaml header. -filename can also be a folder. In this case folder/README.md will be used for -getting the header. + filename can also be a folder. In this case folder/README.md will be used + for getting the header. -If a header is found a tuple is returned: (first yaml header line index, last+1 -yaml header line index, header) + If a header is found a tuple is returned: (first yaml header line index, + last+1 yaml header line index, header) -Otherwise, if `add_header` is True, a header is added and the function is called -again. + Otherwise, if `add_header_to_file` is True, a header is added and the + function is called again. -The header is normalized in the following way: + The header is normalized in the following way: -- If the value to a key is a string, a list with that string as only element is - returned. + - If the value to a key is a string, a list with that string as only + element is returned. -From https://pandoc.org/MANUAL.html: - -A YAML metadata block is a valid YAML object, delimited by a line of three -hyphens (---) at the top and a line of three hyphens (---) or three dots (...) -at the bottom. A YAML metadata block may occur anywhere in the document, but if -it is not at the beginning, it must be preceded by a blank line. + From https://pandoc.org/MANUAL.html: + A YAML metadata block is a valid YAML object, delimited by a line of three + hyphens (---) at the top and a line of three hyphens (---) or three + dots (...) at the bottom. A YAML metadata block may occur anywhere in the + document, but if it is not at the beginning, it must be preceded by a blank + line. """ if os.path.isdir(filename): @@ -146,7 +145,7 @@ it is not at the beginning, it must be preceded by a blank line. raise NoValidHeader(filename) return (found_1, found_2, clean_header(yaml_part)) - if not add_header: + if not add_header_to_file: raise NoValidHeader(filename) else: print("Adding header in: {fn}".format(fn=filename)) -- GitLab From d4d914d180906cdac85903315acd380e09d09872 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 17:53:48 +0100 Subject: [PATCH 094/106] STY: Fix style errors --- src/caosadvancedtools/table_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/caosadvancedtools/table_converter.py b/src/caosadvancedtools/table_converter.py index 16f27476..19e6d85f 100644 --- a/src/caosadvancedtools/table_converter.py +++ b/src/caosadvancedtools/table_converter.py @@ -112,4 +112,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() -- GitLab From ee8e58919028c07a805621cb4d4ba883c73e708a Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Mon, 16 Dec 2024 18:27:16 +0100 Subject: [PATCH 095/106] DEV: Update 'make lint' fail threshold --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c53f7013..911ea7a7 100644 --- a/Makefile +++ b/Makefile @@ -41,5 +41,5 @@ style: .PHONY: style lint: - pylint --unsafe-load-any-extension=y --fail-under=9.72 -d R,C --ignore=swagger_client src/caosadvancedtools + pylint --unsafe-load-any-extension=y --fail-under=9.99 -d R,C --ignore=swagger_client src/caosadvancedtools .PHONY: lint -- GitLab From 655cb000da2f41c5ce0fa6df999551904e3b0275 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 17 Dec 2024 10:22:16 +0100 Subject: [PATCH 096/106] CI: Remove python 3.8 tests from pipeline --- .gitlab-ci.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5f9d7fe4..f3000856 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -135,21 +135,15 @@ unittest_py311: - python3 -c "import linkahead; print('LinkAhead Version:', linkahead.__version__)" - tox -unittest_py38: +unittest_py39: tags: [docker] stage: unittest - image: python:3.8 + image: python:3.9 script: &python_test_script - pip install --break-system-packages git+https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git@dev - pip install --break-system-packages .[all] - pytest --cov=caosadvancedtools unittests -unittest_py39: - tags: [docker] - stage: unittest - image: python:3.9 - script: *python_test_script - unittest_py310: tags: [docker] stage: unittest -- GitLab From 8429c402362fae8ce7132fe7d62702eddc570ec3 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 17 Dec 2024 10:29:57 +0100 Subject: [PATCH 097/106] MNT: Remove support for Python 3.8 --- CHANGELOG.md | 1 + setup.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a118d98..8b46b11a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Labfolder converter. It was broken anyway, not used by anyone we know and there were no automated tests. For the time being, it lives on in the `f-labfolder-converter` branch, [issue 67](https://gitlab.com/linkahead/linkahead-advanced-user-tools/-/issues/67) is there to coordinate resurrections efforts if someone needs it.. +- Support for Python 3.8 ### Fixed ### diff --git a/setup.py b/setup.py index 732bbf61..c7dd54a9 100755 --- a/setup.py +++ b/setup.py @@ -154,7 +154,7 @@ def setup_package(): long_description_content_type="text/markdown", author='Henrik tom Wörden', author_email='h.tomwoerden@indiscale.com', - python_requires='>=3.8', + python_requires='>=3.9', install_requires=["linkahead>=0.13.1", "jsonref", "jsonschema[format]>=4.4.0", -- GitLab From aacf902d7ff60bd5a56d63dbda44b234fb96c9c9 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 17 Dec 2024 11:50:32 +0100 Subject: [PATCH 098/106] DEV: Remove 'make lint' fail threshold --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 911ea7a7..1ce56f5b 100644 --- a/Makefile +++ b/Makefile @@ -41,5 +41,5 @@ style: .PHONY: style lint: - pylint --unsafe-load-any-extension=y --fail-under=9.99 -d R,C --ignore=swagger_client src/caosadvancedtools + pylint --unsafe-load-any-extension=y -d R,C --ignore=swagger_client src/caosadvancedtools .PHONY: lint -- GitLab From a6d5d230a56455080398811ce1e0433239a14fb9 Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 17 Dec 2024 11:51:12 +0100 Subject: [PATCH 099/106] MNT: Rename list comprehension variable to unconfuse linter --- src/caosadvancedtools/models/data_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 6bc91c22..ce4b7702 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -305,7 +305,7 @@ class DataModel(dict): for prop in deep_parent.properties: importance = importances[deep_parent.get_importance(prop.name)] if (importance <= parent_importance - and prop.name not in [prop.name for prop in entity.properties]): + and prop.name not in [p.name for p in entity.properties]): entity.add_property(prop) else: print(f"Referenced parent \"{parent.name}\" not found in data model.") -- GitLab From 297530b11ea9bd35ba6385360cbda641d15fe7fc Mon Sep 17 00:00:00 2001 From: "i.nueske" <i.nueske@indiscale.com> Date: Tue, 17 Dec 2024 12:03:15 +0100 Subject: [PATCH 100/106] MNT: Ignore pylint errors for which issues have been created. --- src/caosadvancedtools/models/data_model.py | 4 +++- src/caosadvancedtools/models/parser.py | 4 +++- src/caosadvancedtools/table_json_conversion/convert.py | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index ce4b7702..ea864bde 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -251,7 +251,9 @@ class DataModel(dict): for par in entity.get_parents(): if par.name.lower() == valid_e.name.lower(): - par._wrap(valid_e) + # ToDo: Fix https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/140 + # and remove pylint disable, or close and leave + par._wrap(valid_e) # pylint: disable=protected-access def collect_entities(self): """ Collects all entities: explicitly defined RecordTypes and diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 52552bd3..8a18f15c 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -748,7 +748,9 @@ class JsonSchemaParser(Parser): return self._create_model_from_dict(model_dict, top_level_recordtype=top_level_recordtype) - def _create_model_from_dict(self, model_dict: [dict, List[dict]], top_level_recordtype: bool = True): + # ToDo: Fix https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/139 + # and remove pylint disable + def _create_model_from_dict(self, model_dict: [dict, List[dict]], top_level_recordtype: bool = True): # pylint: disable=arguments-renamed """Parse a dictionary and return the Datamodel created from it. The dictionary was typically created from the model definition in a json schema file. diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index b416fc29..e4a8fe5c 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -628,8 +628,10 @@ def _set_in_nested(mydict: dict, path: list, value: Any, prefix: list = [], skip return mydict +# ToDo: Fix https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/138 +# and remove pylint disable def to_dict(xlsx: Union[str, BinaryIO], schema: Union[dict, str, TextIO], - validate: bool = None, strict: bool = False) -> dict: + validate: bool = None, strict: bool = False) -> dict: # pylint: disable=unused-argument """Convert the xlsx contents to a dict, it must follow a schema. Parameters -- GitLab From aa56cc0c12f9b3c188673cd028915afc05ecb3c5 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Fri, 10 Jan 2025 15:43:18 +0100 Subject: [PATCH 101/106] MAINT: simply set the parent ID when syncing the datamodel. --- src/caosadvancedtools/models/data_model.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index ea864bde..4d941993 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -251,9 +251,7 @@ class DataModel(dict): for par in entity.get_parents(): if par.name.lower() == valid_e.name.lower(): - # ToDo: Fix https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/140 - # and remove pylint disable, or close and leave - par._wrap(valid_e) # pylint: disable=protected-access + par.id = valid_e.id def collect_entities(self): """ Collects all entities: explicitly defined RecordTypes and -- GitLab From fef11372cc389f03764d2f33e137118131782394 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Fri, 10 Jan 2025 16:18:15 +0100 Subject: [PATCH 102/106] MAINT: Adding NotImplementedError if validate=True --- src/caosadvancedtools/table_json_conversion/convert.py | 6 +++++- unittests/table_json_conversion/test_read_xlsx.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/caosadvancedtools/table_json_conversion/convert.py b/src/caosadvancedtools/table_json_conversion/convert.py index aabdf827..4b02fa46 100644 --- a/src/caosadvancedtools/table_json_conversion/convert.py +++ b/src/caosadvancedtools/table_json_conversion/convert.py @@ -710,7 +710,7 @@ def _set_in_nested(mydict: dict, path: list, value: Any, prefix: list = [], skip # ToDo: Fix https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/138 # and remove pylint disable def to_dict(xlsx: Union[str, BinaryIO], schema: Union[dict, str, TextIO], - validate: bool = None, strict: bool = False) -> dict: # pylint: disable=unused-argument + validate: Optional[bool] = None, strict: bool = False) -> dict: """Convert the xlsx contents to a dict, it must follow a schema. Parameters @@ -733,5 +733,9 @@ def to_dict(xlsx: Union[str, BinaryIO], schema: Union[dict, str, TextIO], out: dict A dict representing the JSON with the extracted data. """ + if validate: + raise NotImplementedError( + "For input validation implement " + "https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/138") converter = XLSXConverter(xlsx, schema, strict=strict) return converter.to_dict() diff --git a/unittests/table_json_conversion/test_read_xlsx.py b/unittests/table_json_conversion/test_read_xlsx.py index 2a81cdc8..ff32c6b1 100644 --- a/unittests/table_json_conversion/test_read_xlsx.py +++ b/unittests/table_json_conversion/test_read_xlsx.py @@ -43,7 +43,7 @@ def rfp(*pathcomponents): def convert_and_compare(xlsx_file: str, schema_file: str, known_good_file: str, known_good_data: Optional[dict] = None, strict: bool = False, - validate: bool = True) -> dict: + validate: bool = False) -> dict: """Convert an XLSX file and compare to a known result. Exactly one of ``known_good_file`` and ``known_good_data`` should be non-empty. @@ -53,6 +53,8 @@ Returns json: dict The result of the conversion. """ + # FIXME Set default "validate" back to True, after implementation of + # https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/138 result = convert.to_dict(xlsx=xlsx_file, schema=schema_file, validate=validate) if known_good_file: with open(known_good_file, encoding="utf-8") as myfile: -- GitLab From 522ec28e55b390dbdbbebbb1dd139949638571da Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Fri, 10 Jan 2025 16:35:39 +0100 Subject: [PATCH 103/106] STY: Some more small linter and style fixes. --- src/caosadvancedtools/models/data_model.py | 5 +- src/caosadvancedtools/models/parser.py | 2118 ++++++++++---------- unittests/test_json_schema_model_parser.py | 4 +- 3 files changed, 1064 insertions(+), 1063 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 4d941993..beae2d78 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -27,7 +27,7 @@ from copy import deepcopy # actually # [deprecated](https://docs.python.org/3/library/typing.html#typing.List), so # remove this, when we drop support for old Python versions. -from typing import List +from typing import List, Optional import linkahead as db import linkahead.common.models as models @@ -267,7 +267,8 @@ class DataModel(dict): return list(all_ents.values()) - def get_deep(self, name: str, visited_props: dict = None, visited_parents: set = None): + def get_deep(self, name: str, visited_props: Optional[dict] = None, + visited_parents: Optional[set] = None): """Attempt to resolve references for the given ``name``. The returned entity has all the properties it inherits from its ancestry and all properties diff --git a/src/caosadvancedtools/models/parser.py b/src/caosadvancedtools/models/parser.py index 8a18f15c..40734617 100644 --- a/src/caosadvancedtools/models/parser.py +++ b/src/caosadvancedtools/models/parser.py @@ -1,1059 +1,1059 @@ -# This file is a part of the LinkAhead project. -# -# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> -# Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> -# Copyright (C) 2023 Daniel Hornung <d.hornung@indiscale.com> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. - -""" -This module (and script) provides methods to read a DataModel from a YAML file. - -If a file name is passed to parse_model_from_yaml it is parsed and a DataModel -is created. The yaml file needs to be structured in a certain way which will be -described in the following. - -The file should only contain a dictionary. The keys are the names of -RecordTypes or Properties. The values are again dictionaries describing the -entities. This information can be defined via the keys listed in KEYWORDS. -Notably, properties can be given in a dictionary under the xxxx_properties keys -and will be added with the respective importance. These properties can be -RecordTypes or Properties and can be defined right there. -Every Property or RecordType only needs to be defined once anywhere. When it is -not defined, simply the name can be supplied with no value. -Parents can be provided under the 'inherit_from_xxxx' keywords. The value needs -to be a list with the names. Here, NO NEW entities can be defined. -""" -import argparse -import sys -from typing import List, Optional - -import jsonref -import jsonschema -import linkahead as db -import yaml -from linkahead.common.datatype import get_list_datatype - -from .data_model import LINKAHEAD_INTERNAL_PROPERTIES, DataModel - -# Keywords which are allowed in data model descriptions. -KEYWORDS = ["importance", - "datatype", # for example TEXT, INTEGER or REFERENCE - "unit", - "description", - "recommended_properties", - "obligatory_properties", - "suggested_properties", - "inherit_from_recommended", - "inherit_from_suggested", - "inherit_from_obligatory", - "role", - "value", - ] - -# TODO: check whether it's really ignored -# These KEYWORDS are not forbidden as properties, but merely ignored. -KEYWORDS_IGNORED = [ - "unit", -] - -JSON_SCHEMA_ATOMIC_TYPES = [ - "string", - "boolean", - "integer", - "number", - "null" -] - - -# Taken from https://stackoverflow.com/a/53647080, CC-BY-SA, 2018 by -# https://stackoverflow.com/users/2572431/augurar - - -class SafeLineLoader(yaml.SafeLoader): - """Load a line and keep meta-information. - - Note that this will add a `__line__` element to all the dicts. - """ - - def construct_mapping(self, node, deep=False): - """Overwritung the parent method.""" - mapping = super().construct_mapping(node, deep=deep) - # Add 1 so line numbering starts at 1 - mapping['__line__'] = node.start_mark.line + 1 - - return mapping -# End of https://stackoverflow.com/a/53647080 - - -class TwiceDefinedException(Exception): - def __init__(self, name): - super().__init__("The Entity '{}' was defined multiple times!".format( - name)) - - -class YamlDefinitionError(RuntimeError): - def __init__(self, line, template=None): - if not template: - template = "Error in YAML definition in line {}." - super().__init__(template.format(line)) - - -class JsonSchemaDefinitionError(RuntimeError): - # @author Florian Spreckelsen - # @date 2022-02-17 - # @review Daniel Hornung 2022-02-18 - def __init__(self, msg): - super().__init__(msg) - - -def parse_model_from_yaml(filename, existing_model: Optional[dict] = None, debug: bool = False): - """Parse a data model from a YAML file. - -This is a convenience function if the Parser object is not needed, it calls -``Parser.parse_model_from_yaml(...)`` internally. - - -Parameters ----------- - -existing_model : dict, optional - An existing model to which the created model shall be added. - -debug : bool, optional - If True, turn on miscellaneous debugging. Default is False. - """ - parser = Parser(debug=debug) - - return parser.parse_model_from_yaml(filename, existing_model=existing_model) - - -def parse_model_from_string(string, existing_model: Optional[dict] = None, debug: bool = False): - """Parse a data model from a YAML string - -This is a convenience function if the Parser object is not needed, it calls -``Parser.parse_model_from_string(...)`` internally. - -Parameters ----------- - -existing_model : dict, optional - An existing model to which the created model shall be added. - -debug : bool, optional - If True, turn on miscellaneous debugging. Default is False. - """ - parser = Parser(debug=debug) - - return parser.parse_model_from_string(string, existing_model=existing_model) - - -def parse_model_from_json_schema( - filename: str, - top_level_recordtype: bool = True, - types_for_missing_array_items: dict = None, - ignore_unspecified_array_items: bool = False, - existing_model: Optional[dict] = None -): - """Return a datamodel parsed from a json schema definition. - - Parameters - ---------- - - filename : str - The path of the json schema file that is to be parsed - - top_level_recordtype : bool, optional - Whether there is a record type defined at the top level of the - schema. Default is true. - - types_for_missing_array_items : dict, optional - dictionary containing fall-back types for json entries with `type: - array` but without `items` specification. Default is an empty dict. - - ignore_unspecified_array_items : bool, optional - Whether to ignore `type: array` entries the type of which is not - specified by their `items` property or given in - `types_for_missing_array_items`. An error is raised if they are not - ignored. Default is False. - - existing_model : dict, optional - An existing model to which the created model shall be added. Not implemented yet. - - Returns - ------- - - out : Datamodel - The datamodel generated from the input schema which then can be used for - synchronizing with LinkAhead. - - Note - ---- - This is an experimental feature, see ``JsonSchemaParser`` for information - about the limitations of the current implementation. - - """ - if types_for_missing_array_items is None: - types_for_missing_array_items = {} - - if existing_model is not None: - raise NotImplementedError("Adding to an existing model is not implemented yet.") - - # @author Florian Spreckelsen - # @date 2022-02-17 - # @review Timm Fitschen 2023-05-25 - parser = JsonSchemaParser(types_for_missing_array_items, ignore_unspecified_array_items) - - return parser.parse_model_from_json_schema(filename, top_level_recordtype) - - -class Parser(object): - def __init__(self, debug: bool = False): - """Initialize an empty parser object and initialize the dictionary of entities and the list of - treated elements. - -Parameters ----------- - -debug : bool, optional - If True, turn on miscellaneous debugging. Default is False. - - """ - self.model = {} - self.treated = [] - self.debug = debug - - def parse_model_from_yaml(self, filename, existing_model: Optional[dict] = None): - """Create and return a data model from the given file. - - Parameters - ---------- - filename : str - The path to the YAML file. - - existing_model : dict, optional - An existing model to which the created model shall be added. - - Returns - ------- - out : data_model.DataModel - The created DataModel - """ - with open(filename, 'r', encoding="utf-8") as outfile: - ymlmodel = yaml.load(outfile, Loader=SafeLineLoader) - - return self._create_model_from_dict(ymlmodel, existing_model=existing_model) - - def parse_model_from_string(self, string, existing_model: Optional[dict] = None): - """Create and return a data model from the given YAML string. - - Parameters - ---------- - string : str - The YAML string. - - existing_model : dict, optional - An existing model to which the created model shall be added. - - Returns - ------- - out : data_model.DataModel - The created DataModel - """ - ymlmodel = yaml.load(string, Loader=SafeLineLoader) - - return self._create_model_from_dict(ymlmodel, existing_model=existing_model) - - def _create_model_from_dict(self, ymlmodel, existing_model: Optional[dict] = None): - """Create and return a data model out of the YAML dict `ymlmodel`. - - Parameters - ---------- - ymlmodel : dict - The dictionary parsed from a YAML file. - - existing_model : dict, optional - An existing model to which the created model shall be added. - - Raises - ------ - ValueError - If model_dict is not a dict, model_dict["extern"] contains an - unknown entry, or there is an unknown entry in model_dict. - - Returns - ------- - out : data_model.DataModel - The created DataModel - """ - - if not isinstance(ymlmodel, dict): - raise ValueError("Yaml file should only contain one dictionary!") - - if existing_model is not None: - self.model.update(existing_model) - - # Extern keyword: - # The extern keyword can be used to include Properties and RecordTypes - # from existing LinkAhead datamodels into the current model. - # Any name included in the list specified by the extern keyword - # will be used in queries to retrieve a property or (if no property exists) - # a record type with the name of the element. - # The retrieved entity will be added to the model. - # If no entity with that name is found an exception is raised. - - if "extern" not in ymlmodel: - ymlmodel["extern"] = [] - - for name in ymlmodel["extern"]: - if name in LINKAHEAD_INTERNAL_PROPERTIES: - self.model[name] = db.Property(name=name).retrieve() - continue - for role in ("Property", "RecordType", "Record", "File"): - if db.execute_query("COUNT {} \"{}\"".format(role, name)) > 0: - self.model[name] = db.execute_query( - f"FIND {role} WITH name=\"{name}\"", unique=True) - break - else: - raise ValueError("Did not find {}".format(name)) - - ymlmodel.pop("extern") - - # add all names to ymlmodel; initialize properties - - for name, entity in ymlmodel.items(): - self._add_entity_to_model(name, entity) - # initialize recordtypes - self._set_recordtypes() - self._check_and_convert_datatypes() - - for name, entity in ymlmodel.items(): - try: - self._treat_entity(name, entity, line=ymlmodel["__line__"]) - except ValueError as err: - err_str = err.args[0].replace("invalid keyword:", - f"invalid keyword in line {entity['__line__']}:", 1) - raise ValueError(err_str, *err.args[1:]) from err - -# Update properties that are part of record types: -# e.g. add their datatypes, units etc.. -# Otherwise comparison of existing models and the parsed model become difficult. - for name, ent in self.model.items(): - if not isinstance(ent, db.RecordType): - continue - props = ent.get_properties() - for prop in props: - if prop.name in self.model: - model_prop = self.model[prop.name] - # The information must be missing, we don't want to overwrite it accidentally: - if prop.datatype is None: - if isinstance(model_prop, db.RecordType): - prop.datatype = model_prop.name - else: - prop.datatype = model_prop.datatype - # TODO: Data type overwrite is allowed here (because - # of lists), but this might change in the future. - # elif prop.datatype != model_prop.datatype: - # raise RuntimeError("datatype must not be set, here. This is probably a bug.") - if prop.unit is None: - # No unit for plain reference properties - if not isinstance(model_prop, db.RecordType): - prop.unit = model_prop.unit - if prop.description is None: - prop.description = model_prop.description - - return DataModel(self.model.values()) - - @staticmethod - def _stringify(name, context=None): - """Make a string out of `name`. - - Warnings are emitted for difficult values of `name`. - - Parameters - ---------- - name : - The value to be converted to a string. - - context : obj - Will be printed in the case of warnings. - - Returns - ------- - out : str - If `name` was a string, return it. Else return str(`name`). - """ - - if name is None: - print("WARNING: Name of this context is None: {}".format(context), - file=sys.stderr) - - if not isinstance(name, str): - name = str(name) - - return name - - def _add_entity_to_model(self, name, definition): - """ adds names of Properties and RecordTypes to the model dictionary - - Properties are also initialized. - - name is the key of the yaml element and definition the value. - """ - - if name == "__line__": - return - name = self._stringify(name) - - if name not in self.model: - self.model[name] = None - - if definition is None: - return - - if (self.model[name] is None and isinstance(definition, dict) - # is it a property - and "datatype" in definition - # but not simply an RT of the model - and not (get_list_datatype(definition["datatype"]) == name and - get_list_datatype(definition["datatype"]) in self.model)): - - # and create the new property - self.model[name] = db.Property(name=name, - datatype=definition["datatype"]) - elif (self.model[name] is None and isinstance(definition, dict) - and "role" in definition): - if definition["role"] == "RecordType": - self.model[name] = db.RecordType(name=name) - elif definition["role"] == "Record": - self.model[name] = db.Record(name=name) - elif definition["role"] == "File": - # TODO(fspreck) Implement files at some later point in time - raise NotImplementedError( - "The definition of file objects is not yet implemented.") - - # self.model[name] = db.File(name=name) - elif definition["role"] == "Property": - self.model[name] = db.Property(name=name) - else: - raise RuntimeError("Unknown role {} in definition of entity.".format( - definition["role"])) - - # for setting values of properties directly: - if not isinstance(definition, dict): - return - - # add other definitions recursively - for prop_type in ["recommended_properties", - "suggested_properties", "obligatory_properties"]: - - if prop_type in definition: - # Empty property mapping should be allowed. - - if definition[prop_type] is None: - definition[prop_type] = {} - try: - for n, e in definition[prop_type].items(): - if n == "__line__": - continue - self._add_entity_to_model(n, e) - except AttributeError as ate: - if ate.args[0].endswith("'items'"): - line = definition["__line__"] - - if isinstance(definition[prop_type], list): - line = definition[prop_type][0]["__line__"] - raise YamlDefinitionError(line) from None - raise - - if self.debug and self.model[name] is not None: - self.model[name].__line__ = definition["__line__"] - - def _add_to_recordtype(self, ent_name, props, importance): - """Add properties to a RecordType. - - Parameters - ---------- - ent_name : str - The name of the entity to which the properties shall be added. - - props : dict [str -> dict or :doc:`Entity`] - The properties, indexed by their names. Properties may be given as :doc:`Entity` objects - or as dictionaries. - - importance - The importance as used in :doc:`Entity.add_property`. - - Returns - ------- - None - - """ - - for n, e in props.items(): - - if n in KEYWORDS: - if n in KEYWORDS_IGNORED: - continue - raise YamlDefinitionError("Unexpected keyword in line {}: {}".format( - props["__line__"], n)) - - if n == "__line__": - continue - n = self._stringify(n) - - if isinstance(e, dict): - if "datatype" in e and get_list_datatype(e["datatype"]) is not None: - # Reuse the existing datatype for lists. - datatype = db.LIST(get_list_datatype(e["datatype"])) - else: - # Ignore a possible e["datatype"] here if it's not a list - # since it has been treated in the definition of the - # property (entity) already - datatype = None - if "value" in e: - value = e["value"] - else: - value = None - - else: - value = e - datatype = None - - self.model[ent_name].add_property(name=n, - value=value, - importance=importance, - datatype=datatype) - - def _inherit(self, name, prop, inheritance): - if not isinstance(prop, list): - if isinstance(prop, str): - raise YamlDefinitionError( - f"Parents must be a list but is given as string: {name} > {prop}") - raise YamlDefinitionError("Parents must be a list, error in line {}".format( - prop["__line__"])) - - for pname in prop: - if not isinstance(pname, str): - raise ValueError("Only provide the names of parents.") - self.model[name].add_parent(name=pname, inheritance=inheritance) - - def _treat_entity(self, name, definition, line=None): - """Parse the definition and the information to the entity.""" - - if name == "__line__": - return - name = self._stringify(name) - - try: - if definition is None: - return - - # for setting values of properties directly: - if not isinstance(definition, dict): - return - - # These definition items must be handled even for list props. - for prop_name, prop in definition.items(): - if prop_name == "description": - self.model[name].description = prop - - # For lists, everything else is not needed at this level. - if ("datatype" in definition and definition["datatype"].startswith("LIST")): - return - - if name in self.treated: - raise TwiceDefinedException(name) - - # for reducing a little bit of code duplication: - importance_dict = { - "recommended_properties": db.RECOMMENDED, - "obligatory_properties": db.OBLIGATORY, - "suggested_properties": db.SUGGESTED - } - - for prop_name, prop in definition.items(): - if prop_name == "__line__": - continue - line = definition["__line__"] - - if prop_name == "unit": - self.model[name].unit = prop - - elif prop_name == "value": - self.model[name].value = prop - - elif prop_name == "description": - # Handled above - continue - - elif prop_name in importance_dict: - for imp_name, imp_val in importance_dict.items(): - if prop_name == imp_name: - self._add_to_recordtype( - name, prop, importance=imp_val) - - for n, e in prop.items(): - self._treat_entity(n, e) - - # datatype is already set - elif prop_name == "datatype": - continue - - # role has already been used - elif prop_name == "role": - continue - - elif prop_name == "inherit_from_obligatory": - self._inherit(name, prop, db.OBLIGATORY) - elif prop_name == "inherit_from_recommended": - self._inherit(name, prop, db.RECOMMENDED) - elif prop_name == "inherit_from_suggested": - self._inherit(name, prop, db.SUGGESTED) - - else: - raise ValueError("invalid keyword: {}".format(prop_name)) - except AttributeError as ate: - if ate.args[0].endswith("'items'"): - raise YamlDefinitionError(line) from None - except Exception as e: - print("Error in treating: "+name) - raise e - self.treated.append(name) - - def _check_and_convert_datatypes(self): - """ checks if datatype is valid. - datatype of properties is simply initialized with string. Here, we - iterate over properties and check whether it is a base datatype of a - name that was defined in the model (or extern part) - - the string representations are replaced with linkahead objects - - """ - - for _, value in self.model.items(): - - if isinstance(value, db.Property): - dtype = value.datatype - is_list = False - - if get_list_datatype(dtype) is not None: - dtype = get_list_datatype(dtype) - is_list = True - - dtype_name = dtype - if not isinstance(dtype_name, str): - dtype_name = dtype.name - - if dtype_name in self.model: - if is_list: - value.datatype = db.LIST(self.model[dtype_name]) - else: - value.datatype = self.model[dtype_name] - - continue - - if dtype in [db.DOUBLE, - db.REFERENCE, - db.TEXT, - db.DATETIME, - db.INTEGER, - db.FILE, - db.BOOLEAN]: - - if is_list: - value.datatype = db.LIST(db.__getattribute__( # pylint: disable=no-member - dtype)) - else: - value.datatype = db.__getattribute__( # pylint: disable=no-member - dtype) - - continue - - raise ValueError("Property {} has an unknown datatype: {}".format( - value.name, dtype_name)) - - def _set_recordtypes(self): - """ properties are defined in first iteration; set remaining as RTs """ - - for key, value in self.model.items(): - if value is None: - self.model[key] = db.RecordType(name=key) - - -class JsonSchemaParser(Parser): - """Extends the yaml parser to read in datamodels defined in a json schema. - - **EXPERIMENTAL:** While this class can already be used to create data models - from basic json schemas, there are the following limitations and missing - features: - - * Due to limitations of json-schema itself, we currently do not support - inheritance in the imported data models - * The same goes for suggested properties of RecordTypes - * Already defined RecordTypes and (scalar) Properties can't be re-used as - list properties - * Reference properties that are different from the referenced RT. (Although - this is possible for list of references) - * Values - * Roles - * The extern keyword from the yaml parser - - """ - # @author Florian Spreckelsen - # @date 2022-02-17 - # @review Timm Fitschen 2023-05-25 - - def __init__(self, types_for_missing_array_items=None, - ignore_unspecified_array_items=False): - super().__init__() - if types_for_missing_array_items is None: - types_for_missing_array_items = {} - self.types_for_missing_array_items = types_for_missing_array_items - self.ignore_unspecified_array_items = ignore_unspecified_array_items - - def parse_model_from_json_schema(self, filename: str, top_level_recordtype: bool = True): - """Return a datamodel created from the definition in the json schema in - `filename`. - - Parameters - ---------- - filename : str - The path to the json-schema file containing the datamodel definition - top_level_recordtype : bool, optional - Whether there is a record type defined at the top level of the - schema. Default is true. - - Returns - ------- - out : data_model.DataModel - The created DataModel - """ - # @author Florian Spreckelsen - # @date 2022-02-17 - # @review Timm Fitschen 2023-05-25 - with open(filename, 'r', encoding="utf-8") as schema_file: - model_dict = jsonref.load(schema_file) - - return self._create_model_from_dict(model_dict, top_level_recordtype=top_level_recordtype) - - # ToDo: Fix https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/139 - # and remove pylint disable - def _create_model_from_dict(self, model_dict: [dict, List[dict]], top_level_recordtype: bool = True): # pylint: disable=arguments-renamed - """Parse a dictionary and return the Datamodel created from it. - - The dictionary was typically created from the model definition in a json schema file. - - Parameters - ---------- - model_dict : dict or list[dict] - One or several dictionaries read in from a json-schema file - top_level_recordtype : bool, optional - Whether there is a record type defined at the top level of the - schema. Default is true. - - Returns - ------- - our : data_model.DataModel - The datamodel defined in `model_dict` - """ - # @review Timm Fitschen 2023-05-25 - if isinstance(model_dict, dict): - model_dict = [model_dict] - - for ii, elt in enumerate(model_dict): - try: - jsonschema.Draft202012Validator.check_schema(elt) - except jsonschema.SchemaError as err: - key = elt["title"] if "title" in elt else f"element {ii}" - raise JsonSchemaDefinitionError( - f"Json Schema error in {key}:\n{str(err)}") from err - - if top_level_recordtype: - if "title" not in elt: - raise JsonSchemaDefinitionError( - f"Object {ii+1} is lacking the `title` key word") - if "type" not in elt: - raise JsonSchemaDefinitionError( - f"Object {ii+1} is lacking the `type` key word") - # Check if this is a valid Json Schema - name = self._stringify(elt["title"], context=elt) - self._treat_element(elt, name) - elif "properties" in elt or "patternProperties" in elt: - # No top-level type but there are entities - if "properties" in elt: - for key, prop in elt["properties"].items(): - name = self._get_name_from_property(key, prop) - self._treat_element(prop, name) - if "patternProperties" in elt: - # See also treatment in ``_treat_record_type``. Since here, - # there is no top-level RT we use the prefix `__Pattern`, - # i.e., the resulting Record Types will be called - # `__PatternElement`. - self._treat_pattern_properties( - elt["patternProperties"], name_prefix="__Pattern") - else: - # Neither RecordType itself, nor further properties in schema, - # so nothing to do here. Maybe add something in the future. - continue - - return DataModel(self.model.values()) - - def _get_name_from_property(self, key: str, prop: dict): - # @review Timm Fitschen 2023-05-25 - if "title" in prop: - name = self._stringify(prop["title"]) - else: - name = self._stringify(key) - - return name - - def _get_atomic_datatype(self, elt): - # @review Timm Fitschen 2023-05-25 - if elt["type"] == "string": - if "format" in elt and elt["format"] in ["date", "date-time"]: - return db.DATETIME - else: - return db.TEXT - elif elt["type"] == "integer": - return db.INTEGER - elif elt["type"] == "number": - return db.DOUBLE - elif elt["type"] == "boolean": - return db.BOOLEAN - elif elt["type"] == "null": - # This could be any datatype since a valid json will never have a - # value in a null property. We use TEXT for convenience. - return db.TEXT - else: - raise JsonSchemaDefinitionError(f"Unkown atomic type in {elt}.") - - def _treat_element(self, elt: dict, name: str): - # @review Timm Fitschen 2023-05-25 - force_list = False - if name in self.model: - return self.model[name], force_list - if "type" not in elt: - # Each element must have a specific type - raise JsonSchemaDefinitionError( - f"`type` is missing in element {name}.") - if name == "name": - # This is identified with the LinkAhead name property as long as the - # type is correct. - if not elt["type"] == "string" and "string" not in elt["type"]: - raise JsonSchemaDefinitionError( - "The 'name' property must be string-typed, otherwise it cannot " - "be identified with LinkAhead's name property." - ) - return None, force_list - # LinkAhead suports null for all types, so in the very special case of - # `"type": ["null", "<other_type>"]`, only consider the other type: - if isinstance(elt["type"], list) and len(elt["type"]) == 2 and "null" in elt["type"]: - elt["type"].remove("null") - elt["type"] = elt["type"][0] - if "enum" in elt: - ent = self._treat_enum(elt, name) - elif elt["type"] in JSON_SCHEMA_ATOMIC_TYPES: - ent = db.Property( - name=name, datatype=self._get_atomic_datatype(elt)) - elif elt["type"] == "object": - ent = self._treat_record_type(elt, name) - elif elt["type"] == "array": - ent, force_list = self._treat_list(elt, name) - else: - raise NotImplementedError( - f"Cannot parse items of type '{elt['type']}' (yet).") - if "description" in elt and ent.description is None: - # There is a description and it hasn't been set by another - # treat_something function - ent.description = elt["description"] - - if ent is not None: - self.model[name] = ent - return ent, force_list - - def _treat_record_type(self, elt: dict, name: str): - # @review Timm Fitschen 2023-05-25 - rt = db.RecordType(name=name) - if "required" in elt: - required = elt["required"] - else: - required = [] - if "properties" in elt: - for key, prop in elt["properties"].items(): - name = self._get_name_from_property(key, prop) - prop_ent, force_list = self._treat_element(prop, name) - if prop_ent is None: - # Nothing to be appended since the property has to be - # treated specially. - continue - importance = db.OBLIGATORY if key in required else db.RECOMMENDED - if not force_list: - rt.add_property(prop_ent, importance=importance) - else: - # Special case of rt used as a list property - rt.add_property(prop_ent, importance=importance, - datatype=db.LIST(prop_ent)) - - if "patternProperties" in elt: - - pattern_property_rts = self._treat_pattern_properties( - elt["patternProperties"], name_prefix=name) - for ppr in pattern_property_rts: - # add reference to pattern property type. These can never be - # obligatory since pattern properties cannot be required in the - # original schema (since their actual names are not known a - # priori). - rt.add_property(ppr) - - if "description" in elt: - rt.description = elt["description"] - return rt - - def _treat_enum(self, elt: dict, name: str): - # @review Timm Fitschen 2022-02-30 - if "type" in elt and elt["type"] == "integer": - raise NotImplementedError( - "Integer-enums are not allowd until " - "https://gitlab.indiscale.com/caosdb/src/caosdb-server/-/issues/224 " - "has been fixed." - ) - rt = db.RecordType(name=name) - for enum_elt in elt["enum"]: - rec = db.Record(name=self._stringify(enum_elt)) - rec.add_parent(rt) - self.model[enum_elt] = rec - - return rt - - def _treat_list(self, elt: dict, name: str): - # @review Timm Fitschen 2023-05-25 - - if "items" not in elt and name not in self.types_for_missing_array_items: - if self.ignore_unspecified_array_items: - return None, False - raise JsonSchemaDefinitionError( - f"The definition of the list items is missing in {elt}.") - if "items" in elt: - items = elt["items"] - if "enum" in items: - return self._treat_enum(items, name), True - if items["type"] in JSON_SCHEMA_ATOMIC_TYPES: - datatype = db.LIST(self._get_atomic_datatype(items)) - return db.Property(name=name, datatype=datatype), False - if items["type"] == "object": - if "title" not in items or self._stringify(items["title"]) == name: - # Property is RecordType - return self._treat_record_type(items, name), True - else: - # List property will be an entity of its own with a name - # different from the referenced RT - ref_rt = self._treat_record_type( - items, self._stringify(items["title"])) - self.model[ref_rt.name] = ref_rt - return db.Property(name=name, datatype=db.LIST(ref_rt)), False - else: - # Use predefined type: - datatype = db.LIST(self.types_for_missing_array_items[name]) - return db.Property(name=name, datatype=datatype), False - - def _get_pattern_prop(self): - # @review Timm Fitschen 2023-05-25 - if "__pattern_property_pattern_property" in self.model: - return self.model["__pattern_property_pattern_property"] - pp = db.Property(name="__matched_pattern", datatype=db.TEXT) - self.model["__pattern_property_pattern_property"] = pp - return pp - - def _treat_pattern_properties(self, pattern_elements, name_prefix=""): - """Special Treatment for pattern properties: A RecordType is created for - each pattern property. In case of a `type: object` PatternProperty, the - remaining properties of the JSON entry are appended to the new - RecordType; in case of an atomic type PatternProperty, a single value - Property is added to the RecordType. - - Raises - ------ - NotImplementedError - In case of patternProperties with non-object, non-atomic type, e.g., - array. - - """ - # @review Timm Fitschen 2023-05-25 - num_patterns = len(pattern_elements) - pattern_prop = self._get_pattern_prop() - returns = [] - for ii, (key, element) in enumerate(pattern_elements.items()): - if "title" not in element: - name_suffix = f"_{ii+1}" if num_patterns > 1 else "" - name = name_prefix + "Entry" + name_suffix - else: - name = element["title"] - if element["type"] == "object": - # simple, is already an object, so can be treated like any other - # record type. - pattern_type = self._treat_record_type(element, name) - elif element["type"] in JSON_SCHEMA_ATOMIC_TYPES: - # create a property that stores the actual value of the pattern - # property. - propname = f"{name}_value" - prop = db.Property(name=propname, datatype=self._get_atomic_datatype(element)) - self.model[propname] = prop - pattern_type = db.RecordType(name=name) - pattern_type.add_property(prop) - else: - raise NotImplementedError( - "Pattern properties are currently only supported for types " + - ", ".join(JSON_SCHEMA_ATOMIC_TYPES) + ", and object.") - - # Add pattern property and description - pattern_type.add_property(pattern_prop, importance=db.OBLIGATORY) - if pattern_type.description: - pattern_type.description += f"\n\npattern: {key}" - else: - pattern_type.description = f"pattern: {key}" - - self.model[name] = pattern_type - returns.append(pattern_type) - - return returns - - -def main(): - parser = argparse.ArgumentParser(description=__doc__, - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument("data_model", - help="Path name of the data model file (yaml or json) to be used.") - parser.add_argument("--sync", action="store_true", - help="Whether or not to sync the data model with the server.") - parser.add_argument("--noquestion", action="store_true", - help="Whether or not to ask questions during synchronization.") - parser.add_argument("--print", action="store_true", - help="Whether or not to print the data model.") - - args = parser.parse_args() - if args.data_model.endswith(".json"): - model = parse_model_from_json_schema(args.data_model) - elif args.data_model.endswith(".yml") or args.data_model.endswith(".yaml"): - model = parse_model_from_yaml(args.data_model) - else: - raise RuntimeError(f"Unknown file ending of data model: {args.data_model}") - if args.print: - print(model) - if args.sync: - model.sync_data_model(noquestion=args.noquestion) - - -if __name__ == "__main__": - main() +# This file is a part of the LinkAhead project. +# +# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com> +# Copyright (C) 2023 Daniel Hornung <d.hornung@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +""" +This module (and script) provides methods to read a DataModel from a YAML file. + +If a file name is passed to parse_model_from_yaml it is parsed and a DataModel +is created. The yaml file needs to be structured in a certain way which will be +described in the following. + +The file should only contain a dictionary. The keys are the names of +RecordTypes or Properties. The values are again dictionaries describing the +entities. This information can be defined via the keys listed in KEYWORDS. +Notably, properties can be given in a dictionary under the xxxx_properties keys +and will be added with the respective importance. These properties can be +RecordTypes or Properties and can be defined right there. +Every Property or RecordType only needs to be defined once anywhere. When it is +not defined, simply the name can be supplied with no value. +Parents can be provided under the 'inherit_from_xxxx' keywords. The value needs +to be a list with the names. Here, NO NEW entities can be defined. +""" +import argparse +import sys +from typing import List, Optional, Union + +import jsonref +import jsonschema +import linkahead as db +import yaml +from linkahead.common.datatype import get_list_datatype + +from .data_model import LINKAHEAD_INTERNAL_PROPERTIES, DataModel + +# Keywords which are allowed in data model descriptions. +KEYWORDS = ["importance", + "datatype", # for example TEXT, INTEGER or REFERENCE + "unit", + "description", + "recommended_properties", + "obligatory_properties", + "suggested_properties", + "inherit_from_recommended", + "inherit_from_suggested", + "inherit_from_obligatory", + "role", + "value", + ] + +# TODO: check whether it's really ignored +# These KEYWORDS are not forbidden as properties, but merely ignored. +KEYWORDS_IGNORED = [ + "unit", +] + +JSON_SCHEMA_ATOMIC_TYPES = [ + "string", + "boolean", + "integer", + "number", + "null" +] + + +# Taken from https://stackoverflow.com/a/53647080, CC-BY-SA, 2018 by +# https://stackoverflow.com/users/2572431/augurar + + +class SafeLineLoader(yaml.SafeLoader): + """Load a line and keep meta-information. + + Note that this will add a `__line__` element to all the dicts. + """ + + def construct_mapping(self, node, deep=False): + """Overwritung the parent method.""" + mapping = super().construct_mapping(node, deep=deep) + # Add 1 so line numbering starts at 1 + mapping['__line__'] = node.start_mark.line + 1 + + return mapping +# End of https://stackoverflow.com/a/53647080 + + +class TwiceDefinedException(Exception): + def __init__(self, name): + super().__init__("The Entity '{}' was defined multiple times!".format( + name)) + + +class YamlDefinitionError(RuntimeError): + def __init__(self, line, template=None): + if not template: + template = "Error in YAML definition in line {}." + super().__init__(template.format(line)) + + +class JsonSchemaDefinitionError(RuntimeError): + # @author Florian Spreckelsen + # @date 2022-02-17 + # @review Daniel Hornung 2022-02-18 + def __init__(self, msg): + super().__init__(msg) + + +def parse_model_from_yaml(filename, existing_model: Optional[dict] = None, debug: bool = False): + """Parse a data model from a YAML file. + +This is a convenience function if the Parser object is not needed, it calls +``Parser.parse_model_from_yaml(...)`` internally. + + +Parameters +---------- + +existing_model : dict, optional + An existing model to which the created model shall be added. + +debug : bool, optional + If True, turn on miscellaneous debugging. Default is False. + """ + parser = Parser(debug=debug) + + return parser.parse_model_from_yaml(filename, existing_model=existing_model) + + +def parse_model_from_string(string, existing_model: Optional[dict] = None, debug: bool = False): + """Parse a data model from a YAML string + +This is a convenience function if the Parser object is not needed, it calls +``Parser.parse_model_from_string(...)`` internally. + +Parameters +---------- + +existing_model : dict, optional + An existing model to which the created model shall be added. + +debug : bool, optional + If True, turn on miscellaneous debugging. Default is False. + """ + parser = Parser(debug=debug) + + return parser.parse_model_from_string(string, existing_model=existing_model) + + +def parse_model_from_json_schema( + filename: str, + top_level_recordtype: bool = True, + types_for_missing_array_items: Optional[dict] = None, + ignore_unspecified_array_items: bool = False, + existing_model: Optional[dict] = None +): + """Return a datamodel parsed from a json schema definition. + + Parameters + ---------- + + filename : str + The path of the json schema file that is to be parsed + + top_level_recordtype : bool, optional + Whether there is a record type defined at the top level of the + schema. Default is true. + + types_for_missing_array_items : dict, optional + dictionary containing fall-back types for json entries with `type: + array` but without `items` specification. Default is an empty dict. + + ignore_unspecified_array_items : bool, optional + Whether to ignore `type: array` entries the type of which is not + specified by their `items` property or given in + `types_for_missing_array_items`. An error is raised if they are not + ignored. Default is False. + + existing_model : dict, optional + An existing model to which the created model shall be added. Not implemented yet. + + Returns + ------- + + out : Datamodel + The datamodel generated from the input schema which then can be used for + synchronizing with LinkAhead. + + Note + ---- + This is an experimental feature, see ``JsonSchemaParser`` for information + about the limitations of the current implementation. + + """ + if types_for_missing_array_items is None: + types_for_missing_array_items = {} + + if existing_model is not None: + raise NotImplementedError("Adding to an existing model is not implemented yet.") + + # @author Florian Spreckelsen + # @date 2022-02-17 + # @review Timm Fitschen 2023-05-25 + parser = JsonSchemaParser(types_for_missing_array_items, ignore_unspecified_array_items) + + return parser.parse_model_from_json_schema(filename, top_level_recordtype) + + +class Parser(object): + def __init__(self, debug: bool = False): + """Initialize an empty parser object and initialize the dictionary of entities and the list of + treated elements. + +Parameters +---------- + +debug : bool, optional + If True, turn on miscellaneous debugging. Default is False. + + """ + self.model = {} + self.treated = [] + self.debug = debug + + def parse_model_from_yaml(self, filename, existing_model: Optional[dict] = None): + """Create and return a data model from the given file. + + Parameters + ---------- + filename : str + The path to the YAML file. + + existing_model : dict, optional + An existing model to which the created model shall be added. + + Returns + ------- + out : data_model.DataModel + The created DataModel + """ + with open(filename, 'r', encoding="utf-8") as outfile: + ymlmodel = yaml.load(outfile, Loader=SafeLineLoader) + + return self._create_model_from_dict(ymlmodel, existing_model=existing_model) + + def parse_model_from_string(self, string, existing_model: Optional[dict] = None): + """Create and return a data model from the given YAML string. + + Parameters + ---------- + string : str + The YAML string. + + existing_model : dict, optional + An existing model to which the created model shall be added. + + Returns + ------- + out : data_model.DataModel + The created DataModel + """ + ymlmodel = yaml.load(string, Loader=SafeLineLoader) + + return self._create_model_from_dict(ymlmodel, existing_model=existing_model) + + def _create_model_from_dict(self, ymlmodel, existing_model: Optional[dict] = None): + """Create and return a data model out of the YAML dict `ymlmodel`. + + Parameters + ---------- + ymlmodel : dict + The dictionary parsed from a YAML file. + + existing_model : dict, optional + An existing model to which the created model shall be added. + + Raises + ------ + ValueError + If model_dict is not a dict, model_dict["extern"] contains an + unknown entry, or there is an unknown entry in model_dict. + + Returns + ------- + out : data_model.DataModel + The created DataModel + """ + + if not isinstance(ymlmodel, dict): + raise ValueError("Yaml file should only contain one dictionary!") + + if existing_model is not None: + self.model.update(existing_model) + + # Extern keyword: + # The extern keyword can be used to include Properties and RecordTypes + # from existing LinkAhead datamodels into the current model. + # Any name included in the list specified by the extern keyword + # will be used in queries to retrieve a property or (if no property exists) + # a record type with the name of the element. + # The retrieved entity will be added to the model. + # If no entity with that name is found an exception is raised. + + if "extern" not in ymlmodel: + ymlmodel["extern"] = [] + + for name in ymlmodel["extern"]: + if name in LINKAHEAD_INTERNAL_PROPERTIES: + self.model[name] = db.Property(name=name).retrieve() + continue + for role in ("Property", "RecordType", "Record", "File"): + if db.execute_query("COUNT {} \"{}\"".format(role, name)) > 0: + self.model[name] = db.execute_query( + f"FIND {role} WITH name=\"{name}\"", unique=True) + break + else: + raise ValueError("Did not find {}".format(name)) + + ymlmodel.pop("extern") + + # add all names to ymlmodel; initialize properties + + for name, entity in ymlmodel.items(): + self._add_entity_to_model(name, entity) + # initialize recordtypes + self._set_recordtypes() + self._check_and_convert_datatypes() + + for name, entity in ymlmodel.items(): + try: + self._treat_entity(name, entity, line=ymlmodel["__line__"]) + except ValueError as err: + err_str = err.args[0].replace("invalid keyword:", + f"invalid keyword in line {entity['__line__']}:", 1) + raise ValueError(err_str, *err.args[1:]) from err + +# Update properties that are part of record types: +# e.g. add their datatypes, units etc.. +# Otherwise comparison of existing models and the parsed model become difficult. + for name, ent in self.model.items(): + if not isinstance(ent, db.RecordType): + continue + props = ent.get_properties() + for prop in props: + if prop.name in self.model: + model_prop = self.model[prop.name] + # The information must be missing, we don't want to overwrite it accidentally: + if prop.datatype is None: + if isinstance(model_prop, db.RecordType): + prop.datatype = model_prop.name + else: + prop.datatype = model_prop.datatype + # TODO: Data type overwrite is allowed here (because + # of lists), but this might change in the future. + # elif prop.datatype != model_prop.datatype: + # raise RuntimeError("datatype must not be set, here. This is probably a bug.") + if prop.unit is None: + # No unit for plain reference properties + if not isinstance(model_prop, db.RecordType): + prop.unit = model_prop.unit + if prop.description is None: + prop.description = model_prop.description + + return DataModel(self.model.values()) + + @staticmethod + def _stringify(name, context=None): + """Make a string out of `name`. + + Warnings are emitted for difficult values of `name`. + + Parameters + ---------- + name : + The value to be converted to a string. + + context : obj + Will be printed in the case of warnings. + + Returns + ------- + out : str + If `name` was a string, return it. Else return str(`name`). + """ + + if name is None: + print("WARNING: Name of this context is None: {}".format(context), + file=sys.stderr) + + if not isinstance(name, str): + name = str(name) + + return name + + def _add_entity_to_model(self, name, definition): + """ adds names of Properties and RecordTypes to the model dictionary + + Properties are also initialized. + + name is the key of the yaml element and definition the value. + """ + + if name == "__line__": + return + name = self._stringify(name) + + if name not in self.model: + self.model[name] = None + + if definition is None: + return + + if (self.model[name] is None and isinstance(definition, dict) + # is it a property + and "datatype" in definition + # but not simply an RT of the model + and not (get_list_datatype(definition["datatype"]) == name and + get_list_datatype(definition["datatype"]) in self.model)): + + # and create the new property + self.model[name] = db.Property(name=name, + datatype=definition["datatype"]) + elif (self.model[name] is None and isinstance(definition, dict) + and "role" in definition): + if definition["role"] == "RecordType": + self.model[name] = db.RecordType(name=name) + elif definition["role"] == "Record": + self.model[name] = db.Record(name=name) + elif definition["role"] == "File": + # TODO(fspreck) Implement files at some later point in time + raise NotImplementedError( + "The definition of file objects is not yet implemented.") + + # self.model[name] = db.File(name=name) + elif definition["role"] == "Property": + self.model[name] = db.Property(name=name) + else: + raise RuntimeError("Unknown role {} in definition of entity.".format( + definition["role"])) + + # for setting values of properties directly: + if not isinstance(definition, dict): + return + + # add other definitions recursively + for prop_type in ["recommended_properties", + "suggested_properties", "obligatory_properties"]: + + if prop_type in definition: + # Empty property mapping should be allowed. + + if definition[prop_type] is None: + definition[prop_type] = {} + try: + for n, e in definition[prop_type].items(): + if n == "__line__": + continue + self._add_entity_to_model(n, e) + except AttributeError as ate: + if ate.args[0].endswith("'items'"): + line = definition["__line__"] + + if isinstance(definition[prop_type], list): + line = definition[prop_type][0]["__line__"] + raise YamlDefinitionError(line) from None + raise + + if self.debug and self.model[name] is not None: + self.model[name].__line__ = definition["__line__"] + + def _add_to_recordtype(self, ent_name, props, importance): + """Add properties to a RecordType. + + Parameters + ---------- + ent_name : str + The name of the entity to which the properties shall be added. + + props : dict [str -> dict or :doc:`Entity`] + The properties, indexed by their names. Properties may be given as :doc:`Entity` objects + or as dictionaries. + + importance + The importance as used in :doc:`Entity.add_property`. + + Returns + ------- + None + + """ + + for n, e in props.items(): + + if n in KEYWORDS: + if n in KEYWORDS_IGNORED: + continue + raise YamlDefinitionError("Unexpected keyword in line {}: {}".format( + props["__line__"], n)) + + if n == "__line__": + continue + n = self._stringify(n) + + if isinstance(e, dict): + if "datatype" in e and get_list_datatype(e["datatype"]) is not None: + # Reuse the existing datatype for lists. + datatype = db.LIST(get_list_datatype(e["datatype"])) + else: + # Ignore a possible e["datatype"] here if it's not a list + # since it has been treated in the definition of the + # property (entity) already + datatype = None + if "value" in e: + value = e["value"] + else: + value = None + + else: + value = e + datatype = None + + self.model[ent_name].add_property(name=n, + value=value, + importance=importance, + datatype=datatype) + + def _inherit(self, name, prop, inheritance): + if not isinstance(prop, list): + if isinstance(prop, str): + raise YamlDefinitionError( + f"Parents must be a list but is given as string: {name} > {prop}") + raise YamlDefinitionError("Parents must be a list, error in line {}".format( + prop["__line__"])) + + for pname in prop: + if not isinstance(pname, str): + raise ValueError("Only provide the names of parents.") + self.model[name].add_parent(name=pname, inheritance=inheritance) + + def _treat_entity(self, name, definition, line=None): + """Parse the definition and the information to the entity.""" + + if name == "__line__": + return + name = self._stringify(name) + + try: + if definition is None: + return + + # for setting values of properties directly: + if not isinstance(definition, dict): + return + + # These definition items must be handled even for list props. + for prop_name, prop in definition.items(): + if prop_name == "description": + self.model[name].description = prop + + # For lists, everything else is not needed at this level. + if ("datatype" in definition and definition["datatype"].startswith("LIST")): + return + + if name in self.treated: + raise TwiceDefinedException(name) + + # for reducing a little bit of code duplication: + importance_dict = { + "recommended_properties": db.RECOMMENDED, + "obligatory_properties": db.OBLIGATORY, + "suggested_properties": db.SUGGESTED + } + + for prop_name, prop in definition.items(): + if prop_name == "__line__": + continue + line = definition["__line__"] + + if prop_name == "unit": + self.model[name].unit = prop + + elif prop_name == "value": + self.model[name].value = prop + + elif prop_name == "description": + # Handled above + continue + + elif prop_name in importance_dict: + for imp_name, imp_val in importance_dict.items(): + if prop_name == imp_name: + self._add_to_recordtype( + name, prop, importance=imp_val) + + for n, e in prop.items(): + self._treat_entity(n, e) + + # datatype is already set + elif prop_name == "datatype": + continue + + # role has already been used + elif prop_name == "role": + continue + + elif prop_name == "inherit_from_obligatory": + self._inherit(name, prop, db.OBLIGATORY) + elif prop_name == "inherit_from_recommended": + self._inherit(name, prop, db.RECOMMENDED) + elif prop_name == "inherit_from_suggested": + self._inherit(name, prop, db.SUGGESTED) + + else: + raise ValueError("invalid keyword: {}".format(prop_name)) + except AttributeError as ate: + if ate.args[0].endswith("'items'"): + raise YamlDefinitionError(line) from None + except Exception as e: + print("Error in treating: "+name) + raise e + self.treated.append(name) + + def _check_and_convert_datatypes(self): + """ checks if datatype is valid. + datatype of properties is simply initialized with string. Here, we + iterate over properties and check whether it is a base datatype of a + name that was defined in the model (or extern part) + + the string representations are replaced with linkahead objects + + """ + + for _, value in self.model.items(): + + if isinstance(value, db.Property): + dtype = value.datatype + is_list = False + + if get_list_datatype(dtype) is not None: + dtype = get_list_datatype(dtype) + is_list = True + + dtype_name = dtype + if not isinstance(dtype_name, str): + dtype_name = dtype.name + + if dtype_name in self.model: + if is_list: + value.datatype = db.LIST(self.model[dtype_name]) + else: + value.datatype = self.model[dtype_name] + + continue + + if dtype in [db.DOUBLE, + db.REFERENCE, + db.TEXT, + db.DATETIME, + db.INTEGER, + db.FILE, + db.BOOLEAN]: + + if is_list: + value.datatype = db.LIST(db.__getattribute__( # pylint: disable=no-member + dtype)) + else: + value.datatype = db.__getattribute__( # pylint: disable=no-member + dtype) + + continue + + raise ValueError("Property {} has an unknown datatype: {}".format( + value.name, dtype_name)) + + def _set_recordtypes(self): + """ properties are defined in first iteration; set remaining as RTs """ + + for key, value in self.model.items(): + if value is None: + self.model[key] = db.RecordType(name=key) + + +class JsonSchemaParser(Parser): + """Extends the yaml parser to read in datamodels defined in a json schema. + + **EXPERIMENTAL:** While this class can already be used to create data models + from basic json schemas, there are the following limitations and missing + features: + + * Due to limitations of json-schema itself, we currently do not support + inheritance in the imported data models + * The same goes for suggested properties of RecordTypes + * Already defined RecordTypes and (scalar) Properties can't be re-used as + list properties + * Reference properties that are different from the referenced RT. (Although + this is possible for list of references) + * Values + * Roles + * The extern keyword from the yaml parser + + """ + # @author Florian Spreckelsen + # @date 2022-02-17 + # @review Timm Fitschen 2023-05-25 + + def __init__(self, types_for_missing_array_items=None, + ignore_unspecified_array_items=False): + super().__init__() + if types_for_missing_array_items is None: + types_for_missing_array_items = {} + self.types_for_missing_array_items = types_for_missing_array_items + self.ignore_unspecified_array_items = ignore_unspecified_array_items + + def parse_model_from_json_schema(self, filename: str, top_level_recordtype: bool = True): + """Return a datamodel created from the definition in the json schema in + `filename`. + + Parameters + ---------- + filename : str + The path to the json-schema file containing the datamodel definition + top_level_recordtype : bool, optional + Whether there is a record type defined at the top level of the + schema. Default is true. + + Returns + ------- + out : data_model.DataModel + The created DataModel + """ + # @author Florian Spreckelsen + # @date 2022-02-17 + # @review Timm Fitschen 2023-05-25 + with open(filename, 'r', encoding="utf-8") as schema_file: + model_dict = jsonref.load(schema_file) + + return self._create_model_from_dict(model_dict, top_level_recordtype=top_level_recordtype) + + # ToDo: Fix https://gitlab.indiscale.com/caosdb/src/caosdb-advanced-user-tools/-/issues/139 + # and remove pylint disable + def _create_model_from_dict(self, model_dict: Union[dict, List[dict]], top_level_recordtype: bool = True): # pylint: disable=arguments-renamed + """Parse a dictionary and return the Datamodel created from it. + + The dictionary was typically created from the model definition in a json schema file. + + Parameters + ---------- + model_dict : dict or list[dict] + One or several dictionaries read in from a json-schema file + top_level_recordtype : bool, optional + Whether there is a record type defined at the top level of the + schema. Default is true. + + Returns + ------- + our : data_model.DataModel + The datamodel defined in `model_dict` + """ + # @review Timm Fitschen 2023-05-25 + if isinstance(model_dict, dict): + model_dict = [model_dict] + + for ii, elt in enumerate(model_dict): + try: + jsonschema.Draft202012Validator.check_schema(elt) + except jsonschema.SchemaError as err: + key = elt["title"] if "title" in elt else f"element {ii}" + raise JsonSchemaDefinitionError( + f"Json Schema error in {key}:\n{str(err)}") from err + + if top_level_recordtype: + if "title" not in elt: + raise JsonSchemaDefinitionError( + f"Object {ii+1} is lacking the `title` key word") + if "type" not in elt: + raise JsonSchemaDefinitionError( + f"Object {ii+1} is lacking the `type` key word") + # Check if this is a valid Json Schema + name = self._stringify(elt["title"], context=elt) + self._treat_element(elt, name) + elif "properties" in elt or "patternProperties" in elt: + # No top-level type but there are entities + if "properties" in elt: + for key, prop in elt["properties"].items(): + name = self._get_name_from_property(key, prop) + self._treat_element(prop, name) + if "patternProperties" in elt: + # See also treatment in ``_treat_record_type``. Since here, + # there is no top-level RT we use the prefix `__Pattern`, + # i.e., the resulting Record Types will be called + # `__PatternElement`. + self._treat_pattern_properties( + elt["patternProperties"], name_prefix="__Pattern") + else: + # Neither RecordType itself, nor further properties in schema, + # so nothing to do here. Maybe add something in the future. + continue + + return DataModel(self.model.values()) + + def _get_name_from_property(self, key: str, prop: dict): + # @review Timm Fitschen 2023-05-25 + if "title" in prop: + name = self._stringify(prop["title"]) + else: + name = self._stringify(key) + + return name + + def _get_atomic_datatype(self, elt): + # @review Timm Fitschen 2023-05-25 + if elt["type"] == "string": + if "format" in elt and elt["format"] in ["date", "date-time"]: + return db.DATETIME + else: + return db.TEXT + elif elt["type"] == "integer": + return db.INTEGER + elif elt["type"] == "number": + return db.DOUBLE + elif elt["type"] == "boolean": + return db.BOOLEAN + elif elt["type"] == "null": + # This could be any datatype since a valid json will never have a + # value in a null property. We use TEXT for convenience. + return db.TEXT + else: + raise JsonSchemaDefinitionError(f"Unkown atomic type in {elt}.") + + def _treat_element(self, elt: dict, name: str): + # @review Timm Fitschen 2023-05-25 + force_list = False + if name in self.model: + return self.model[name], force_list + if "type" not in elt: + # Each element must have a specific type + raise JsonSchemaDefinitionError( + f"`type` is missing in element {name}.") + if name == "name": + # This is identified with the LinkAhead name property as long as the + # type is correct. + if not elt["type"] == "string" and "string" not in elt["type"]: + raise JsonSchemaDefinitionError( + "The 'name' property must be string-typed, otherwise it cannot " + "be identified with LinkAhead's name property." + ) + return None, force_list + # LinkAhead suports null for all types, so in the very special case of + # `"type": ["null", "<other_type>"]`, only consider the other type: + if isinstance(elt["type"], list) and len(elt["type"]) == 2 and "null" in elt["type"]: + elt["type"].remove("null") + elt["type"] = elt["type"][0] + if "enum" in elt: + ent = self._treat_enum(elt, name) + elif elt["type"] in JSON_SCHEMA_ATOMIC_TYPES: + ent = db.Property( + name=name, datatype=self._get_atomic_datatype(elt)) + elif elt["type"] == "object": + ent = self._treat_record_type(elt, name) + elif elt["type"] == "array": + ent, force_list = self._treat_list(elt, name) + else: + raise NotImplementedError( + f"Cannot parse items of type '{elt['type']}' (yet).") + if "description" in elt and ent.description is None: + # There is a description and it hasn't been set by another + # treat_something function + ent.description = elt["description"] + + if ent is not None: + self.model[name] = ent + return ent, force_list + + def _treat_record_type(self, elt: dict, name: str): + # @review Timm Fitschen 2023-05-25 + rt = db.RecordType(name=name) + if "required" in elt: + required = elt["required"] + else: + required = [] + if "properties" in elt: + for key, prop in elt["properties"].items(): + name = self._get_name_from_property(key, prop) + prop_ent, force_list = self._treat_element(prop, name) + if prop_ent is None: + # Nothing to be appended since the property has to be + # treated specially. + continue + importance = db.OBLIGATORY if key in required else db.RECOMMENDED + if not force_list: + rt.add_property(prop_ent, importance=importance) + else: + # Special case of rt used as a list property + rt.add_property(prop_ent, importance=importance, + datatype=db.LIST(prop_ent)) + + if "patternProperties" in elt: + + pattern_property_rts = self._treat_pattern_properties( + elt["patternProperties"], name_prefix=name) + for ppr in pattern_property_rts: + # add reference to pattern property type. These can never be + # obligatory since pattern properties cannot be required in the + # original schema (since their actual names are not known a + # priori). + rt.add_property(ppr) + + if "description" in elt: + rt.description = elt["description"] + return rt + + def _treat_enum(self, elt: dict, name: str): + # @review Timm Fitschen 2022-02-30 + if "type" in elt and elt["type"] == "integer": + raise NotImplementedError( + "Integer-enums are not allowd until " + "https://gitlab.indiscale.com/caosdb/src/caosdb-server/-/issues/224 " + "has been fixed." + ) + rt = db.RecordType(name=name) + for enum_elt in elt["enum"]: + rec = db.Record(name=self._stringify(enum_elt)) + rec.add_parent(rt) + self.model[enum_elt] = rec + + return rt + + def _treat_list(self, elt: dict, name: str): + # @review Timm Fitschen 2023-05-25 + + if "items" not in elt and name not in self.types_for_missing_array_items: + if self.ignore_unspecified_array_items: + return None, False + raise JsonSchemaDefinitionError( + f"The definition of the list items is missing in {elt}.") + if "items" in elt: + items = elt["items"] + if "enum" in items: + return self._treat_enum(items, name), True + if items["type"] in JSON_SCHEMA_ATOMIC_TYPES: + datatype = db.LIST(self._get_atomic_datatype(items)) + return db.Property(name=name, datatype=datatype), False + if items["type"] == "object": + if "title" not in items or self._stringify(items["title"]) == name: + # Property is RecordType + return self._treat_record_type(items, name), True + else: + # List property will be an entity of its own with a name + # different from the referenced RT + ref_rt = self._treat_record_type( + items, self._stringify(items["title"])) + self.model[ref_rt.name] = ref_rt + return db.Property(name=name, datatype=db.LIST(ref_rt)), False + else: + # Use predefined type: + datatype = db.LIST(self.types_for_missing_array_items[name]) + return db.Property(name=name, datatype=datatype), False + + def _get_pattern_prop(self): + # @review Timm Fitschen 2023-05-25 + if "__pattern_property_pattern_property" in self.model: + return self.model["__pattern_property_pattern_property"] + pp = db.Property(name="__matched_pattern", datatype=db.TEXT) + self.model["__pattern_property_pattern_property"] = pp + return pp + + def _treat_pattern_properties(self, pattern_elements, name_prefix=""): + """Special Treatment for pattern properties: A RecordType is created for + each pattern property. In case of a `type: object` PatternProperty, the + remaining properties of the JSON entry are appended to the new + RecordType; in case of an atomic type PatternProperty, a single value + Property is added to the RecordType. + + Raises + ------ + NotImplementedError + In case of patternProperties with non-object, non-atomic type, e.g., + array. + + """ + # @review Timm Fitschen 2023-05-25 + num_patterns = len(pattern_elements) + pattern_prop = self._get_pattern_prop() + returns = [] + for ii, (key, element) in enumerate(pattern_elements.items()): + if "title" not in element: + name_suffix = f"_{ii+1}" if num_patterns > 1 else "" + name = name_prefix + "Entry" + name_suffix + else: + name = element["title"] + if element["type"] == "object": + # simple, is already an object, so can be treated like any other + # record type. + pattern_type = self._treat_record_type(element, name) + elif element["type"] in JSON_SCHEMA_ATOMIC_TYPES: + # create a property that stores the actual value of the pattern + # property. + propname = f"{name}_value" + prop = db.Property(name=propname, datatype=self._get_atomic_datatype(element)) + self.model[propname] = prop + pattern_type = db.RecordType(name=name) + pattern_type.add_property(prop) + else: + raise NotImplementedError( + "Pattern properties are currently only supported for types " + + ", ".join(JSON_SCHEMA_ATOMIC_TYPES) + ", and object.") + + # Add pattern property and description + pattern_type.add_property(pattern_prop, importance=db.OBLIGATORY) + if pattern_type.description: + pattern_type.description += f"\n\npattern: {key}" + else: + pattern_type.description = f"pattern: {key}" + + self.model[name] = pattern_type + returns.append(pattern_type) + + return returns + + +def main(): + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("data_model", + help="Path name of the data model file (yaml or json) to be used.") + parser.add_argument("--sync", action="store_true", + help="Whether or not to sync the data model with the server.") + parser.add_argument("--noquestion", action="store_true", + help="Whether or not to ask questions during synchronization.") + parser.add_argument("--print", action="store_true", + help="Whether or not to print the data model.") + + args = parser.parse_args() + if args.data_model.endswith(".json"): + model = parse_model_from_json_schema(args.data_model) + elif args.data_model.endswith(".yml") or args.data_model.endswith(".yaml"): + model = parse_model_from_yaml(args.data_model) + else: + raise RuntimeError(f"Unknown file ending of data model: {args.data_model}") + if args.print: + print(model) + if args.sync: + model.sync_data_model(noquestion=args.noquestion) + + +if __name__ == "__main__": + main() diff --git a/unittests/test_json_schema_model_parser.py b/unittests/test_json_schema_model_parser.py index cdd4c074..619714aa 100644 --- a/unittests/test_json_schema_model_parser.py +++ b/unittests/test_json_schema_model_parser.py @@ -357,8 +357,8 @@ def test_name_property(): broken = parse_model_from_json_schema(os.path.join( FILEPATH, "datamodel_name_wrong_type.schema.json")) assert str(err.value).startswith( - "The 'name' property must be string-typed, otherwise it cannot be identified with LinkAhead's " - "name property.") + "The 'name' property must be string-typed, otherwise it cannot be identified with " + "LinkAhead's name property.") def test_no_toplevel_entity(): -- GitLab From 1949243032789473da2dbf75799549de37f63ec3 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Fri, 10 Jan 2025 16:52:32 +0100 Subject: [PATCH 104/106] MAINT: Removed more Python 3.8 code. --- src/caosadvancedtools/models/data_model.py | 7 +------ tox.ini | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/caosadvancedtools/models/data_model.py b/src/caosadvancedtools/models/data_model.py index 92afb7eb..6d30b8fb 100644 --- a/src/caosadvancedtools/models/data_model.py +++ b/src/caosadvancedtools/models/data_model.py @@ -23,11 +23,6 @@ # ** end header # from copy import deepcopy -# TODO(fspreck) for backwards compatibility with Python < 3.9 but this is -# actually -# [deprecated](https://docs.python.org/3/library/typing.html#typing.List), so -# remove this, when we drop support for old Python versions. -from typing import List import linkahead as db import linkahead.common.models as models @@ -85,7 +80,7 @@ class DataModel(dict): def append(self, entity: db.Entity): self[entity.name] = entity - def extend(self, entities: List[db.Entity]): + def extend(self, entities: list[db.Entity]): for entity in entities: self.append(entity) diff --git a/tox.ini b/tox.ini index 12c7ad50..786a1054 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38, py39, py310, py311, py312, py313 +envlist = py39, py310, py311, py312, py313 skip_missing_interpreters = true [testenv] -- GitLab From a800eb64cfb234096d366640fc28ef745543c044 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Thu, 16 Jan 2025 10:48:47 +0100 Subject: [PATCH 105/106] DOC: Update changelog --- CHANGELOG.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5090e89..1375a7d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] ## +## [0.13.0] - 2025-01-16 ## ### Added ### @@ -12,34 +12,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed ### -- Using the official name "LinkAhead" wherever possible without large effort. This includes the - following exposed names / features: +- Using the official name "LinkAhead" wherever possible without large + effort. This includes the following exposed names / features: - `models.data_model.LINKAHEAD_INTERNAL_PROPERTIES` - `export_related.export` exports to `linkahead_data.xml` now. - Renamed (and added) installation "extra" options: - `h5` instead of `h5-crawler` - - `dev`, `doc`, `test` and `all` are new, they install the dependencies for developing, testing, - documentation and everything. -- The `pandoc_header_tools.get_header()` parameter `add_header` has been renamed to `add_header_to_file` - to resolve a name collision. - -### Deprecated ### + - `dev`, `doc`, `test` and `all` are new, they install the + dependencies for developing, testing, documentation and + everything. +- The `pandoc_header_tools.get_header()` parameter `add_header` has + been renamed to `add_header_to_file` to resolve a name collision. ### Removed ### -- Bloxberg code snippets. These were just a proof of concept, untested and never used in production. -- Labfolder converter. It was broken anyway, not used by anyone we know and there were no automated - tests. For the time being, it lives on in the `f-labfolder-converter` branch, [issue 67](https://gitlab.com/linkahead/linkahead-advanced-user-tools/-/issues/67) is - there to coordinate resurrections efforts if someone needs it.. +- Bloxberg code snippets. These were just a proof of concept, untested + and never used in production. +- Labfolder converter. It was broken anyway, not used by anyone we + know and there were no automated tests. For the time being, it lives + on in the `f-labfolder-converter` branch, [issue + 67](https://gitlab.com/linkahead/linkahead-advanced-user-tools/-/issues/67) + is there to coordinate resurrections efforts if someone needs it.. - Support for Python 3.8 ### Fixed ### -- Yaml data model parser adds data types of properties of record types and other attributes which fixes https://gitlab.indiscale.com/caosdb/customers/f-fit/management/-/issues/58 +- Yaml data model parser adds data types of properties of record types + and other attributes which fixes + https://gitlab.indiscale.com/caosdb/customers/f-fit/management/-/issues/58 - `XLSXConverter` now checks path validity before parsing the worksheet. -### Security ### - ### Documentation ### * Added documentation of `caosadvancedtools.loadFiles` module. -- GitLab From fea642646ee83306cf45d5044f833328bde49f95 Mon Sep 17 00:00:00 2001 From: Florian Spreckelsen <f.spreckelsen@indiscale.com> Date: Thu, 16 Jan 2025 10:51:53 +0100 Subject: [PATCH 106/106] REL: Prepare 0.13.0 --- CITATION.cff | 4 ++-- setup.py | 6 +++--- src/doc/conf.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index c4628534..6e685219 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -20,6 +20,6 @@ authors: given-names: Stefan orcid: https://orcid.org/0000-0001-7214-8125 title: CaosDB - Advanced User Tools -version: 0.12.0 +version: 0.13.0 doi: 10.3390/data4020083 -date-released: 2024-07-31 \ No newline at end of file +date-released: 2025-01-16 \ No newline at end of file diff --git a/setup.py b/setup.py index c7dd54a9..d8d28e4d 100755 --- a/setup.py +++ b/setup.py @@ -46,10 +46,10 @@ from setuptools import find_packages, setup ######################################################################## MAJOR = 0 -MINOR = 12 -MICRO = 1 +MINOR = 13 +MICRO = 0 PRE = "" # e.g. rc0, alpha.1, 0.beta-23 -ISRELEASED = False +ISRELEASED = True if PRE: VERSION = "{}.{}.{}-{}".format(MAJOR, MINOR, MICRO, PRE) diff --git a/src/doc/conf.py b/src/doc/conf.py index e8975650..12495069 100644 --- a/src/doc/conf.py +++ b/src/doc/conf.py @@ -23,13 +23,13 @@ import sphinx_rtd_theme # -- Project information ----------------------------------------------------- project = 'caosadvancedtools' -copyright = '2023, IndiScale GmbH' +copyright = '2025, IndiScale GmbH' author = 'Daniel Hornung' # The short X.Y version -version = '0.12.1' +version = '0.13.0' # The full version, including alpha/beta/rc tags -release = '0.12.1-dev' +release = '0.13.0' # -- General configuration --------------------------------------------------- -- GitLab