diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000000..f05ada921937 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +/.git +/share +/data +/media +/.env +/.vscode +/db.sqlite3 +/keys diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..710bd9abf253 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Project Specific +/data/ +/share/ +/static/ +/db.sqlite3 +/.env +/keys +/logs + +# Ignore temporary files +docker-compose.override.yml +/.vscode +__pycache__ +*.pyc +._* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..356157809027 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +# How to contribute to Computer Vision Annotation Tool (CVAT) + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000000..c86e3ae0306e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,99 @@ +FROM ubuntu:16.04 + +ARG http_proxy +ARG https_proxy +ARG no_proxy + +ENV TERM=xterm \ + http_proxy=${http_proxy} \ + https_proxy=${https_proxy} \ + no_proxy=${no_proxy} + +ENV LANG='C.UTF-8' \ + LC_ALL='C.UTF-8' + +ARG USER +ARG TF_ANNOTATION +ENV TF_ANNOTATION=${TF_ANNOTATION} +ARG DJANGO_CONFIGURATION +ENV DJANGO_CONFIGURATION=${DJANGO_CONFIGURATION} + +# Install necessary apt packages +RUN apt-get update && \ + apt-get install -yq \ + python-software-properties \ + software-properties-common \ + wget && \ + add-apt-repository ppa:mc3man/xerus-media -y && \ + add-apt-repository ppa:mc3man/gstffmpeg-keep -y && \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -yq \ + apache2 \ + apache2-dev \ + libapache2-mod-xsendfile \ + supervisor \ + ffmpeg \ + gstreamer0.10-ffmpeg \ + libldap2-dev \ + libsasl2-dev \ + python3-dev \ + python3-pip \ + unzip \ + unrar \ + p7zip-full \ + vim && \ + rm -rf /var/lib/apt/lists/* + +# Add a non-root user +ENV USER=${USER} +ENV HOME /home/${USER} +WORKDIR ${HOME} +RUN adduser --shell /bin/bash --disabled-password --gecos "" ${USER} + +# Install tf annotation if need +COPY cvat/apps/tf_annotation/docker_setup_tf_annotation.sh /tmp/tf_annotation/ +COPY cvat/apps/tf_annotation/requirements.txt /tmp/tf_annotation/ +ENV TF_ANNOTATION_MODEL_PATH=${HOME}/rcnn/frozen_inference_graph.pb + +RUN if [ "$TF_ANNOTATION" = "yes" ]; then \ + /tmp/tf_annotation/docker_setup_tf_annotation.sh; \ + fi + +ARG WITH_TESTS +RUN if [ "$WITH_TESTS" = "yes" ]; then \ + wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list && \ + wget -qO- https://deb.nodesource.com/setup_9.x | bash - && \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -yq \ + google-chrome-stable \ + nodejs && \ + rm -rf /var/lib/apt/lists/*; \ + mkdir tests && cd tests && npm install \ + eslint \ + eslint-detailed-reporter \ + karma \ + karma-chrome-launcher \ + karma-coverage \ + karma-junit-reporter \ + karma-qunit \ + qunit; \ + echo "export PATH=~/tests/node_modules/.bin:${PATH}" >> ~/.bashrc; \ + fi + +# Install and initialize CVAT, copy all necessary files +COPY cvat/requirements/ /tmp/requirements/ +COPY supervisord.conf mod_wsgi.conf wait-for-it.sh manage.py ${HOME}/ +RUN pip3 install --no-cache-dir -r /tmp/requirements/${DJANGO_CONFIGURATION}.txt +COPY cvat/ ${HOME}/cvat +COPY tests ${HOME}/tests +RUN chown -R ${USER}:${USER} . + +# RUN all commands below as 'django' user +USER ${USER} + +RUN mkdir data share media keys logs /tmp/supervisord +RUN python3 manage.py collectstatic + +EXPOSE 8080 8443 +ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000000..97c8a762b6f7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 annotation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000000..539622755fab --- /dev/null +++ b/README.md @@ -0,0 +1,106 @@ +# Computer Vision Annotation Tool (CVAT) + +CVAT is completely re-designed and re-implemented version of [Video Annotation Tool from Irvine, California](http://carlvondrick.com/vatic/) tool. It is free, online, interactive video and image annotation tool for computer vision. It is being used by our team to annotate million of objects with different properties. Many UI and UX decisions are based on feedbacks from professional data annotation team. + +## LICENSE + +Code released under the [MIT License](https://opensource.org/licenses/MIT). + +## INSTALLATION + +These instructions below should work for Ubuntu 16.04. Probably it will work on other OSes as well with minor modifications. + +### Install [Docker CE](https://www.docker.com/community-edition) or [Docker EE](https://www.docker.com/enterprise-edition) from official site + +Please read official manual [here](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/). + +### Install the latest driver for your graphics card + +The step is necessary only to run tf_annotation app. If you don't have a Nvidia GPU you can skip the step. + +```bash +sudo add-apt-repository ppa:graphics-drivers/ppa +sudo apt-get update +sudo apt-cache search nvidia-* # find latest nvidia driver +sudo apt-get install nvidia-* # install the nvidia driver +sudo apt-get install mesa-common-dev +sudo apt-get install freeglut3-dev +sudo apt-get install nvidia-modprobe +``` + +Reboot your PC and verify installation by `nvidia-smi` command. + +### Install [Nvidia-Docker](https://github.com/NVIDIA/nvidia-docker) + +The step is necessary only to run tf_annotation app. If you don't have a Nvidia GPU you can skip the step. See detailed installation instructions on repository page. + +### Install docker-compose (1.19.0 or newer) + +```bash +sudo pip install docker-compose +``` + +### Build docker images + +To build all necessary docker images run `docker-compose build` command. By default, in production mode the tool uses PostgreSQL as database, Redis for caching. + +### Run containers without tf_annotation app + +To start all containers run `docker-compose up -d` command. Go to [localhost:8080](http://localhost:8080/). You should see a login page. + +### Run containers with tf_annotation app + +If you would like to enable tf_annotation app first of all be sure that nvidia-driver, nvidia-docker and docker-compose>=1.19.0 are installed properly (see instructions above) and `docker info | grep 'Runtimes'` output contains `nvidia`. + +Run following command: +```bash +docker-compose -f docker-compose.yml -f docker-compose.nvidia.yml up -d --build +``` + +### Create superuser account + +You can [register a user](http://localhost:8080/auth/register) but by default it will not have rights even to view list of tasks. Thus you should create a superuser. The superuser can use admin panel to assign correct groups to the user. Please use the command below: + +```bash +docker exec -it cvat sh -c '/usr/bin/python3 ~/manage.py createsuperuser' +``` + +Type your login/password for the superuser [on the login page](http://localhost:8080/auth/login) and press **Login** button. Now you should be able to create a new annotation task. Please read documentation for more details. + +### Stop all containers + +The command below will stop and remove containers, networks, volumes, and images +created by `up`. + +```bash +docker-compose down +``` + +### Advanced settings + +If you want to access you instance of CVAT outside of your localhost you should specify [ALLOWED_HOSTS](https://docs.djangoproject.com/en/2.0/ref/settings/#allowed-hosts) environment variable. The best way to do that is to create [docker-compose.override.yml](https://docs.docker.com/compose/extends/) and put all your extra settings here. + +```yml +version: "2.3" + +services: + cvat: + environment: + ALLOWED_HOSTS: .example.com + ports: + - "80:8080" +``` +### Annotation logs + +It is possible to proxy annotation logs from client to another server over http. For examlpe you can use Logstash. +To do that set DJANGO_LOG_SERVER_URL environment variable in cvat section of docker-compose.yml +file (or add this variable to docker-compose.override.yml). + +```yml +version: "2.3" + +services: +cvat: + environment: + DJANGO_LOG_SERVER_URL: https://annotation.example.com:5000 +``` diff --git a/cvat/__init__.py b/cvat/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/authentication/__init__.py b/cvat/apps/authentication/__init__.py new file mode 100644 index 000000000000..b3d5c6b0799a --- /dev/null +++ b/cvat/apps/authentication/__init__.py @@ -0,0 +1 @@ +default_app_config = 'cvat.apps.authentication.apps.AuthenticationConfig' diff --git a/cvat/apps/authentication/admin.py b/cvat/apps/authentication/admin.py new file mode 100644 index 000000000000..8c38f3f3dad5 --- /dev/null +++ b/cvat/apps/authentication/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cvat/apps/authentication/apps.py b/cvat/apps/authentication/apps.py new file mode 100644 index 000000000000..f742de0441c8 --- /dev/null +++ b/cvat/apps/authentication/apps.py @@ -0,0 +1,18 @@ +from django.apps import AppConfig +from django.db.models.signals import post_migrate, post_save +from .settings.authentication import DJANGO_AUTH_TYPE + +class AuthenticationConfig(AppConfig): + name = 'cvat.apps.authentication' + + def ready(self): + from . import signals + from django.contrib.auth.models import User + + post_migrate.connect(signals.create_groups) + + if DJANGO_AUTH_TYPE == 'SIMPLE': + post_save.connect(signals.create_user, sender=User, dispatch_uid="create_user") + + import django_auth_ldap.backend + django_auth_ldap.backend.populate_user.connect(signals.update_ldap_groups) diff --git a/cvat/apps/authentication/decorators.py b/cvat/apps/authentication/decorators.py new file mode 100644 index 000000000000..1e3d49183945 --- /dev/null +++ b/cvat/apps/authentication/decorators.py @@ -0,0 +1,32 @@ +from django.contrib.auth import REDIRECT_FIELD_NAME +from django.shortcuts import resolve_url, reverse +from django.http import JsonResponse +from urllib.parse import urlparse +from django.contrib.auth.views import redirect_to_login + +from functools import wraps +from django.conf import settings + +def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None, redirect_methods=['GET']): + def decorator(view_func): + @wraps(view_func) + def _wrapped_view(request, *args, **kwargs): + if request.user.is_authenticated: + return view_func(request, *args, **kwargs) + else: + if request.method not in redirect_methods: + return JsonResponse({'login_page_url': reverse('login')}, status=403) + + path = request.build_absolute_uri() + resolved_login_url = resolve_url(login_url or settings.LOGIN_URL) + # If the login url is the same scheme and net location then just + # use the path as the "next" url. + login_scheme, login_netloc = urlparse(resolved_login_url)[:2] + current_scheme, current_netloc = urlparse(path)[:2] + if ((not login_scheme or login_scheme == current_scheme) and + (not login_netloc or login_netloc == current_netloc)): + path = request.get_full_path() + + return redirect_to_login(path, resolved_login_url, redirect_field_name) + return _wrapped_view + return decorator(function) if function else decorator diff --git a/cvat/apps/authentication/forms.py b/cvat/apps/authentication/forms.py new file mode 100644 index 000000000000..9b6ab87779ae --- /dev/null +++ b/cvat/apps/authentication/forms.py @@ -0,0 +1,55 @@ +from django.contrib.auth.forms import ( + UsernameField, + AuthenticationForm, + UserCreationForm, +) +from django.utils.translation import gettext, gettext_lazy as _ +from django.contrib.auth.models import User + +from django import forms + +class AuthForm(AuthenticationForm): + username = UsernameField( + widget=forms.TextInput(attrs={'autofocus': True, 'placeholder': "Username"}), + ) + password = forms.CharField( + label=_("Password"), + strip=False, + widget=forms.PasswordInput(attrs={'placeholder': "Password"}), + ) + +class NewUserForm(UserCreationForm): + username = UsernameField( + widget=forms.TextInput(attrs={'autofocus': True, 'placeholder': "Username (required)"}), + required=True, + ) + + first_name = UsernameField( + widget=forms.TextInput(attrs={'placeholder': "First name"}), + required=False, + ) + + last_name = UsernameField( + widget=forms.TextInput(attrs={'placeholder': "Last name"}), + required=False, + ) + + email = forms.EmailField( + widget=forms.EmailInput(attrs={'placeholder': "Email (required)"}), + required=True, + ) + + password1 = forms.CharField( + label=_("Password"), + strip=False, + widget=forms.PasswordInput(attrs={'placeholder': "Password (required)"}), + ) + password2 = forms.CharField( + label=_("Password confirmation"), + widget=forms.PasswordInput(attrs={'placeholder': "Password confirmation (required)"}), + strip=False, + ) + + class Meta: + model = User + fields = ('username', 'first_name', 'last_name', 'email', ) diff --git a/cvat/apps/authentication/migrations/__init__.py b/cvat/apps/authentication/migrations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/authentication/models.py b/cvat/apps/authentication/models.py new file mode 100644 index 000000000000..71a836239075 --- /dev/null +++ b/cvat/apps/authentication/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/cvat/apps/authentication/settings/__init__.py b/cvat/apps/authentication/settings/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/authentication/settings/auth_ldap.py b/cvat/apps/authentication/settings/auth_ldap.py new file mode 100644 index 000000000000..1abc5ac1cd55 --- /dev/null +++ b/cvat/apps/authentication/settings/auth_ldap.py @@ -0,0 +1,51 @@ +from django.conf import settings +import ldap +from django_auth_ldap.config import LDAPSearch, NestedActiveDirectoryGroupType + +# Baseline configuration. +settings.AUTH_LDAP_SERVER_URI = "" + +# Credentials for LDAP server +settings.AUTH_LDAP_BIND_DN = "" +settings.AUTH_LDAP_BIND_PASSWORD = "" + +# Set up basic user search +settings.AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=example,dc=com", + ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)") + +# Set up the basic group parameters. +settings.AUTH_LDAP_GROUP_SEARCH = LDAPSearch("dc=example,dc=com", + ldap.SCOPE_SUBTREE, "(objectClass=group)") +settings.AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType() + +# # Simple group restrictions +settings.AUTH_LDAP_REQUIRE_GROUP = "cn=cvat,ou=Groups,dc=example,dc=com" + +# Populate the Django user from the LDAP directory. +settings.AUTH_LDAP_USER_ATTR_MAP = { + "first_name": "givenName", + "last_name": "sn", + "email": "mail", +} + +settings.AUTH_LDAP_ALWAYS_UPDATE_USER = True + +# Cache group memberships for an hour to minimize LDAP traffic +settings.AUTH_LDAP_CACHE_GROUPS = True +settings.AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 +settings.AUTH_LDAP_AUTHORIZE_ALL_USERS = True + +# Keep ModelBackend around for per-user permissions and maybe a local +# superuser. +settings.AUTHENTICATION_BACKENDS.append('django_auth_ldap.backend.LDAPBackend') + +AUTH_LDAP_ADMIN_GROUPS = [ + "cn=cvat_admins,ou=Groups,dc=example,dc=com" +] + +AUTH_LDAP_DATA_ANNOTATORS_GROUPS = [ +] + +AUTH_LDAP_DEVELOPER_GROUPS = [ + "cn=cvat_users,ou=Groups,dc=example,dc=com" +] diff --git a/cvat/apps/authentication/settings/auth_simple.py b/cvat/apps/authentication/settings/auth_simple.py new file mode 100644 index 000000000000..dcd04277246a --- /dev/null +++ b/cvat/apps/authentication/settings/auth_simple.py @@ -0,0 +1,2 @@ +# Specify groups that new users will have +AUTH_SIMPLE_DEFAULT_GROUPS = [] diff --git a/cvat/apps/authentication/settings/authentication.py b/cvat/apps/authentication/settings/authentication.py new file mode 100644 index 000000000000..2cb9d4707e26 --- /dev/null +++ b/cvat/apps/authentication/settings/authentication.py @@ -0,0 +1,53 @@ +from django.conf import settings +import os + +settings.LOGIN_URL = 'login' +settings.LOGIN_REDIRECT_URL = '/' + +settings.AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', +] + +AUTH_LDAP_DEVELOPER_GROUPS = [] +AUTH_LDAP_DATA_ANNOTATORS_GROUPS = [] +AUTH_LDAP_ADMIN_GROUPS = [] + +DJANGO_AUTH_TYPE = 'LDAP' if os.environ.get('DJANGO_AUTH_TYPE', '') == 'LDAP' else 'SIMPLE' + +if DJANGO_AUTH_TYPE == 'LDAP': + from .auth_ldap import * +else: + from .auth_simple import * + +# Definition of CVAT groups with permissions for task and annotation objects +# Annotator - can modify annotation for task, but cannot add, change and delete tasks +# Developer - can create tasks and modify (delete) owned tasks and any actions with annotation +# Admin - can any actions for task and annotation, can login to admin area and manage groups and users +cvat_groups_definition = { + 'user': { + 'description': '', + 'permissions': { + 'task': ['view', 'add', 'change', 'delete'], + 'annotation': ['view', 'change'], + }, + 'ldap_groups': AUTH_LDAP_DEVELOPER_GROUPS, + }, + + 'annotator': { + 'description': '', + 'permissions': { + 'task': ['view'], + 'annotation': ['view', 'change'], + }, + 'ldap_groups': AUTH_LDAP_DATA_ANNOTATORS_GROUPS, + }, + + 'admin': { + 'description': '', + 'permissions': { + 'task': ['view', 'add', 'change', 'delete'], + 'annotation': ['view', 'change'], + }, + 'ldap_groups': AUTH_LDAP_ADMIN_GROUPS, + }, +} diff --git a/cvat/apps/authentication/signals.py b/cvat/apps/authentication/signals.py new file mode 100644 index 000000000000..3a30ac2099e6 --- /dev/null +++ b/cvat/apps/authentication/signals.py @@ -0,0 +1,57 @@ +from django.db import models + +from django.conf import settings +from .settings import authentication +from django.contrib.auth.models import User, Group + +def setup_group_permissions(group): + from cvat.apps.engine.models import Task + from django.contrib.auth.models import Permission + from django.contrib.contenttypes.models import ContentType + + def append_permissions_for_model(model): + content_type = ContentType.objects.get_for_model(model) + for perm_target, actions in authentication.cvat_groups_definition[group.name]['permissions'].items(): + for action in actions: + codename = '{}_{}'.format(action, perm_target) + try: + perm = Permission.objects.get(codename=codename, content_type=content_type) + group_permissions.append(perm) + except: + pass + group_permissions = [] + append_permissions_for_model(Task) + + group.permissions.set(group_permissions) + group.save() + +def create_groups(sender, **kwargs): + for cvat_role, _ in authentication.cvat_groups_definition.items(): + Group.objects.get_or_create(name=cvat_role) + +def update_ldap_groups(sender, user=None, ldap_user=None, **kwargs): + user_groups = [] + for cvat_role, role_settings in authentication.cvat_groups_definition.items(): + group_instance, _ = Group.objects.get_or_create(name=cvat_role) + setup_group_permissions(group_instance) + + for ldap_group in role_settings['ldap_groups']: + if ldap_group.lower() in ldap_user.group_dns: + user_groups.append(group_instance) + + user.save() + user.groups.set(user_groups) + user.is_staff = user.is_superuser = user.groups.filter(name='admin').exists() + +def create_user(sender, instance, created, **kwargs): + if instance.is_superuser and instance.is_staff: + admin_group, _ = Group.objects.get_or_create(name='admin') + admin_group.user_set.add(instance) + + if created: + for cvat_role, _ in authentication.cvat_groups_definition.items(): + group_instance, _ = Group.objects.get_or_create(name=cvat_role) + setup_group_permissions(group_instance) + + if cvat_role in authentication.AUTH_SIMPLE_DEFAULT_GROUPS: + instance.groups.add(group_instance) diff --git a/cvat/apps/authentication/templates/403.html b/cvat/apps/authentication/templates/403.html new file mode 100644 index 000000000000..daaa6181988d --- /dev/null +++ b/cvat/apps/authentication/templates/403.html @@ -0,0 +1,12 @@ +{% extends "auth_base.html" %} + +{% block title %}Forbidden{% endblock %} + +{% block content %} +

Forbidden

+ {% if user.is_authenticated %} +

Your account doesn't have access to this page. To proceed, + please login with an account that has access or contact your admin.
+ Login

+ {% endif %} +{% endblock %} diff --git a/cvat/apps/authentication/templates/auth_base.html b/cvat/apps/authentication/templates/auth_base.html new file mode 100644 index 000000000000..a9a4b98f4d90 --- /dev/null +++ b/cvat/apps/authentication/templates/auth_base.html @@ -0,0 +1,99 @@ + + + + + + + + {% block title %}{% endblock %} + + + + + + + +
+ {% block note %} {% endblock %} +
+ + diff --git a/cvat/apps/authentication/templates/login.html b/cvat/apps/authentication/templates/login.html new file mode 100644 index 000000000000..d039bcb6281f --- /dev/null +++ b/cvat/apps/authentication/templates/login.html @@ -0,0 +1,22 @@ +{% extends "auth_base.html" %} + +{% block title %}Login{% endblock %} + +{% block content %} +

Login

+ {% if form.errors %} + Your username and password didn't match. Please try again. + {% endif %} +
+ {% csrf_token %} + {% for field in form %} + {{ field }} + {% endfor %} + + +
+{% endblock %} + +{% block note%} +

Have not registered yet? Register here.

+{% endblock %} \ No newline at end of file diff --git a/cvat/apps/authentication/templates/login_ldap.html b/cvat/apps/authentication/templates/login_ldap.html new file mode 100644 index 000000000000..ba89202242da --- /dev/null +++ b/cvat/apps/authentication/templates/login_ldap.html @@ -0,0 +1,22 @@ +{% extends "auth_base.html" %} + +{% block title %}Login{% endblock %} + +{% block content %} +

Login

+ {% if form.errors %} + Your username and password didn't match. Please try again. + {% endif %} +
+ {% csrf_token %} + {% for field in form %} + {{ field }} + {% endfor %} + + +
+{% endblock %} + +{% block note %} + {% include "note.html" %} +{% endblock %} diff --git a/cvat/apps/authentication/templates/note.html b/cvat/apps/authentication/templates/note.html new file mode 100644 index 000000000000..2791447dacb4 --- /dev/null +++ b/cvat/apps/authentication/templates/note.html @@ -0,0 +1,2 @@ +

+

\ No newline at end of file diff --git a/cvat/apps/authentication/templates/register.html b/cvat/apps/authentication/templates/register.html new file mode 100644 index 000000000000..aa0793b8b689 --- /dev/null +++ b/cvat/apps/authentication/templates/register.html @@ -0,0 +1,27 @@ +{% extends "auth_base.html" %} + +{% block title %}Create user{% endblock %} + +{% block content %} + + +
+ +
+{% endblock %} diff --git a/cvat/apps/authentication/templates/user_profile.html b/cvat/apps/authentication/templates/user_profile.html new file mode 100644 index 000000000000..82f9c231e02c --- /dev/null +++ b/cvat/apps/authentication/templates/user_profile.html @@ -0,0 +1,16 @@ +
+ {% if user.is_authenticated %} + {% if user.ldap_user and 'thumbnailPhoto' in user.ldap_user.attrs %} + {# TODO insert photo from ldap #} + {% endif %} + + {% if user.first_name and user.last_name %} +

{{ user.first_name }} {{ user.last_name }}

+ {% else %} +

{{ user.username }}

+ {% endif %} +
+ +
+ {% endif %} +
\ No newline at end of file diff --git a/cvat/apps/authentication/tests.py b/cvat/apps/authentication/tests.py new file mode 100644 index 000000000000..7ce503c2dd97 --- /dev/null +++ b/cvat/apps/authentication/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cvat/apps/authentication/urls.py b/cvat/apps/authentication/urls.py new file mode 100644 index 000000000000..926ce6b5a9ee --- /dev/null +++ b/cvat/apps/authentication/urls.py @@ -0,0 +1,15 @@ +from django.urls import path +import os + +from django.contrib.auth import views as auth_views +from . import forms +from . import views +from .settings.authentication import DJANGO_AUTH_TYPE + +login_page = 'login{}.html'.format('_ldap' if DJANGO_AUTH_TYPE == 'LDAP' else '') + +urlpatterns = [ + path('login', auth_views.LoginView.as_view(form_class=forms.AuthForm, template_name=login_page), name='login'), + path('logout', auth_views.LogoutView.as_view(next_page='login'), name='logout'), + path('register', views.register_user, name='register'), +] diff --git a/cvat/apps/authentication/views.py b/cvat/apps/authentication/views.py new file mode 100644 index 000000000000..2ab2d9676501 --- /dev/null +++ b/cvat/apps/authentication/views.py @@ -0,0 +1,21 @@ +from django.shortcuts import render +from django.contrib.auth.views import LoginView +from django.http import HttpResponseRedirect +from . import forms + +from django.contrib.auth import login, authenticate +from django.shortcuts import render, redirect + +def register_user(request): + if request.method == 'POST': + form = forms.NewUserForm(request.POST) + if form.is_valid(): + form.save() + username = form.cleaned_data.get('username') + raw_password = form.cleaned_data.get('password1') + user = authenticate(username=username, password=raw_password) + login(request, user) + return redirect('/') + else: + form = forms.NewUserForm() + return render(request, 'register.html', {'form': form}) diff --git a/cvat/apps/dashboard/__init__.py b/cvat/apps/dashboard/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/dashboard/admin.py b/cvat/apps/dashboard/admin.py new file mode 100644 index 000000000000..8c38f3f3dad5 --- /dev/null +++ b/cvat/apps/dashboard/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cvat/apps/dashboard/apps.py b/cvat/apps/dashboard/apps.py new file mode 100644 index 000000000000..50878e766268 --- /dev/null +++ b/cvat/apps/dashboard/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class DashboardConfig(AppConfig): + name = 'dashboard' diff --git a/cvat/apps/dashboard/migrations/__init__.py b/cvat/apps/dashboard/migrations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/dashboard/models.py b/cvat/apps/dashboard/models.py new file mode 100644 index 000000000000..71a836239075 --- /dev/null +++ b/cvat/apps/dashboard/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/jstree.js b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/jstree.js new file mode 100644 index 000000000000..aee295e2b313 --- /dev/null +++ b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/jstree.js @@ -0,0 +1,8589 @@ +/*globals jQuery, define, module, exports, require, window, document, postMessage */ +(function (factory) { + "use strict"; + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } + else if(typeof module !== 'undefined' && module.exports) { + module.exports = factory(require('jquery')); + } + else { + factory(jQuery); + } +}(function ($, undefined) { + "use strict"; +/*! + * jsTree 3.3.5 + * http://jstree.com/ + * + * Copyright (c) 2014 Ivan Bozhanov (http://vakata.com) + * + * Licensed same as jquery - under the terms of the MIT License + * http://www.opensource.org/licenses/mit-license.php + */ +/*! + * if using jslint please allow for the jQuery global and use following options: + * jslint: loopfunc: true, browser: true, ass: true, bitwise: true, continue: true, nomen: true, plusplus: true, regexp: true, unparam: true, todo: true, white: true + */ +/*jshint -W083 */ + + // prevent another load? maybe there is a better way? + if($.jstree) { + return; + } + + /** + * ### jsTree core functionality + */ + + // internal variables + var instance_counter = 0, + ccp_node = false, + ccp_mode = false, + ccp_inst = false, + themes_loaded = [], + src = $('script:last').attr('src'), + document = window.document; // local variable is always faster to access then a global + + /** + * holds all jstree related functions and variables, including the actual class and methods to create, access and manipulate instances. + * @name $.jstree + */ + $.jstree = { + /** + * specifies the jstree version in use + * @name $.jstree.version + */ + version : '3.3.5', + /** + * holds all the default options used when creating new instances + * @name $.jstree.defaults + */ + defaults : { + /** + * configure which plugins will be active on an instance. Should be an array of strings, where each element is a plugin name. The default is `[]` + * @name $.jstree.defaults.plugins + */ + plugins : [] + }, + /** + * stores all loaded jstree plugins (used internally) + * @name $.jstree.plugins + */ + plugins : {}, + path : src && src.indexOf('/') !== -1 ? src.replace(/\/[^\/]+$/,'') : '', + idregex : /[\\:&!^|()\[\]<>@*'+~#";.,=\- \/${}%?`]/g, + root : '#' + }; + + /** + * creates a jstree instance + * @name $.jstree.create(el [, options]) + * @param {DOMElement|jQuery|String} el the element to create the instance on, can be jQuery extended or a selector + * @param {Object} options options for this instance (extends `$.jstree.defaults`) + * @return {jsTree} the new instance + */ + $.jstree.create = function (el, options) { + var tmp = new $.jstree.core(++instance_counter), + opt = options; + options = $.extend(true, {}, $.jstree.defaults, options); + if(opt && opt.plugins) { + options.plugins = opt.plugins; + } + $.each(options.plugins, function (i, k) { + if(i !== 'core') { + tmp = tmp.plugin(k, options[k]); + } + }); + $(el).data('jstree', tmp); + tmp.init(el, options); + return tmp; + }; + /** + * remove all traces of jstree from the DOM and destroy all instances + * @name $.jstree.destroy() + */ + $.jstree.destroy = function () { + $('.jstree:jstree').jstree('destroy'); + $(document).off('.jstree'); + }; + /** + * the jstree class constructor, used only internally + * @private + * @name $.jstree.core(id) + * @param {Number} id this instance's index + */ + $.jstree.core = function (id) { + this._id = id; + this._cnt = 0; + this._wrk = null; + this._data = { + core : { + themes : { + name : false, + dots : false, + icons : false, + ellipsis : false + }, + selected : [], + last_error : {}, + working : false, + worker_queue : [], + focused : null + } + }; + }; + /** + * get a reference to an existing instance + * + * __Examples__ + * + * // provided a container with an ID of "tree", and a nested node with an ID of "branch" + * // all of there will return the same instance + * $.jstree.reference('tree'); + * $.jstree.reference('#tree'); + * $.jstree.reference($('#tree')); + * $.jstree.reference(document.getElementByID('tree')); + * $.jstree.reference('branch'); + * $.jstree.reference('#branch'); + * $.jstree.reference($('#branch')); + * $.jstree.reference(document.getElementByID('branch')); + * + * @name $.jstree.reference(needle) + * @param {DOMElement|jQuery|String} needle + * @return {jsTree|null} the instance or `null` if not found + */ + $.jstree.reference = function (needle) { + var tmp = null, + obj = null; + if(needle && needle.id && (!needle.tagName || !needle.nodeType)) { needle = needle.id; } + + if(!obj || !obj.length) { + try { obj = $(needle); } catch (ignore) { } + } + if(!obj || !obj.length) { + try { obj = $('#' + needle.replace($.jstree.idregex,'\\$&')); } catch (ignore) { } + } + if(obj && obj.length && (obj = obj.closest('.jstree')).length && (obj = obj.data('jstree'))) { + tmp = obj; + } + else { + $('.jstree').each(function () { + var inst = $(this).data('jstree'); + if(inst && inst._model.data[needle]) { + tmp = inst; + return false; + } + }); + } + return tmp; + }; + /** + * Create an instance, get an instance or invoke a command on a instance. + * + * If there is no instance associated with the current node a new one is created and `arg` is used to extend `$.jstree.defaults` for this new instance. There would be no return value (chaining is not broken). + * + * If there is an existing instance and `arg` is a string the command specified by `arg` is executed on the instance, with any additional arguments passed to the function. If the function returns a value it will be returned (chaining could break depending on function). + * + * If there is an existing instance and `arg` is not a string the instance itself is returned (similar to `$.jstree.reference`). + * + * In any other case - nothing is returned and chaining is not broken. + * + * __Examples__ + * + * $('#tree1').jstree(); // creates an instance + * $('#tree2').jstree({ plugins : [] }); // create an instance with some options + * $('#tree1').jstree('open_node', '#branch_1'); // call a method on an existing instance, passing additional arguments + * $('#tree2').jstree(); // get an existing instance (or create an instance) + * $('#tree2').jstree(true); // get an existing instance (will not create new instance) + * $('#branch_1').jstree().select_node('#branch_1'); // get an instance (using a nested element and call a method) + * + * @name $().jstree([arg]) + * @param {String|Object} arg + * @return {Mixed} + */ + $.fn.jstree = function (arg) { + // check for string argument + var is_method = (typeof arg === 'string'), + args = Array.prototype.slice.call(arguments, 1), + result = null; + if(arg === true && !this.length) { return false; } + this.each(function () { + // get the instance (if there is one) and method (if it exists) + var instance = $.jstree.reference(this), + method = is_method && instance ? instance[arg] : null; + // if calling a method, and method is available - execute on the instance + result = is_method && method ? + method.apply(instance, args) : + null; + // if there is no instance and no method is being called - create one + if(!instance && !is_method && (arg === undefined || $.isPlainObject(arg))) { + $.jstree.create(this, arg); + } + // if there is an instance and no method is called - return the instance + if( (instance && !is_method) || arg === true ) { + result = instance || false; + } + // if there was a method call which returned a result - break and return the value + if(result !== null && result !== undefined) { + return false; + } + }); + // if there was a method call with a valid return value - return that, otherwise continue the chain + return result !== null && result !== undefined ? + result : this; + }; + /** + * used to find elements containing an instance + * + * __Examples__ + * + * $('div:jstree').each(function () { + * $(this).jstree('destroy'); + * }); + * + * @name $(':jstree') + * @return {jQuery} + */ + $.expr.pseudos.jstree = $.expr.createPseudo(function(search) { + return function(a) { + return $(a).hasClass('jstree') && + $(a).data('jstree') !== undefined; + }; + }); + + /** + * stores all defaults for the core + * @name $.jstree.defaults.core + */ + $.jstree.defaults.core = { + /** + * data configuration + * + * If left as `false` the HTML inside the jstree container element is used to populate the tree (that should be an unordered list with list items). + * + * You can also pass in a HTML string or a JSON array here. + * + * It is possible to pass in a standard jQuery-like AJAX config and jstree will automatically determine if the response is JSON or HTML and use that to populate the tree. + * In addition to the standard jQuery ajax options here you can suppy functions for `data` and `url`, the functions will be run in the current instance's scope and a param will be passed indicating which node is being loaded, the return value of those functions will be used. + * + * The last option is to specify a function, that function will receive the node being loaded as argument and a second param which is a function which should be called with the result. + * + * __Examples__ + * + * // AJAX + * $('#tree').jstree({ + * 'core' : { + * 'data' : { + * 'url' : '/get/children/', + * 'data' : function (node) { + * return { 'id' : node.id }; + * } + * } + * }); + * + * // direct data + * $('#tree').jstree({ + * 'core' : { + * 'data' : [ + * 'Simple root node', + * { + * 'id' : 'node_2', + * 'text' : 'Root node with options', + * 'state' : { 'opened' : true, 'selected' : true }, + * 'children' : [ { 'text' : 'Child 1' }, 'Child 2'] + * } + * ] + * } + * }); + * + * // function + * $('#tree').jstree({ + * 'core' : { + * 'data' : function (obj, callback) { + * callback.call(this, ['Root 1', 'Root 2']); + * } + * }); + * + * @name $.jstree.defaults.core.data + */ + data : false, + /** + * configure the various strings used throughout the tree + * + * You can use an object where the key is the string you need to replace and the value is your replacement. + * Another option is to specify a function which will be called with an argument of the needed string and should return the replacement. + * If left as `false` no replacement is made. + * + * __Examples__ + * + * $('#tree').jstree({ + * 'core' : { + * 'strings' : { + * 'Loading ...' : 'Please wait ...' + * } + * } + * }); + * + * @name $.jstree.defaults.core.strings + */ + strings : false, + /** + * determines what happens when a user tries to modify the structure of the tree + * If left as `false` all operations like create, rename, delete, move or copy are prevented. + * You can set this to `true` to allow all interactions or use a function to have better control. + * + * __Examples__ + * + * $('#tree').jstree({ + * 'core' : { + * 'check_callback' : function (operation, node, node_parent, node_position, more) { + * // operation can be 'create_node', 'rename_node', 'delete_node', 'move_node', 'copy_node' or 'edit' + * // in case of 'rename_node' node_position is filled with the new node name + * return operation === 'rename_node' ? true : false; + * } + * } + * }); + * + * @name $.jstree.defaults.core.check_callback + */ + check_callback : false, + /** + * a callback called with a single object parameter in the instance's scope when something goes wrong (operation prevented, ajax failed, etc) + * @name $.jstree.defaults.core.error + */ + error : $.noop, + /** + * the open / close animation duration in milliseconds - set this to `false` to disable the animation (default is `200`) + * @name $.jstree.defaults.core.animation + */ + animation : 200, + /** + * a boolean indicating if multiple nodes can be selected + * @name $.jstree.defaults.core.multiple + */ + multiple : true, + /** + * theme configuration object + * @name $.jstree.defaults.core.themes + */ + themes : { + /** + * the name of the theme to use (if left as `false` the default theme is used) + * @name $.jstree.defaults.core.themes.name + */ + name : false, + /** + * the URL of the theme's CSS file, leave this as `false` if you have manually included the theme CSS (recommended). You can set this to `true` too which will try to autoload the theme. + * @name $.jstree.defaults.core.themes.url + */ + url : false, + /** + * the location of all jstree themes - only used if `url` is set to `true` + * @name $.jstree.defaults.core.themes.dir + */ + dir : false, + /** + * a boolean indicating if connecting dots are shown + * @name $.jstree.defaults.core.themes.dots + */ + dots : true, + /** + * a boolean indicating if node icons are shown + * @name $.jstree.defaults.core.themes.icons + */ + icons : true, + /** + * a boolean indicating if node ellipsis should be shown - this only works with a fixed with on the container + * @name $.jstree.defaults.core.themes.ellipsis + */ + ellipsis : false, + /** + * a boolean indicating if the tree background is striped + * @name $.jstree.defaults.core.themes.stripes + */ + stripes : false, + /** + * a string (or boolean `false`) specifying the theme variant to use (if the theme supports variants) + * @name $.jstree.defaults.core.themes.variant + */ + variant : false, + /** + * a boolean specifying if a reponsive version of the theme should kick in on smaller screens (if the theme supports it). Defaults to `false`. + * @name $.jstree.defaults.core.themes.responsive + */ + responsive : false + }, + /** + * if left as `true` all parents of all selected nodes will be opened once the tree loads (so that all selected nodes are visible to the user) + * @name $.jstree.defaults.core.expand_selected_onload + */ + expand_selected_onload : true, + /** + * if left as `true` web workers will be used to parse incoming JSON data where possible, so that the UI will not be blocked by large requests. Workers are however about 30% slower. Defaults to `true` + * @name $.jstree.defaults.core.worker + */ + worker : true, + /** + * Force node text to plain text (and escape HTML). Defaults to `false` + * @name $.jstree.defaults.core.force_text + */ + force_text : false, + /** + * Should the node should be toggled if the text is double clicked . Defaults to `true` + * @name $.jstree.defaults.core.dblclick_toggle + */ + dblclick_toggle : true, + /** + * Should the loaded nodes be part of the state. Defaults to `false` + * @name $.jstree.defaults.core.loaded_state + */ + loaded_state : false, + /** + * Should the last active node be focused when the tree container is blurred and the focused again. This helps working with screen readers. Defaults to `true` + * @name $.jstree.defaults.core.restore_focus + */ + restore_focus : true, + /** + * Default keyboard shortcuts (an object where each key is the button name or combo - like 'enter', 'ctrl-space', 'p', etc and the value is the function to execute in the instance's scope) + * @name $.jstree.defaults.core.keyboard + */ + keyboard : { + 'ctrl-space': function (e) { + // aria defines space only with Ctrl + e.type = "click"; + $(e.currentTarget).trigger(e); + }, + 'enter': function (e) { + // enter + e.type = "click"; + $(e.currentTarget).trigger(e); + }, + 'left': function (e) { + // left + e.preventDefault(); + if(this.is_open(e.currentTarget)) { + this.close_node(e.currentTarget); + } + else { + var o = this.get_parent(e.currentTarget); + if(o && o.id !== $.jstree.root) { this.get_node(o, true).children('.jstree-anchor').focus(); } + } + }, + 'up': function (e) { + // up + e.preventDefault(); + var o = this.get_prev_dom(e.currentTarget); + if(o && o.length) { o.children('.jstree-anchor').focus(); } + }, + 'right': function (e) { + // right + e.preventDefault(); + if(this.is_closed(e.currentTarget)) { + this.open_node(e.currentTarget, function (o) { this.get_node(o, true).children('.jstree-anchor').focus(); }); + } + else if (this.is_open(e.currentTarget)) { + var o = this.get_node(e.currentTarget, true).children('.jstree-children')[0]; + if(o) { $(this._firstChild(o)).children('.jstree-anchor').focus(); } + } + }, + 'down': function (e) { + // down + e.preventDefault(); + var o = this.get_next_dom(e.currentTarget); + if(o && o.length) { o.children('.jstree-anchor').focus(); } + }, + '*': function (e) { + // aria defines * on numpad as open_all - not very common + this.open_all(); + }, + 'home': function (e) { + // home + e.preventDefault(); + var o = this._firstChild(this.get_container_ul()[0]); + if(o) { $(o).children('.jstree-anchor').filter(':visible').focus(); } + }, + 'end': function (e) { + // end + e.preventDefault(); + this.element.find('.jstree-anchor').filter(':visible').last().focus(); + }, + 'f2': function (e) { + // f2 - safe to include - if check_callback is false it will fail + e.preventDefault(); + this.edit(e.currentTarget); + } + } + }; + $.jstree.core.prototype = { + /** + * used to decorate an instance with a plugin. Used internally. + * @private + * @name plugin(deco [, opts]) + * @param {String} deco the plugin to decorate with + * @param {Object} opts options for the plugin + * @return {jsTree} + */ + plugin : function (deco, opts) { + var Child = $.jstree.plugins[deco]; + if(Child) { + this._data[deco] = {}; + Child.prototype = this; + return new Child(opts, this); + } + return this; + }, + /** + * initialize the instance. Used internally. + * @private + * @name init(el, optons) + * @param {DOMElement|jQuery|String} el the element we are transforming + * @param {Object} options options for this instance + * @trigger init.jstree, loading.jstree, loaded.jstree, ready.jstree, changed.jstree + */ + init : function (el, options) { + this._model = { + data : {}, + changed : [], + force_full_redraw : false, + redraw_timeout : false, + default_state : { + loaded : true, + opened : false, + selected : false, + disabled : false + } + }; + this._model.data[$.jstree.root] = { + id : $.jstree.root, + parent : null, + parents : [], + children : [], + children_d : [], + state : { loaded : false } + }; + + this.element = $(el).addClass('jstree jstree-' + this._id); + this.settings = options; + + this._data.core.ready = false; + this._data.core.loaded = false; + this._data.core.rtl = (this.element.css("direction") === "rtl"); + this.element[this._data.core.rtl ? 'addClass' : 'removeClass']("jstree-rtl"); + this.element.attr('role','tree'); + if(this.settings.core.multiple) { + this.element.attr('aria-multiselectable', true); + } + if(!this.element.attr('tabindex')) { + this.element.attr('tabindex','0'); + } + + this.bind(); + /** + * triggered after all events are bound + * @event + * @name init.jstree + */ + this.trigger("init"); + + this._data.core.original_container_html = this.element.find(" > ul > li").clone(true); + this._data.core.original_container_html + .find("li").addBack() + .contents().filter(function() { + return this.nodeType === 3 && (!this.nodeValue || /^\s+$/.test(this.nodeValue)); + }) + .remove(); + this.element.html("<"+"ul class='jstree-container-ul jstree-children' role='group'><"+"li id='j"+this._id+"_loading' class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='tree-item'><"+"a class='jstree-anchor' href='#'>" + this.get_string("Loading ...") + ""); + this.element.attr('aria-activedescendant','j' + this._id + '_loading'); + this._data.core.li_height = this.get_container_ul().children("li").first().outerHeight() || 24; + this._data.core.node = this._create_prototype_node(); + /** + * triggered after the loading text is shown and before loading starts + * @event + * @name loading.jstree + */ + this.trigger("loading"); + this.load_node($.jstree.root); + }, + /** + * destroy an instance + * @name destroy() + * @param {Boolean} keep_html if not set to `true` the container will be emptied, otherwise the current DOM elements will be kept intact + */ + destroy : function (keep_html) { + /** + * triggered before the tree is destroyed + * @event + * @name destroy.jstree + */ + this.trigger("destroy"); + if(this._wrk) { + try { + window.URL.revokeObjectURL(this._wrk); + this._wrk = null; + } + catch (ignore) { } + } + if(!keep_html) { this.element.empty(); } + this.teardown(); + }, + /** + * Create a prototype node + * @name _create_prototype_node() + * @return {DOMElement} + */ + _create_prototype_node : function () { + var _node = document.createElement('LI'), _temp1, _temp2; + _node.setAttribute('role', 'treeitem'); + _temp1 = document.createElement('I'); + _temp1.className = 'jstree-icon jstree-ocl'; + _temp1.setAttribute('role', 'presentation'); + _node.appendChild(_temp1); + _temp1 = document.createElement('A'); + _temp1.className = 'jstree-anchor'; + _temp1.setAttribute('href','#'); + _temp1.setAttribute('tabindex','-1'); + _temp2 = document.createElement('I'); + _temp2.className = 'jstree-icon jstree-themeicon'; + _temp2.setAttribute('role', 'presentation'); + _temp1.appendChild(_temp2); + _node.appendChild(_temp1); + _temp1 = _temp2 = null; + + return _node; + }, + _kbevent_to_func : function (e) { + var keys = { + 8: "Backspace", 9: "Tab", 13: "Return", 19: "Pause", 27: "Esc", + 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", + 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "Print", 45: "Insert", + 46: "Delete", 96: "Numpad0", 97: "Numpad1", 98: "Numpad2", 99 : "Numpad3", + 100: "Numpad4", 101: "Numpad5", 102: "Numpad6", 103: "Numpad7", + 104: "Numpad8", 105: "Numpad9", '-13': "NumpadEnter", 112: "F1", + 113: "F2", 114: "F3", 115: "F4", 116: "F5", 117: "F6", 118: "F7", + 119: "F8", 120: "F9", 121: "F10", 122: "F11", 123: "F12", 144: "Numlock", + 145: "Scrolllock", 16: 'Shift', 17: 'Ctrl', 18: 'Alt', + 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', + 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a', + 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', + 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', + 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', + 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', + 186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', + 219: '[', 220: '\\',221: ']', 222: "'", 111: '/', 106: '*', 173: '-' + }; + var parts = []; + if (e.ctrlKey) { parts.push('ctrl'); } + if (e.altKey) { parts.push('alt'); } + if (e.shiftKey) { parts.push('shift'); } + parts.push(keys[e.which] || e.which); + parts = parts.sort().join('-').toLowerCase(); + + var kb = this.settings.core.keyboard, i, tmp; + for (i in kb) { + if (kb.hasOwnProperty(i)) { + tmp = i; + if (tmp !== '-' && tmp !== '+') { + tmp = tmp.replace('--', '-MINUS').replace('+-', '-MINUS').replace('++', '-PLUS').replace('-+', '-PLUS'); + tmp = tmp.split(/-|\+/).sort().join('-').replace('MINUS', '-').replace('PLUS', '+').toLowerCase(); + } + if (tmp === parts) { + return kb[i]; + } + } + } + return null; + }, + /** + * part of the destroying of an instance. Used internally. + * @private + * @name teardown() + */ + teardown : function () { + this.unbind(); + this.element + .removeClass('jstree') + .removeData('jstree') + .find("[class^='jstree']") + .addBack() + .attr("class", function () { return this.className.replace(/jstree[^ ]*|$/ig,''); }); + this.element = null; + }, + /** + * bind all events. Used internally. + * @private + * @name bind() + */ + bind : function () { + var word = '', + tout = null, + was_click = 0; + this.element + .on("dblclick.jstree", function (e) { + if(e.target.tagName && e.target.tagName.toLowerCase() === "input") { return true; } + if(document.selection && document.selection.empty) { + document.selection.empty(); + } + else { + if(window.getSelection) { + var sel = window.getSelection(); + try { + sel.removeAllRanges(); + sel.collapse(); + } catch (ignore) { } + } + } + }) + .on("mousedown.jstree", $.proxy(function (e) { + if(e.target === this.element[0]) { + e.preventDefault(); // prevent losing focus when clicking scroll arrows (FF, Chrome) + was_click = +(new Date()); // ie does not allow to prevent losing focus + } + }, this)) + .on("mousedown.jstree", ".jstree-ocl", function (e) { + e.preventDefault(); // prevent any node inside from losing focus when clicking the open/close icon + }) + .on("click.jstree", ".jstree-ocl", $.proxy(function (e) { + this.toggle_node(e.target); + }, this)) + .on("dblclick.jstree", ".jstree-anchor", $.proxy(function (e) { + if(e.target.tagName && e.target.tagName.toLowerCase() === "input") { return true; } + if(this.settings.core.dblclick_toggle) { + this.toggle_node(e.target); + } + }, this)) + .on("click.jstree", ".jstree-anchor", $.proxy(function (e) { + e.preventDefault(); + if(e.currentTarget !== document.activeElement) { $(e.currentTarget).focus(); } + this.activate_node(e.currentTarget, e); + }, this)) + .on('keydown.jstree', '.jstree-anchor', $.proxy(function (e) { + if(e.target.tagName && e.target.tagName.toLowerCase() === "input") { return true; } + if(this._data.core.rtl) { + if(e.which === 37) { e.which = 39; } + else if(e.which === 39) { e.which = 37; } + } + var f = this._kbevent_to_func(e); + if (f) { + var r = f.call(this, e); + if (r === false || r === true) { + return r; + } + } + }, this)) + .on("load_node.jstree", $.proxy(function (e, data) { + if(data.status) { + if(data.node.id === $.jstree.root && !this._data.core.loaded) { + this._data.core.loaded = true; + if(this._firstChild(this.get_container_ul()[0])) { + this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id); + } + /** + * triggered after the root node is loaded for the first time + * @event + * @name loaded.jstree + */ + this.trigger("loaded"); + } + if(!this._data.core.ready) { + setTimeout($.proxy(function() { + if(this.element && !this.get_container_ul().find('.jstree-loading').length) { + this._data.core.ready = true; + if(this._data.core.selected.length) { + if(this.settings.core.expand_selected_onload) { + var tmp = [], i, j; + for(i = 0, j = this._data.core.selected.length; i < j; i++) { + tmp = tmp.concat(this._model.data[this._data.core.selected[i]].parents); + } + tmp = $.vakata.array_unique(tmp); + for(i = 0, j = tmp.length; i < j; i++) { + this.open_node(tmp[i], false, 0); + } + } + this.trigger('changed', { 'action' : 'ready', 'selected' : this._data.core.selected }); + } + /** + * triggered after all nodes are finished loading + * @event + * @name ready.jstree + */ + this.trigger("ready"); + } + }, this), 0); + } + } + }, this)) + // quick searching when the tree is focused + .on('keypress.jstree', $.proxy(function (e) { + if(e.target.tagName && e.target.tagName.toLowerCase() === "input") { return true; } + if(tout) { clearTimeout(tout); } + tout = setTimeout(function () { + word = ''; + }, 500); + + var chr = String.fromCharCode(e.which).toLowerCase(), + col = this.element.find('.jstree-anchor').filter(':visible'), + ind = col.index(document.activeElement) || 0, + end = false; + word += chr; + + // match for whole word from current node down (including the current node) + if(word.length > 1) { + col.slice(ind).each($.proxy(function (i, v) { + if($(v).text().toLowerCase().indexOf(word) === 0) { + $(v).focus(); + end = true; + return false; + } + }, this)); + if(end) { return; } + + // match for whole word from the beginning of the tree + col.slice(0, ind).each($.proxy(function (i, v) { + if($(v).text().toLowerCase().indexOf(word) === 0) { + $(v).focus(); + end = true; + return false; + } + }, this)); + if(end) { return; } + } + // list nodes that start with that letter (only if word consists of a single char) + if(new RegExp('^' + chr.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '+$').test(word)) { + // search for the next node starting with that letter + col.slice(ind + 1).each($.proxy(function (i, v) { + if($(v).text().toLowerCase().charAt(0) === chr) { + $(v).focus(); + end = true; + return false; + } + }, this)); + if(end) { return; } + + // search from the beginning + col.slice(0, ind + 1).each($.proxy(function (i, v) { + if($(v).text().toLowerCase().charAt(0) === chr) { + $(v).focus(); + end = true; + return false; + } + }, this)); + if(end) { return; } + } + }, this)) + // THEME RELATED + .on("init.jstree", $.proxy(function () { + var s = this.settings.core.themes; + this._data.core.themes.dots = s.dots; + this._data.core.themes.stripes = s.stripes; + this._data.core.themes.icons = s.icons; + this._data.core.themes.ellipsis = s.ellipsis; + this.set_theme(s.name || "default", s.url); + this.set_theme_variant(s.variant); + }, this)) + .on("loading.jstree", $.proxy(function () { + this[ this._data.core.themes.dots ? "show_dots" : "hide_dots" ](); + this[ this._data.core.themes.icons ? "show_icons" : "hide_icons" ](); + this[ this._data.core.themes.stripes ? "show_stripes" : "hide_stripes" ](); + this[ this._data.core.themes.ellipsis ? "show_ellipsis" : "hide_ellipsis" ](); + }, this)) + .on('blur.jstree', '.jstree-anchor', $.proxy(function (e) { + this._data.core.focused = null; + $(e.currentTarget).filter('.jstree-hovered').mouseleave(); + this.element.attr('tabindex', '0'); + }, this)) + .on('focus.jstree', '.jstree-anchor', $.proxy(function (e) { + var tmp = this.get_node(e.currentTarget); + if(tmp && tmp.id) { + this._data.core.focused = tmp.id; + } + this.element.find('.jstree-hovered').not(e.currentTarget).mouseleave(); + $(e.currentTarget).mouseenter(); + this.element.attr('tabindex', '-1'); + }, this)) + .on('focus.jstree', $.proxy(function () { + if(+(new Date()) - was_click > 500 && !this._data.core.focused && this.settings.core.restore_focus) { + was_click = 0; + var act = this.get_node(this.element.attr('aria-activedescendant'), true); + if(act) { + act.find('> .jstree-anchor').focus(); + } + } + }, this)) + .on('mouseenter.jstree', '.jstree-anchor', $.proxy(function (e) { + this.hover_node(e.currentTarget); + }, this)) + .on('mouseleave.jstree', '.jstree-anchor', $.proxy(function (e) { + this.dehover_node(e.currentTarget); + }, this)); + }, + /** + * part of the destroying of an instance. Used internally. + * @private + * @name unbind() + */ + unbind : function () { + this.element.off('.jstree'); + $(document).off('.jstree-' + this._id); + }, + /** + * trigger an event. Used internally. + * @private + * @name trigger(ev [, data]) + * @param {String} ev the name of the event to trigger + * @param {Object} data additional data to pass with the event + */ + trigger : function (ev, data) { + if(!data) { + data = {}; + } + data.instance = this; + this.element.triggerHandler(ev.replace('.jstree','') + '.jstree', data); + }, + /** + * returns the jQuery extended instance container + * @name get_container() + * @return {jQuery} + */ + get_container : function () { + return this.element; + }, + /** + * returns the jQuery extended main UL node inside the instance container. Used internally. + * @private + * @name get_container_ul() + * @return {jQuery} + */ + get_container_ul : function () { + return this.element.children(".jstree-children").first(); + }, + /** + * gets string replacements (localization). Used internally. + * @private + * @name get_string(key) + * @param {String} key + * @return {String} + */ + get_string : function (key) { + var a = this.settings.core.strings; + if($.isFunction(a)) { return a.call(this, key); } + if(a && a[key]) { return a[key]; } + return key; + }, + /** + * gets the first child of a DOM node. Used internally. + * @private + * @name _firstChild(dom) + * @param {DOMElement} dom + * @return {DOMElement} + */ + _firstChild : function (dom) { + dom = dom ? dom.firstChild : null; + while(dom !== null && dom.nodeType !== 1) { + dom = dom.nextSibling; + } + return dom; + }, + /** + * gets the next sibling of a DOM node. Used internally. + * @private + * @name _nextSibling(dom) + * @param {DOMElement} dom + * @return {DOMElement} + */ + _nextSibling : function (dom) { + dom = dom ? dom.nextSibling : null; + while(dom !== null && dom.nodeType !== 1) { + dom = dom.nextSibling; + } + return dom; + }, + /** + * gets the previous sibling of a DOM node. Used internally. + * @private + * @name _previousSibling(dom) + * @param {DOMElement} dom + * @return {DOMElement} + */ + _previousSibling : function (dom) { + dom = dom ? dom.previousSibling : null; + while(dom !== null && dom.nodeType !== 1) { + dom = dom.previousSibling; + } + return dom; + }, + /** + * get the JSON representation of a node (or the actual jQuery extended DOM node) by using any input (child DOM element, ID string, selector, etc) + * @name get_node(obj [, as_dom]) + * @param {mixed} obj + * @param {Boolean} as_dom + * @return {Object|jQuery} + */ + get_node : function (obj, as_dom) { + if(obj && obj.id) { + obj = obj.id; + } + var dom; + try { + if(this._model.data[obj]) { + obj = this._model.data[obj]; + } + else if(typeof obj === "string" && this._model.data[obj.replace(/^#/, '')]) { + obj = this._model.data[obj.replace(/^#/, '')]; + } + else if(typeof obj === "string" && (dom = $('#' + obj.replace($.jstree.idregex,'\\$&'), this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) { + obj = this._model.data[dom.closest('.jstree-node').attr('id')]; + } + else if((dom = $(obj, this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) { + obj = this._model.data[dom.closest('.jstree-node').attr('id')]; + } + else if((dom = $(obj, this.element)).length && dom.hasClass('jstree')) { + obj = this._model.data[$.jstree.root]; + } + else { + return false; + } + + if(as_dom) { + obj = obj.id === $.jstree.root ? this.element : $('#' + obj.id.replace($.jstree.idregex,'\\$&'), this.element); + } + return obj; + } catch (ex) { return false; } + }, + /** + * get the path to a node, either consisting of node texts, or of node IDs, optionally glued together (otherwise an array) + * @name get_path(obj [, glue, ids]) + * @param {mixed} obj the node + * @param {String} glue if you want the path as a string - pass the glue here (for example '/'), if a falsy value is supplied here, an array is returned + * @param {Boolean} ids if set to true build the path using ID, otherwise node text is used + * @return {mixed} + */ + get_path : function (obj, glue, ids) { + obj = obj.parents ? obj : this.get_node(obj); + if(!obj || obj.id === $.jstree.root || !obj.parents) { + return false; + } + var i, j, p = []; + p.push(ids ? obj.id : obj.text); + for(i = 0, j = obj.parents.length; i < j; i++) { + p.push(ids ? obj.parents[i] : this.get_text(obj.parents[i])); + } + p = p.reverse().slice(1); + return glue ? p.join(glue) : p; + }, + /** + * get the next visible node that is below the `obj` node. If `strict` is set to `true` only sibling nodes are returned. + * @name get_next_dom(obj [, strict]) + * @param {mixed} obj + * @param {Boolean} strict + * @return {jQuery} + */ + get_next_dom : function (obj, strict) { + var tmp; + obj = this.get_node(obj, true); + if(obj[0] === this.element[0]) { + tmp = this._firstChild(this.get_container_ul()[0]); + while (tmp && tmp.offsetHeight === 0) { + tmp = this._nextSibling(tmp); + } + return tmp ? $(tmp) : false; + } + if(!obj || !obj.length) { + return false; + } + if(strict) { + tmp = obj[0]; + do { + tmp = this._nextSibling(tmp); + } while (tmp && tmp.offsetHeight === 0); + return tmp ? $(tmp) : false; + } + if(obj.hasClass("jstree-open")) { + tmp = this._firstChild(obj.children('.jstree-children')[0]); + while (tmp && tmp.offsetHeight === 0) { + tmp = this._nextSibling(tmp); + } + if(tmp !== null) { + return $(tmp); + } + } + tmp = obj[0]; + do { + tmp = this._nextSibling(tmp); + } while (tmp && tmp.offsetHeight === 0); + if(tmp !== null) { + return $(tmp); + } + return obj.parentsUntil(".jstree",".jstree-node").nextAll(".jstree-node:visible").first(); + }, + /** + * get the previous visible node that is above the `obj` node. If `strict` is set to `true` only sibling nodes are returned. + * @name get_prev_dom(obj [, strict]) + * @param {mixed} obj + * @param {Boolean} strict + * @return {jQuery} + */ + get_prev_dom : function (obj, strict) { + var tmp; + obj = this.get_node(obj, true); + if(obj[0] === this.element[0]) { + tmp = this.get_container_ul()[0].lastChild; + while (tmp && tmp.offsetHeight === 0) { + tmp = this._previousSibling(tmp); + } + return tmp ? $(tmp) : false; + } + if(!obj || !obj.length) { + return false; + } + if(strict) { + tmp = obj[0]; + do { + tmp = this._previousSibling(tmp); + } while (tmp && tmp.offsetHeight === 0); + return tmp ? $(tmp) : false; + } + tmp = obj[0]; + do { + tmp = this._previousSibling(tmp); + } while (tmp && tmp.offsetHeight === 0); + if(tmp !== null) { + obj = $(tmp); + while(obj.hasClass("jstree-open")) { + obj = obj.children(".jstree-children").first().children(".jstree-node:visible:last"); + } + return obj; + } + tmp = obj[0].parentNode.parentNode; + return tmp && tmp.className && tmp.className.indexOf('jstree-node') !== -1 ? $(tmp) : false; + }, + /** + * get the parent ID of a node + * @name get_parent(obj) + * @param {mixed} obj + * @return {String} + */ + get_parent : function (obj) { + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + return obj.parent; + }, + /** + * get a jQuery collection of all the children of a node (node must be rendered), returns false on error + * @name get_children_dom(obj) + * @param {mixed} obj + * @return {jQuery} + */ + get_children_dom : function (obj) { + obj = this.get_node(obj, true); + if(obj[0] === this.element[0]) { + return this.get_container_ul().children(".jstree-node"); + } + if(!obj || !obj.length) { + return false; + } + return obj.children(".jstree-children").children(".jstree-node"); + }, + /** + * checks if a node has children + * @name is_parent(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_parent : function (obj) { + obj = this.get_node(obj); + return obj && (obj.state.loaded === false || obj.children.length > 0); + }, + /** + * checks if a node is loaded (its children are available) + * @name is_loaded(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_loaded : function (obj) { + obj = this.get_node(obj); + return obj && obj.state.loaded; + }, + /** + * check if a node is currently loading (fetching children) + * @name is_loading(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_loading : function (obj) { + obj = this.get_node(obj); + return obj && obj.state && obj.state.loading; + }, + /** + * check if a node is opened + * @name is_open(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_open : function (obj) { + obj = this.get_node(obj); + return obj && obj.state.opened; + }, + /** + * check if a node is in a closed state + * @name is_closed(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_closed : function (obj) { + obj = this.get_node(obj); + return obj && this.is_parent(obj) && !obj.state.opened; + }, + /** + * check if a node has no children + * @name is_leaf(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_leaf : function (obj) { + return !this.is_parent(obj); + }, + /** + * loads a node (fetches its children using the `core.data` setting). Multiple nodes can be passed to by using an array. + * @name load_node(obj [, callback]) + * @param {mixed} obj + * @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives two arguments - the node and a boolean status + * @return {Boolean} + * @trigger load_node.jstree + */ + load_node : function (obj, callback) { + var k, l, i, j, c; + if($.isArray(obj)) { + this._load_nodes(obj.slice(), callback); + return true; + } + obj = this.get_node(obj); + if(!obj) { + if(callback) { callback.call(this, obj, false); } + return false; + } + // if(obj.state.loading) { } // the node is already loading - just wait for it to load and invoke callback? but if called implicitly it should be loaded again? + if(obj.state.loaded) { + obj.state.loaded = false; + for(i = 0, j = obj.parents.length; i < j; i++) { + this._model.data[obj.parents[i]].children_d = $.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function (v) { + return $.inArray(v, obj.children_d) === -1; + }); + } + for(k = 0, l = obj.children_d.length; k < l; k++) { + if(this._model.data[obj.children_d[k]].state.selected) { + c = true; + } + delete this._model.data[obj.children_d[k]]; + } + if (c) { + this._data.core.selected = $.vakata.array_filter(this._data.core.selected, function (v) { + return $.inArray(v, obj.children_d) === -1; + }); + } + obj.children = []; + obj.children_d = []; + if(c) { + this.trigger('changed', { 'action' : 'load_node', 'node' : obj, 'selected' : this._data.core.selected }); + } + } + obj.state.failed = false; + obj.state.loading = true; + this.get_node(obj, true).addClass("jstree-loading").attr('aria-busy',true); + this._load_node(obj, $.proxy(function (status) { + obj = this._model.data[obj.id]; + obj.state.loading = false; + obj.state.loaded = status; + obj.state.failed = !obj.state.loaded; + var dom = this.get_node(obj, true), i = 0, j = 0, m = this._model.data, has_children = false; + for(i = 0, j = obj.children.length; i < j; i++) { + if(m[obj.children[i]] && !m[obj.children[i]].state.hidden) { + has_children = true; + break; + } + } + if(obj.state.loaded && dom && dom.length) { + dom.removeClass('jstree-closed jstree-open jstree-leaf'); + if (!has_children) { + dom.addClass('jstree-leaf'); + } + else { + if (obj.id !== '#') { + dom.addClass(obj.state.opened ? 'jstree-open' : 'jstree-closed'); + } + } + } + dom.removeClass("jstree-loading").attr('aria-busy',false); + /** + * triggered after a node is loaded + * @event + * @name load_node.jstree + * @param {Object} node the node that was loading + * @param {Boolean} status was the node loaded successfully + */ + this.trigger('load_node', { "node" : obj, "status" : status }); + if(callback) { + callback.call(this, obj, status); + } + }, this)); + return true; + }, + /** + * load an array of nodes (will also load unavailable nodes as soon as the appear in the structure). Used internally. + * @private + * @name _load_nodes(nodes [, callback]) + * @param {array} nodes + * @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - the array passed to _load_nodes + */ + _load_nodes : function (nodes, callback, is_callback, force_reload) { + var r = true, + c = function () { this._load_nodes(nodes, callback, true); }, + m = this._model.data, i, j, tmp = []; + for(i = 0, j = nodes.length; i < j; i++) { + if(m[nodes[i]] && ( (!m[nodes[i]].state.loaded && !m[nodes[i]].state.failed) || (!is_callback && force_reload) )) { + if(!this.is_loading(nodes[i])) { + this.load_node(nodes[i], c); + } + r = false; + } + } + if(r) { + for(i = 0, j = nodes.length; i < j; i++) { + if(m[nodes[i]] && m[nodes[i]].state.loaded) { + tmp.push(nodes[i]); + } + } + if(callback && !callback.done) { + callback.call(this, tmp); + callback.done = true; + } + } + }, + /** + * loads all unloaded nodes + * @name load_all([obj, callback]) + * @param {mixed} obj the node to load recursively, omit to load all nodes in the tree + * @param {function} callback a function to be executed once loading all the nodes is complete, + * @trigger load_all.jstree + */ + load_all : function (obj, callback) { + if(!obj) { obj = $.jstree.root; } + obj = this.get_node(obj); + if(!obj) { return false; } + var to_load = [], + m = this._model.data, + c = m[obj.id].children_d, + i, j; + if(obj.state && !obj.state.loaded) { + to_load.push(obj.id); + } + for(i = 0, j = c.length; i < j; i++) { + if(m[c[i]] && m[c[i]].state && !m[c[i]].state.loaded) { + to_load.push(c[i]); + } + } + if(to_load.length) { + this._load_nodes(to_load, function () { + this.load_all(obj, callback); + }); + } + else { + /** + * triggered after a load_all call completes + * @event + * @name load_all.jstree + * @param {Object} node the recursively loaded node + */ + if(callback) { callback.call(this, obj); } + this.trigger('load_all', { "node" : obj }); + } + }, + /** + * handles the actual loading of a node. Used only internally. + * @private + * @name _load_node(obj [, callback]) + * @param {mixed} obj + * @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - a boolean status + * @return {Boolean} + */ + _load_node : function (obj, callback) { + var s = this.settings.core.data, t; + var notTextOrCommentNode = function notTextOrCommentNode () { + return this.nodeType !== 3 && this.nodeType !== 8; + }; + // use original HTML + if(!s) { + if(obj.id === $.jstree.root) { + return this._append_html_data(obj, this._data.core.original_container_html.clone(true), function (status) { + callback.call(this, status); + }); + } + else { + return callback.call(this, false); + } + // return callback.call(this, obj.id === $.jstree.root ? this._append_html_data(obj, this._data.core.original_container_html.clone(true)) : false); + } + if($.isFunction(s)) { + return s.call(this, obj, $.proxy(function (d) { + if(d === false) { + callback.call(this, false); + } + else { + this[typeof d === 'string' ? '_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $($.parseHTML(d)).filter(notTextOrCommentNode) : d, function (status) { + callback.call(this, status); + }); + } + // return d === false ? callback.call(this, false) : callback.call(this, this[typeof d === 'string' ? '_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $(d) : d)); + }, this)); + } + if(typeof s === 'object') { + if(s.url) { + s = $.extend(true, {}, s); + if($.isFunction(s.url)) { + s.url = s.url.call(this, obj); + } + if($.isFunction(s.data)) { + s.data = s.data.call(this, obj); + } + return $.ajax(s) + .done($.proxy(function (d,t,x) { + var type = x.getResponseHeader('Content-Type'); + if((type && type.indexOf('json') !== -1) || typeof d === "object") { + return this._append_json_data(obj, d, function (status) { callback.call(this, status); }); + //return callback.call(this, this._append_json_data(obj, d)); + } + if((type && type.indexOf('html') !== -1) || typeof d === "string") { + return this._append_html_data(obj, $($.parseHTML(d)).filter(notTextOrCommentNode), function (status) { callback.call(this, status); }); + // return callback.call(this, this._append_html_data(obj, $(d))); + } + this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : x }) }; + this.settings.core.error.call(this, this._data.core.last_error); + return callback.call(this, false); + }, this)) + .fail($.proxy(function (f) { + this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : f }) }; + callback.call(this, false); + this.settings.core.error.call(this, this._data.core.last_error); + }, this)); + } + if ($.isArray(s)) { + t = $.extend(true, [], s); + } else if ($.isPlainObject(s)) { + t = $.extend(true, {}, s); + } else { + t = s; + } + if(obj.id === $.jstree.root) { + return this._append_json_data(obj, t, function (status) { + callback.call(this, status); + }); + } + else { + this._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_05', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) }; + this.settings.core.error.call(this, this._data.core.last_error); + return callback.call(this, false); + } + //return callback.call(this, (obj.id === $.jstree.root ? this._append_json_data(obj, t) : false) ); + } + if(typeof s === 'string') { + if(obj.id === $.jstree.root) { + return this._append_html_data(obj, $($.parseHTML(s)).filter(notTextOrCommentNode), function (status) { + callback.call(this, status); + }); + } + else { + this._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_06', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) }; + this.settings.core.error.call(this, this._data.core.last_error); + return callback.call(this, false); + } + //return callback.call(this, (obj.id === $.jstree.root ? this._append_html_data(obj, $(s)) : false) ); + } + return callback.call(this, false); + }, + /** + * adds a node to the list of nodes to redraw. Used only internally. + * @private + * @name _node_changed(obj [, callback]) + * @param {mixed} obj + */ + _node_changed : function (obj) { + obj = this.get_node(obj); + if (obj && $.inArray(obj.id, this._model.changed) === -1) { + this._model.changed.push(obj.id); + } + }, + /** + * appends HTML content to the tree. Used internally. + * @private + * @name _append_html_data(obj, data) + * @param {mixed} obj the node to append to + * @param {String} data the HTML string to parse and append + * @trigger model.jstree, changed.jstree + */ + _append_html_data : function (dom, data, cb) { + dom = this.get_node(dom); + dom.children = []; + dom.children_d = []; + var dat = data.is('ul') ? data.children() : data, + par = dom.id, + chd = [], + dpc = [], + m = this._model.data, + p = m[par], + s = this._data.core.selected.length, + tmp, i, j; + dat.each($.proxy(function (i, v) { + tmp = this._parse_model_from_html($(v), par, p.parents.concat()); + if(tmp) { + chd.push(tmp); + dpc.push(tmp); + if(m[tmp].children_d.length) { + dpc = dpc.concat(m[tmp].children_d); + } + } + }, this)); + p.children = chd; + p.children_d = dpc; + for(i = 0, j = p.parents.length; i < j; i++) { + m[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc); + } + /** + * triggered when new data is inserted to the tree model + * @event + * @name model.jstree + * @param {Array} nodes an array of node IDs + * @param {String} parent the parent ID of the nodes + */ + this.trigger('model', { "nodes" : dpc, 'parent' : par }); + if(par !== $.jstree.root) { + this._node_changed(par); + this.redraw(); + } + else { + this.get_container_ul().children('.jstree-initial-node').remove(); + this.redraw(true); + } + if(this._data.core.selected.length !== s) { + this.trigger('changed', { 'action' : 'model', 'selected' : this._data.core.selected }); + } + cb.call(this, true); + }, + /** + * appends JSON content to the tree. Used internally. + * @private + * @name _append_json_data(obj, data) + * @param {mixed} obj the node to append to + * @param {String} data the JSON object to parse and append + * @param {Boolean} force_processing internal param - do not set + * @trigger model.jstree, changed.jstree + */ + _append_json_data : function (dom, data, cb, force_processing) { + if(this.element === null) { return; } + dom = this.get_node(dom); + dom.children = []; + dom.children_d = []; + // *%$@!!! + if(data.d) { + data = data.d; + if(typeof data === "string") { + data = JSON.parse(data); + } + } + if(!$.isArray(data)) { data = [data]; } + var w = null, + args = { + 'df' : this._model.default_state, + 'dat' : data, + 'par' : dom.id, + 'm' : this._model.data, + 't_id' : this._id, + 't_cnt' : this._cnt, + 'sel' : this._data.core.selected + }, + func = function (data, undefined) { + if(data.data) { data = data.data; } + var dat = data.dat, + par = data.par, + chd = [], + dpc = [], + add = [], + df = data.df, + t_id = data.t_id, + t_cnt = data.t_cnt, + m = data.m, + p = m[par], + sel = data.sel, + tmp, i, j, rslt, + parse_flat = function (d, p, ps) { + if(!ps) { ps = []; } + else { ps = ps.concat(); } + if(p) { ps.unshift(p); } + var tid = d.id.toString(), + i, j, c, e, + tmp = { + id : tid, + text : d.text || '', + icon : d.icon !== undefined ? d.icon : true, + parent : p, + parents : ps, + children : d.children || [], + children_d : d.children_d || [], + data : d.data, + state : { }, + li_attr : { id : false }, + a_attr : { href : '#' }, + original : false + }; + for(i in df) { + if(df.hasOwnProperty(i)) { + tmp.state[i] = df[i]; + } + } + if(d && d.data && d.data.jstree && d.data.jstree.icon) { + tmp.icon = d.data.jstree.icon; + } + if(tmp.icon === undefined || tmp.icon === null || tmp.icon === "") { + tmp.icon = true; + } + if(d && d.data) { + tmp.data = d.data; + if(d.data.jstree) { + for(i in d.data.jstree) { + if(d.data.jstree.hasOwnProperty(i)) { + tmp.state[i] = d.data.jstree[i]; + } + } + } + } + if(d && typeof d.state === 'object') { + for (i in d.state) { + if(d.state.hasOwnProperty(i)) { + tmp.state[i] = d.state[i]; + } + } + } + if(d && typeof d.li_attr === 'object') { + for (i in d.li_attr) { + if(d.li_attr.hasOwnProperty(i)) { + tmp.li_attr[i] = d.li_attr[i]; + } + } + } + if(!tmp.li_attr.id) { + tmp.li_attr.id = tid; + } + if(d && typeof d.a_attr === 'object') { + for (i in d.a_attr) { + if(d.a_attr.hasOwnProperty(i)) { + tmp.a_attr[i] = d.a_attr[i]; + } + } + } + if(d && d.children && d.children === true) { + tmp.state.loaded = false; + tmp.children = []; + tmp.children_d = []; + } + m[tmp.id] = tmp; + for(i = 0, j = tmp.children.length; i < j; i++) { + c = parse_flat(m[tmp.children[i]], tmp.id, ps); + e = m[c]; + tmp.children_d.push(c); + if(e.children_d.length) { + tmp.children_d = tmp.children_d.concat(e.children_d); + } + } + delete d.data; + delete d.children; + m[tmp.id].original = d; + if(tmp.state.selected) { + add.push(tmp.id); + } + return tmp.id; + }, + parse_nest = function (d, p, ps) { + if(!ps) { ps = []; } + else { ps = ps.concat(); } + if(p) { ps.unshift(p); } + var tid = false, i, j, c, e, tmp; + do { + tid = 'j' + t_id + '_' + (++t_cnt); + } while(m[tid]); + + tmp = { + id : false, + text : typeof d === 'string' ? d : '', + icon : typeof d === 'object' && d.icon !== undefined ? d.icon : true, + parent : p, + parents : ps, + children : [], + children_d : [], + data : null, + state : { }, + li_attr : { id : false }, + a_attr : { href : '#' }, + original : false + }; + for(i in df) { + if(df.hasOwnProperty(i)) { + tmp.state[i] = df[i]; + } + } + if(d && d.id) { tmp.id = d.id.toString(); } + if(d && d.text) { tmp.text = d.text; } + if(d && d.data && d.data.jstree && d.data.jstree.icon) { + tmp.icon = d.data.jstree.icon; + } + if(tmp.icon === undefined || tmp.icon === null || tmp.icon === "") { + tmp.icon = true; + } + if(d && d.data) { + tmp.data = d.data; + if(d.data.jstree) { + for(i in d.data.jstree) { + if(d.data.jstree.hasOwnProperty(i)) { + tmp.state[i] = d.data.jstree[i]; + } + } + } + } + if(d && typeof d.state === 'object') { + for (i in d.state) { + if(d.state.hasOwnProperty(i)) { + tmp.state[i] = d.state[i]; + } + } + } + if(d && typeof d.li_attr === 'object') { + for (i in d.li_attr) { + if(d.li_attr.hasOwnProperty(i)) { + tmp.li_attr[i] = d.li_attr[i]; + } + } + } + if(tmp.li_attr.id && !tmp.id) { + tmp.id = tmp.li_attr.id.toString(); + } + if(!tmp.id) { + tmp.id = tid; + } + if(!tmp.li_attr.id) { + tmp.li_attr.id = tmp.id; + } + if(d && typeof d.a_attr === 'object') { + for (i in d.a_attr) { + if(d.a_attr.hasOwnProperty(i)) { + tmp.a_attr[i] = d.a_attr[i]; + } + } + } + if(d && d.children && d.children.length) { + for(i = 0, j = d.children.length; i < j; i++) { + c = parse_nest(d.children[i], tmp.id, ps); + e = m[c]; + tmp.children.push(c); + if(e.children_d.length) { + tmp.children_d = tmp.children_d.concat(e.children_d); + } + } + tmp.children_d = tmp.children_d.concat(tmp.children); + } + if(d && d.children && d.children === true) { + tmp.state.loaded = false; + tmp.children = []; + tmp.children_d = []; + } + delete d.data; + delete d.children; + tmp.original = d; + m[tmp.id] = tmp; + if(tmp.state.selected) { + add.push(tmp.id); + } + return tmp.id; + }; + + if(dat.length && dat[0].id !== undefined && dat[0].parent !== undefined) { + // Flat JSON support (for easy import from DB): + // 1) convert to object (foreach) + for(i = 0, j = dat.length; i < j; i++) { + if(!dat[i].children) { + dat[i].children = []; + } + if(!dat[i].state) { + dat[i].state = {}; + } + m[dat[i].id.toString()] = dat[i]; + } + // 2) populate children (foreach) + for(i = 0, j = dat.length; i < j; i++) { + if (!m[dat[i].parent.toString()]) { + this._data.core.last_error = { 'error' : 'parse', 'plugin' : 'core', 'id' : 'core_07', 'reason' : 'Node with invalid parent', 'data' : JSON.stringify({ 'id' : dat[i].id.toString(), 'parent' : dat[i].parent.toString() }) }; + this.settings.core.error.call(this, this._data.core.last_error); + continue; + } + + m[dat[i].parent.toString()].children.push(dat[i].id.toString()); + // populate parent.children_d + p.children_d.push(dat[i].id.toString()); + } + // 3) normalize && populate parents and children_d with recursion + for(i = 0, j = p.children.length; i < j; i++) { + tmp = parse_flat(m[p.children[i]], par, p.parents.concat()); + dpc.push(tmp); + if(m[tmp].children_d.length) { + dpc = dpc.concat(m[tmp].children_d); + } + } + for(i = 0, j = p.parents.length; i < j; i++) { + m[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc); + } + // ?) three_state selection - p.state.selected && t - (if three_state foreach(dat => ch) -> foreach(parents) if(parent.selected) child.selected = true; + rslt = { + 'cnt' : t_cnt, + 'mod' : m, + 'sel' : sel, + 'par' : par, + 'dpc' : dpc, + 'add' : add + }; + } + else { + for(i = 0, j = dat.length; i < j; i++) { + tmp = parse_nest(dat[i], par, p.parents.concat()); + if(tmp) { + chd.push(tmp); + dpc.push(tmp); + if(m[tmp].children_d.length) { + dpc = dpc.concat(m[tmp].children_d); + } + } + } + p.children = chd; + p.children_d = dpc; + for(i = 0, j = p.parents.length; i < j; i++) { + m[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc); + } + rslt = { + 'cnt' : t_cnt, + 'mod' : m, + 'sel' : sel, + 'par' : par, + 'dpc' : dpc, + 'add' : add + }; + } + if(typeof window === 'undefined' || typeof window.document === 'undefined') { + postMessage(rslt); + } + else { + return rslt; + } + }, + rslt = function (rslt, worker) { + if(this.element === null) { return; } + this._cnt = rslt.cnt; + var i, m = this._model.data; + for (i in m) { + if (m.hasOwnProperty(i) && m[i].state && m[i].state.loading && rslt.mod[i]) { + rslt.mod[i].state.loading = true; + } + } + this._model.data = rslt.mod; // breaks the reference in load_node - careful + + if(worker) { + var j, a = rslt.add, r = rslt.sel, s = this._data.core.selected.slice(); + m = this._model.data; + // if selection was changed while calculating in worker + if(r.length !== s.length || $.vakata.array_unique(r.concat(s)).length !== r.length) { + // deselect nodes that are no longer selected + for(i = 0, j = r.length; i < j; i++) { + if($.inArray(r[i], a) === -1 && $.inArray(r[i], s) === -1) { + m[r[i]].state.selected = false; + } + } + // select nodes that were selected in the mean time + for(i = 0, j = s.length; i < j; i++) { + if($.inArray(s[i], r) === -1) { + m[s[i]].state.selected = true; + } + } + } + } + if(rslt.add.length) { + this._data.core.selected = this._data.core.selected.concat(rslt.add); + } + + this.trigger('model', { "nodes" : rslt.dpc, 'parent' : rslt.par }); + + if(rslt.par !== $.jstree.root) { + this._node_changed(rslt.par); + this.redraw(); + } + else { + // this.get_container_ul().children('.jstree-initial-node').remove(); + this.redraw(true); + } + if(rslt.add.length) { + this.trigger('changed', { 'action' : 'model', 'selected' : this._data.core.selected }); + } + cb.call(this, true); + }; + if(this.settings.core.worker && window.Blob && window.URL && window.Worker) { + try { + if(this._wrk === null) { + this._wrk = window.URL.createObjectURL( + new window.Blob( + ['self.onmessage = ' + func.toString()], + {type:"text/javascript"} + ) + ); + } + if(!this._data.core.working || force_processing) { + this._data.core.working = true; + w = new window.Worker(this._wrk); + w.onmessage = $.proxy(function (e) { + rslt.call(this, e.data, true); + try { w.terminate(); w = null; } catch(ignore) { } + if(this._data.core.worker_queue.length) { + this._append_json_data.apply(this, this._data.core.worker_queue.shift()); + } + else { + this._data.core.working = false; + } + }, this); + if(!args.par) { + if(this._data.core.worker_queue.length) { + this._append_json_data.apply(this, this._data.core.worker_queue.shift()); + } + else { + this._data.core.working = false; + } + } + else { + w.postMessage(args); + } + } + else { + this._data.core.worker_queue.push([dom, data, cb, true]); + } + } + catch(e) { + rslt.call(this, func(args), false); + if(this._data.core.worker_queue.length) { + this._append_json_data.apply(this, this._data.core.worker_queue.shift()); + } + else { + this._data.core.working = false; + } + } + } + else { + rslt.call(this, func(args), false); + } + }, + /** + * parses a node from a jQuery object and appends them to the in memory tree model. Used internally. + * @private + * @name _parse_model_from_html(d [, p, ps]) + * @param {jQuery} d the jQuery object to parse + * @param {String} p the parent ID + * @param {Array} ps list of all parents + * @return {String} the ID of the object added to the model + */ + _parse_model_from_html : function (d, p, ps) { + if(!ps) { ps = []; } + else { ps = [].concat(ps); } + if(p) { ps.unshift(p); } + var c, e, m = this._model.data, + data = { + id : false, + text : false, + icon : true, + parent : p, + parents : ps, + children : [], + children_d : [], + data : null, + state : { }, + li_attr : { id : false }, + a_attr : { href : '#' }, + original : false + }, i, tmp, tid; + for(i in this._model.default_state) { + if(this._model.default_state.hasOwnProperty(i)) { + data.state[i] = this._model.default_state[i]; + } + } + tmp = $.vakata.attributes(d, true); + $.each(tmp, function (i, v) { + v = $.trim(v); + if(!v.length) { return true; } + data.li_attr[i] = v; + if(i === 'id') { + data.id = v.toString(); + } + }); + tmp = d.children('a').first(); + if(tmp.length) { + tmp = $.vakata.attributes(tmp, true); + $.each(tmp, function (i, v) { + v = $.trim(v); + if(v.length) { + data.a_attr[i] = v; + } + }); + } + tmp = d.children("a").first().length ? d.children("a").first().clone() : d.clone(); + tmp.children("ins, i, ul").remove(); + tmp = tmp.html(); + tmp = $('
').html(tmp); + data.text = this.settings.core.force_text ? tmp.text() : tmp.html(); + tmp = d.data(); + data.data = tmp ? $.extend(true, {}, tmp) : null; + data.state.opened = d.hasClass('jstree-open'); + data.state.selected = d.children('a').hasClass('jstree-clicked'); + data.state.disabled = d.children('a').hasClass('jstree-disabled'); + if(data.data && data.data.jstree) { + for(i in data.data.jstree) { + if(data.data.jstree.hasOwnProperty(i)) { + data.state[i] = data.data.jstree[i]; + } + } + } + tmp = d.children("a").children(".jstree-themeicon"); + if(tmp.length) { + data.icon = tmp.hasClass('jstree-themeicon-hidden') ? false : tmp.attr('rel'); + } + if(data.state.icon !== undefined) { + data.icon = data.state.icon; + } + if(data.icon === undefined || data.icon === null || data.icon === "") { + data.icon = true; + } + tmp = d.children("ul").children("li"); + do { + tid = 'j' + this._id + '_' + (++this._cnt); + } while(m[tid]); + data.id = data.li_attr.id ? data.li_attr.id.toString() : tid; + if(tmp.length) { + tmp.each($.proxy(function (i, v) { + c = this._parse_model_from_html($(v), data.id, ps); + e = this._model.data[c]; + data.children.push(c); + if(e.children_d.length) { + data.children_d = data.children_d.concat(e.children_d); + } + }, this)); + data.children_d = data.children_d.concat(data.children); + } + else { + if(d.hasClass('jstree-closed')) { + data.state.loaded = false; + } + } + if(data.li_attr['class']) { + data.li_attr['class'] = data.li_attr['class'].replace('jstree-closed','').replace('jstree-open',''); + } + if(data.a_attr['class']) { + data.a_attr['class'] = data.a_attr['class'].replace('jstree-clicked','').replace('jstree-disabled',''); + } + m[data.id] = data; + if(data.state.selected) { + this._data.core.selected.push(data.id); + } + return data.id; + }, + /** + * parses a node from a JSON object (used when dealing with flat data, which has no nesting of children, but has id and parent properties) and appends it to the in memory tree model. Used internally. + * @private + * @name _parse_model_from_flat_json(d [, p, ps]) + * @param {Object} d the JSON object to parse + * @param {String} p the parent ID + * @param {Array} ps list of all parents + * @return {String} the ID of the object added to the model + */ + _parse_model_from_flat_json : function (d, p, ps) { + if(!ps) { ps = []; } + else { ps = ps.concat(); } + if(p) { ps.unshift(p); } + var tid = d.id.toString(), + m = this._model.data, + df = this._model.default_state, + i, j, c, e, + tmp = { + id : tid, + text : d.text || '', + icon : d.icon !== undefined ? d.icon : true, + parent : p, + parents : ps, + children : d.children || [], + children_d : d.children_d || [], + data : d.data, + state : { }, + li_attr : { id : false }, + a_attr : { href : '#' }, + original : false + }; + for(i in df) { + if(df.hasOwnProperty(i)) { + tmp.state[i] = df[i]; + } + } + if(d && d.data && d.data.jstree && d.data.jstree.icon) { + tmp.icon = d.data.jstree.icon; + } + if(tmp.icon === undefined || tmp.icon === null || tmp.icon === "") { + tmp.icon = true; + } + if(d && d.data) { + tmp.data = d.data; + if(d.data.jstree) { + for(i in d.data.jstree) { + if(d.data.jstree.hasOwnProperty(i)) { + tmp.state[i] = d.data.jstree[i]; + } + } + } + } + if(d && typeof d.state === 'object') { + for (i in d.state) { + if(d.state.hasOwnProperty(i)) { + tmp.state[i] = d.state[i]; + } + } + } + if(d && typeof d.li_attr === 'object') { + for (i in d.li_attr) { + if(d.li_attr.hasOwnProperty(i)) { + tmp.li_attr[i] = d.li_attr[i]; + } + } + } + if(!tmp.li_attr.id) { + tmp.li_attr.id = tid; + } + if(d && typeof d.a_attr === 'object') { + for (i in d.a_attr) { + if(d.a_attr.hasOwnProperty(i)) { + tmp.a_attr[i] = d.a_attr[i]; + } + } + } + if(d && d.children && d.children === true) { + tmp.state.loaded = false; + tmp.children = []; + tmp.children_d = []; + } + m[tmp.id] = tmp; + for(i = 0, j = tmp.children.length; i < j; i++) { + c = this._parse_model_from_flat_json(m[tmp.children[i]], tmp.id, ps); + e = m[c]; + tmp.children_d.push(c); + if(e.children_d.length) { + tmp.children_d = tmp.children_d.concat(e.children_d); + } + } + delete d.data; + delete d.children; + m[tmp.id].original = d; + if(tmp.state.selected) { + this._data.core.selected.push(tmp.id); + } + return tmp.id; + }, + /** + * parses a node from a JSON object and appends it to the in memory tree model. Used internally. + * @private + * @name _parse_model_from_json(d [, p, ps]) + * @param {Object} d the JSON object to parse + * @param {String} p the parent ID + * @param {Array} ps list of all parents + * @return {String} the ID of the object added to the model + */ + _parse_model_from_json : function (d, p, ps) { + if(!ps) { ps = []; } + else { ps = ps.concat(); } + if(p) { ps.unshift(p); } + var tid = false, i, j, c, e, m = this._model.data, df = this._model.default_state, tmp; + do { + tid = 'j' + this._id + '_' + (++this._cnt); + } while(m[tid]); + + tmp = { + id : false, + text : typeof d === 'string' ? d : '', + icon : typeof d === 'object' && d.icon !== undefined ? d.icon : true, + parent : p, + parents : ps, + children : [], + children_d : [], + data : null, + state : { }, + li_attr : { id : false }, + a_attr : { href : '#' }, + original : false + }; + for(i in df) { + if(df.hasOwnProperty(i)) { + tmp.state[i] = df[i]; + } + } + if(d && d.id) { tmp.id = d.id.toString(); } + if(d && d.text) { tmp.text = d.text; } + if(d && d.data && d.data.jstree && d.data.jstree.icon) { + tmp.icon = d.data.jstree.icon; + } + if(tmp.icon === undefined || tmp.icon === null || tmp.icon === "") { + tmp.icon = true; + } + if(d && d.data) { + tmp.data = d.data; + if(d.data.jstree) { + for(i in d.data.jstree) { + if(d.data.jstree.hasOwnProperty(i)) { + tmp.state[i] = d.data.jstree[i]; + } + } + } + } + if(d && typeof d.state === 'object') { + for (i in d.state) { + if(d.state.hasOwnProperty(i)) { + tmp.state[i] = d.state[i]; + } + } + } + if(d && typeof d.li_attr === 'object') { + for (i in d.li_attr) { + if(d.li_attr.hasOwnProperty(i)) { + tmp.li_attr[i] = d.li_attr[i]; + } + } + } + if(tmp.li_attr.id && !tmp.id) { + tmp.id = tmp.li_attr.id.toString(); + } + if(!tmp.id) { + tmp.id = tid; + } + if(!tmp.li_attr.id) { + tmp.li_attr.id = tmp.id; + } + if(d && typeof d.a_attr === 'object') { + for (i in d.a_attr) { + if(d.a_attr.hasOwnProperty(i)) { + tmp.a_attr[i] = d.a_attr[i]; + } + } + } + if(d && d.children && d.children.length) { + for(i = 0, j = d.children.length; i < j; i++) { + c = this._parse_model_from_json(d.children[i], tmp.id, ps); + e = m[c]; + tmp.children.push(c); + if(e.children_d.length) { + tmp.children_d = tmp.children_d.concat(e.children_d); + } + } + tmp.children_d = tmp.children_d.concat(tmp.children); + } + if(d && d.children && d.children === true) { + tmp.state.loaded = false; + tmp.children = []; + tmp.children_d = []; + } + delete d.data; + delete d.children; + tmp.original = d; + m[tmp.id] = tmp; + if(tmp.state.selected) { + this._data.core.selected.push(tmp.id); + } + return tmp.id; + }, + /** + * redraws all nodes that need to be redrawn. Used internally. + * @private + * @name _redraw() + * @trigger redraw.jstree + */ + _redraw : function () { + var nodes = this._model.force_full_redraw ? this._model.data[$.jstree.root].children.concat([]) : this._model.changed.concat([]), + f = document.createElement('UL'), tmp, i, j, fe = this._data.core.focused; + for(i = 0, j = nodes.length; i < j; i++) { + tmp = this.redraw_node(nodes[i], true, this._model.force_full_redraw); + if(tmp && this._model.force_full_redraw) { + f.appendChild(tmp); + } + } + if(this._model.force_full_redraw) { + f.className = this.get_container_ul()[0].className; + f.setAttribute('role','group'); + this.element.empty().append(f); + //this.get_container_ul()[0].appendChild(f); + } + if(fe !== null) { + tmp = this.get_node(fe, true); + if(tmp && tmp.length && tmp.children('.jstree-anchor')[0] !== document.activeElement) { + tmp.children('.jstree-anchor').focus(); + } + else { + this._data.core.focused = null; + } + } + this._model.force_full_redraw = false; + this._model.changed = []; + /** + * triggered after nodes are redrawn + * @event + * @name redraw.jstree + * @param {array} nodes the redrawn nodes + */ + this.trigger('redraw', { "nodes" : nodes }); + }, + /** + * redraws all nodes that need to be redrawn or optionally - the whole tree + * @name redraw([full]) + * @param {Boolean} full if set to `true` all nodes are redrawn. + */ + redraw : function (full) { + if(full) { + this._model.force_full_redraw = true; + } + //if(this._model.redraw_timeout) { + // clearTimeout(this._model.redraw_timeout); + //} + //this._model.redraw_timeout = setTimeout($.proxy(this._redraw, this),0); + this._redraw(); + }, + /** + * redraws a single node's children. Used internally. + * @private + * @name draw_children(node) + * @param {mixed} node the node whose children will be redrawn + */ + draw_children : function (node) { + var obj = this.get_node(node), + i = false, + j = false, + k = false, + d = document; + if(!obj) { return false; } + if(obj.id === $.jstree.root) { return this.redraw(true); } + node = this.get_node(node, true); + if(!node || !node.length) { return false; } // TODO: quick toggle + + node.children('.jstree-children').remove(); + node = node[0]; + if(obj.children.length && obj.state.loaded) { + k = d.createElement('UL'); + k.setAttribute('role', 'group'); + k.className = 'jstree-children'; + for(i = 0, j = obj.children.length; i < j; i++) { + k.appendChild(this.redraw_node(obj.children[i], true, true)); + } + node.appendChild(k); + } + }, + /** + * redraws a single node. Used internally. + * @private + * @name redraw_node(node, deep, is_callback, force_render) + * @param {mixed} node the node to redraw + * @param {Boolean} deep should child nodes be redrawn too + * @param {Boolean} is_callback is this a recursion call + * @param {Boolean} force_render should children of closed parents be drawn anyway + */ + redraw_node : function (node, deep, is_callback, force_render) { + var obj = this.get_node(node), + par = false, + ind = false, + old = false, + i = false, + j = false, + k = false, + c = '', + d = document, + m = this._model.data, + f = false, + s = false, + tmp = null, + t = 0, + l = 0, + has_children = false, + last_sibling = false; + if(!obj) { return false; } + if(obj.id === $.jstree.root) { return this.redraw(true); } + deep = deep || obj.children.length === 0; + node = !document.querySelector ? document.getElementById(obj.id) : this.element[0].querySelector('#' + ("0123456789".indexOf(obj.id[0]) !== -1 ? '\\3' + obj.id[0] + ' ' + obj.id.substr(1).replace($.jstree.idregex,'\\$&') : obj.id.replace($.jstree.idregex,'\\$&')) ); //, this.element); + if(!node) { + deep = true; + //node = d.createElement('LI'); + if(!is_callback) { + par = obj.parent !== $.jstree.root ? $('#' + obj.parent.replace($.jstree.idregex,'\\$&'), this.element)[0] : null; + if(par !== null && (!par || !m[obj.parent].state.opened)) { + return false; + } + ind = $.inArray(obj.id, par === null ? m[$.jstree.root].children : m[obj.parent].children); + } + } + else { + node = $(node); + if(!is_callback) { + par = node.parent().parent()[0]; + if(par === this.element[0]) { + par = null; + } + ind = node.index(); + } + // m[obj.id].data = node.data(); // use only node's data, no need to touch jquery storage + if(!deep && obj.children.length && !node.children('.jstree-children').length) { + deep = true; + } + if(!deep) { + old = node.children('.jstree-children')[0]; + } + f = node.children('.jstree-anchor')[0] === document.activeElement; + node.remove(); + //node = d.createElement('LI'); + //node = node[0]; + } + node = this._data.core.node.cloneNode(true); + // node is DOM, deep is boolean + + c = 'jstree-node '; + for(i in obj.li_attr) { + if(obj.li_attr.hasOwnProperty(i)) { + if(i === 'id') { continue; } + if(i !== 'class') { + node.setAttribute(i, obj.li_attr[i]); + } + else { + c += obj.li_attr[i]; + } + } + } + if(!obj.a_attr.id) { + obj.a_attr.id = obj.id + '_anchor'; + } + node.setAttribute('aria-selected', !!obj.state.selected); + node.setAttribute('aria-level', obj.parents.length); + node.setAttribute('aria-labelledby', obj.a_attr.id); + if(obj.state.disabled) { + node.setAttribute('aria-disabled', true); + } + + for(i = 0, j = obj.children.length; i < j; i++) { + if(!m[obj.children[i]].state.hidden) { + has_children = true; + break; + } + } + if(obj.parent !== null && m[obj.parent] && !obj.state.hidden) { + i = $.inArray(obj.id, m[obj.parent].children); + last_sibling = obj.id; + if(i !== -1) { + i++; + for(j = m[obj.parent].children.length; i < j; i++) { + if(!m[m[obj.parent].children[i]].state.hidden) { + last_sibling = m[obj.parent].children[i]; + } + if(last_sibling !== obj.id) { + break; + } + } + } + } + + if(obj.state.hidden) { + c += ' jstree-hidden'; + } + if (obj.state.loading) { + c += ' jstree-loading'; + } + if(obj.state.loaded && !has_children) { + c += ' jstree-leaf'; + } + else { + c += obj.state.opened && obj.state.loaded ? ' jstree-open' : ' jstree-closed'; + node.setAttribute('aria-expanded', (obj.state.opened && obj.state.loaded) ); + } + if(last_sibling === obj.id) { + c += ' jstree-last'; + } + node.id = obj.id; + node.className = c; + c = ( obj.state.selected ? ' jstree-clicked' : '') + ( obj.state.disabled ? ' jstree-disabled' : ''); + for(j in obj.a_attr) { + if(obj.a_attr.hasOwnProperty(j)) { + if(j === 'href' && obj.a_attr[j] === '#') { continue; } + if(j !== 'class') { + node.childNodes[1].setAttribute(j, obj.a_attr[j]); + } + else { + c += ' ' + obj.a_attr[j]; + } + } + } + if(c.length) { + node.childNodes[1].className = 'jstree-anchor ' + c; + } + if((obj.icon && obj.icon !== true) || obj.icon === false) { + if(obj.icon === false) { + node.childNodes[1].childNodes[0].className += ' jstree-themeicon-hidden'; + } + else if(obj.icon.indexOf('/') === -1 && obj.icon.indexOf('.') === -1) { + node.childNodes[1].childNodes[0].className += ' ' + obj.icon + ' jstree-themeicon-custom'; + } + else { + node.childNodes[1].childNodes[0].style.backgroundImage = 'url("'+obj.icon+'")'; + node.childNodes[1].childNodes[0].style.backgroundPosition = 'center center'; + node.childNodes[1].childNodes[0].style.backgroundSize = 'auto'; + node.childNodes[1].childNodes[0].className += ' jstree-themeicon-custom'; + } + } + + if(this.settings.core.force_text) { + node.childNodes[1].appendChild(d.createTextNode(obj.text)); + } + else { + node.childNodes[1].innerHTML += obj.text; + } + + + if(deep && obj.children.length && (obj.state.opened || force_render) && obj.state.loaded) { + k = d.createElement('UL'); + k.setAttribute('role', 'group'); + k.className = 'jstree-children'; + for(i = 0, j = obj.children.length; i < j; i++) { + k.appendChild(this.redraw_node(obj.children[i], deep, true)); + } + node.appendChild(k); + } + if(old) { + node.appendChild(old); + } + if(!is_callback) { + // append back using par / ind + if(!par) { + par = this.element[0]; + } + for(i = 0, j = par.childNodes.length; i < j; i++) { + if(par.childNodes[i] && par.childNodes[i].className && par.childNodes[i].className.indexOf('jstree-children') !== -1) { + tmp = par.childNodes[i]; + break; + } + } + if(!tmp) { + tmp = d.createElement('UL'); + tmp.setAttribute('role', 'group'); + tmp.className = 'jstree-children'; + par.appendChild(tmp); + } + par = tmp; + + if(ind < par.childNodes.length) { + par.insertBefore(node, par.childNodes[ind]); + } + else { + par.appendChild(node); + } + if(f) { + t = this.element[0].scrollTop; + l = this.element[0].scrollLeft; + node.childNodes[1].focus(); + this.element[0].scrollTop = t; + this.element[0].scrollLeft = l; + } + } + if(obj.state.opened && !obj.state.loaded) { + obj.state.opened = false; + setTimeout($.proxy(function () { + this.open_node(obj.id, false, 0); + }, this), 0); + } + return node; + }, + /** + * opens a node, revaling its children. If the node is not loaded it will be loaded and opened once ready. + * @name open_node(obj [, callback, animation]) + * @param {mixed} obj the node to open + * @param {Function} callback a function to execute once the node is opened + * @param {Number} animation the animation duration in milliseconds when opening the node (overrides the `core.animation` setting). Use `false` for no animation. + * @trigger open_node.jstree, after_open.jstree, before_open.jstree + */ + open_node : function (obj, callback, animation) { + var t1, t2, d, t; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.open_node(obj[t1], callback, animation); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + animation = animation === undefined ? this.settings.core.animation : animation; + if(!this.is_closed(obj)) { + if(callback) { + callback.call(this, obj, false); + } + return false; + } + if(!this.is_loaded(obj)) { + if(this.is_loading(obj)) { + return setTimeout($.proxy(function () { + this.open_node(obj, callback, animation); + }, this), 500); + } + this.load_node(obj, function (o, ok) { + return ok ? this.open_node(o, callback, animation) : (callback ? callback.call(this, o, false) : false); + }); + } + else { + d = this.get_node(obj, true); + t = this; + if(d.length) { + if(animation && d.children(".jstree-children").length) { + d.children(".jstree-children").stop(true, true); + } + if(obj.children.length && !this._firstChild(d.children('.jstree-children')[0])) { + this.draw_children(obj); + //d = this.get_node(obj, true); + } + if(!animation) { + this.trigger('before_open', { "node" : obj }); + d[0].className = d[0].className.replace('jstree-closed', 'jstree-open'); + d[0].setAttribute("aria-expanded", true); + } + else { + this.trigger('before_open', { "node" : obj }); + d + .children(".jstree-children").css("display","none").end() + .removeClass("jstree-closed").addClass("jstree-open").attr("aria-expanded", true) + .children(".jstree-children").stop(true, true) + .slideDown(animation, function () { + this.style.display = ""; + if (t.element) { + t.trigger("after_open", { "node" : obj }); + } + }); + } + } + obj.state.opened = true; + if(callback) { + callback.call(this, obj, true); + } + if(!d.length) { + /** + * triggered when a node is about to be opened (if the node is supposed to be in the DOM, it will be, but it won't be visible yet) + * @event + * @name before_open.jstree + * @param {Object} node the opened node + */ + this.trigger('before_open', { "node" : obj }); + } + /** + * triggered when a node is opened (if there is an animation it will not be completed yet) + * @event + * @name open_node.jstree + * @param {Object} node the opened node + */ + this.trigger('open_node', { "node" : obj }); + if(!animation || !d.length) { + /** + * triggered when a node is opened and the animation is complete + * @event + * @name after_open.jstree + * @param {Object} node the opened node + */ + this.trigger("after_open", { "node" : obj }); + } + return true; + } + }, + /** + * opens every parent of a node (node should be loaded) + * @name _open_to(obj) + * @param {mixed} obj the node to reveal + * @private + */ + _open_to : function (obj) { + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + var i, j, p = obj.parents; + for(i = 0, j = p.length; i < j; i+=1) { + if(i !== $.jstree.root) { + this.open_node(p[i], false, 0); + } + } + return $('#' + obj.id.replace($.jstree.idregex,'\\$&'), this.element); + }, + /** + * closes a node, hiding its children + * @name close_node(obj [, animation]) + * @param {mixed} obj the node to close + * @param {Number} animation the animation duration in milliseconds when closing the node (overrides the `core.animation` setting). Use `false` for no animation. + * @trigger close_node.jstree, after_close.jstree + */ + close_node : function (obj, animation) { + var t1, t2, t, d; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.close_node(obj[t1], animation); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + if(this.is_closed(obj)) { + return false; + } + animation = animation === undefined ? this.settings.core.animation : animation; + t = this; + d = this.get_node(obj, true); + + obj.state.opened = false; + /** + * triggered when a node is closed (if there is an animation it will not be complete yet) + * @event + * @name close_node.jstree + * @param {Object} node the closed node + */ + this.trigger('close_node',{ "node" : obj }); + if(!d.length) { + /** + * triggered when a node is closed and the animation is complete + * @event + * @name after_close.jstree + * @param {Object} node the closed node + */ + this.trigger("after_close", { "node" : obj }); + } + else { + if(!animation) { + d[0].className = d[0].className.replace('jstree-open', 'jstree-closed'); + d.attr("aria-expanded", false).children('.jstree-children').remove(); + this.trigger("after_close", { "node" : obj }); + } + else { + d + .children(".jstree-children").attr("style","display:block !important").end() + .removeClass("jstree-open").addClass("jstree-closed").attr("aria-expanded", false) + .children(".jstree-children").stop(true, true).slideUp(animation, function () { + this.style.display = ""; + d.children('.jstree-children').remove(); + if (t.element) { + t.trigger("after_close", { "node" : obj }); + } + }); + } + } + }, + /** + * toggles a node - closing it if it is open, opening it if it is closed + * @name toggle_node(obj) + * @param {mixed} obj the node to toggle + */ + toggle_node : function (obj) { + var t1, t2; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.toggle_node(obj[t1]); + } + return true; + } + if(this.is_closed(obj)) { + return this.open_node(obj); + } + if(this.is_open(obj)) { + return this.close_node(obj); + } + }, + /** + * opens all nodes within a node (or the tree), revaling their children. If the node is not loaded it will be loaded and opened once ready. + * @name open_all([obj, animation, original_obj]) + * @param {mixed} obj the node to open recursively, omit to open all nodes in the tree + * @param {Number} animation the animation duration in milliseconds when opening the nodes, the default is no animation + * @param {jQuery} reference to the node that started the process (internal use) + * @trigger open_all.jstree + */ + open_all : function (obj, animation, original_obj) { + if(!obj) { obj = $.jstree.root; } + obj = this.get_node(obj); + if(!obj) { return false; } + var dom = obj.id === $.jstree.root ? this.get_container_ul() : this.get_node(obj, true), i, j, _this; + if(!dom.length) { + for(i = 0, j = obj.children_d.length; i < j; i++) { + if(this.is_closed(this._model.data[obj.children_d[i]])) { + this._model.data[obj.children_d[i]].state.opened = true; + } + } + return this.trigger('open_all', { "node" : obj }); + } + original_obj = original_obj || dom; + _this = this; + dom = this.is_closed(obj) ? dom.find('.jstree-closed').addBack() : dom.find('.jstree-closed'); + dom.each(function () { + _this.open_node( + this, + function(node, status) { if(status && this.is_parent(node)) { this.open_all(node, animation, original_obj); } }, + animation || 0 + ); + }); + if(original_obj.find('.jstree-closed').length === 0) { + /** + * triggered when an `open_all` call completes + * @event + * @name open_all.jstree + * @param {Object} node the opened node + */ + this.trigger('open_all', { "node" : this.get_node(original_obj) }); + } + }, + /** + * closes all nodes within a node (or the tree), revaling their children + * @name close_all([obj, animation]) + * @param {mixed} obj the node to close recursively, omit to close all nodes in the tree + * @param {Number} animation the animation duration in milliseconds when closing the nodes, the default is no animation + * @trigger close_all.jstree + */ + close_all : function (obj, animation) { + if(!obj) { obj = $.jstree.root; } + obj = this.get_node(obj); + if(!obj) { return false; } + var dom = obj.id === $.jstree.root ? this.get_container_ul() : this.get_node(obj, true), + _this = this, i, j; + if(dom.length) { + dom = this.is_open(obj) ? dom.find('.jstree-open').addBack() : dom.find('.jstree-open'); + $(dom.get().reverse()).each(function () { _this.close_node(this, animation || 0); }); + } + for(i = 0, j = obj.children_d.length; i < j; i++) { + this._model.data[obj.children_d[i]].state.opened = false; + } + /** + * triggered when an `close_all` call completes + * @event + * @name close_all.jstree + * @param {Object} node the closed node + */ + this.trigger('close_all', { "node" : obj }); + }, + /** + * checks if a node is disabled (not selectable) + * @name is_disabled(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_disabled : function (obj) { + obj = this.get_node(obj); + return obj && obj.state && obj.state.disabled; + }, + /** + * enables a node - so that it can be selected + * @name enable_node(obj) + * @param {mixed} obj the node to enable + * @trigger enable_node.jstree + */ + enable_node : function (obj) { + var t1, t2; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.enable_node(obj[t1]); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + obj.state.disabled = false; + this.get_node(obj,true).children('.jstree-anchor').removeClass('jstree-disabled').attr('aria-disabled', false); + /** + * triggered when an node is enabled + * @event + * @name enable_node.jstree + * @param {Object} node the enabled node + */ + this.trigger('enable_node', { 'node' : obj }); + }, + /** + * disables a node - so that it can not be selected + * @name disable_node(obj) + * @param {mixed} obj the node to disable + * @trigger disable_node.jstree + */ + disable_node : function (obj) { + var t1, t2; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.disable_node(obj[t1]); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + obj.state.disabled = true; + this.get_node(obj,true).children('.jstree-anchor').addClass('jstree-disabled').attr('aria-disabled', true); + /** + * triggered when an node is disabled + * @event + * @name disable_node.jstree + * @param {Object} node the disabled node + */ + this.trigger('disable_node', { 'node' : obj }); + }, + /** + * determines if a node is hidden + * @name is_hidden(obj) + * @param {mixed} obj the node + */ + is_hidden : function (obj) { + obj = this.get_node(obj); + return obj.state.hidden === true; + }, + /** + * hides a node - it is still in the structure but will not be visible + * @name hide_node(obj) + * @param {mixed} obj the node to hide + * @param {Boolean} skip_redraw internal parameter controlling if redraw is called + * @trigger hide_node.jstree + */ + hide_node : function (obj, skip_redraw) { + var t1, t2; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.hide_node(obj[t1], true); + } + if (!skip_redraw) { + this.redraw(); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + if(!obj.state.hidden) { + obj.state.hidden = true; + this._node_changed(obj.parent); + if(!skip_redraw) { + this.redraw(); + } + /** + * triggered when an node is hidden + * @event + * @name hide_node.jstree + * @param {Object} node the hidden node + */ + this.trigger('hide_node', { 'node' : obj }); + } + }, + /** + * shows a node + * @name show_node(obj) + * @param {mixed} obj the node to show + * @param {Boolean} skip_redraw internal parameter controlling if redraw is called + * @trigger show_node.jstree + */ + show_node : function (obj, skip_redraw) { + var t1, t2; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.show_node(obj[t1], true); + } + if (!skip_redraw) { + this.redraw(); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + if(obj.state.hidden) { + obj.state.hidden = false; + this._node_changed(obj.parent); + if(!skip_redraw) { + this.redraw(); + } + /** + * triggered when an node is shown + * @event + * @name show_node.jstree + * @param {Object} node the shown node + */ + this.trigger('show_node', { 'node' : obj }); + } + }, + /** + * hides all nodes + * @name hide_all() + * @trigger hide_all.jstree + */ + hide_all : function (skip_redraw) { + var i, m = this._model.data, ids = []; + for(i in m) { + if(m.hasOwnProperty(i) && i !== $.jstree.root && !m[i].state.hidden) { + m[i].state.hidden = true; + ids.push(i); + } + } + this._model.force_full_redraw = true; + if(!skip_redraw) { + this.redraw(); + } + /** + * triggered when all nodes are hidden + * @event + * @name hide_all.jstree + * @param {Array} nodes the IDs of all hidden nodes + */ + this.trigger('hide_all', { 'nodes' : ids }); + return ids; + }, + /** + * shows all nodes + * @name show_all() + * @trigger show_all.jstree + */ + show_all : function (skip_redraw) { + var i, m = this._model.data, ids = []; + for(i in m) { + if(m.hasOwnProperty(i) && i !== $.jstree.root && m[i].state.hidden) { + m[i].state.hidden = false; + ids.push(i); + } + } + this._model.force_full_redraw = true; + if(!skip_redraw) { + this.redraw(); + } + /** + * triggered when all nodes are shown + * @event + * @name show_all.jstree + * @param {Array} nodes the IDs of all shown nodes + */ + this.trigger('show_all', { 'nodes' : ids }); + return ids; + }, + /** + * called when a node is selected by the user. Used internally. + * @private + * @name activate_node(obj, e) + * @param {mixed} obj the node + * @param {Object} e the related event + * @trigger activate_node.jstree, changed.jstree + */ + activate_node : function (obj, e) { + if(this.is_disabled(obj)) { + return false; + } + if(!e || typeof e !== 'object') { + e = {}; + } + + // ensure last_clicked is still in the DOM, make it fresh (maybe it was moved?) and make sure it is still selected, if not - make last_clicked the last selected node + this._data.core.last_clicked = this._data.core.last_clicked && this._data.core.last_clicked.id !== undefined ? this.get_node(this._data.core.last_clicked.id) : null; + if(this._data.core.last_clicked && !this._data.core.last_clicked.state.selected) { this._data.core.last_clicked = null; } + if(!this._data.core.last_clicked && this._data.core.selected.length) { this._data.core.last_clicked = this.get_node(this._data.core.selected[this._data.core.selected.length - 1]); } + + if(!this.settings.core.multiple || (!e.metaKey && !e.ctrlKey && !e.shiftKey) || (e.shiftKey && (!this._data.core.last_clicked || !this.get_parent(obj) || this.get_parent(obj) !== this._data.core.last_clicked.parent ) )) { + if(!this.settings.core.multiple && (e.metaKey || e.ctrlKey || e.shiftKey) && this.is_selected(obj)) { + this.deselect_node(obj, false, e); + } + else { + this.deselect_all(true); + this.select_node(obj, false, false, e); + this._data.core.last_clicked = this.get_node(obj); + } + } + else { + if(e.shiftKey) { + var o = this.get_node(obj).id, + l = this._data.core.last_clicked.id, + p = this.get_node(this._data.core.last_clicked.parent).children, + c = false, + i, j; + for(i = 0, j = p.length; i < j; i += 1) { + // separate IFs work whem o and l are the same + if(p[i] === o) { + c = !c; + } + if(p[i] === l) { + c = !c; + } + if(!this.is_disabled(p[i]) && (c || p[i] === o || p[i] === l)) { + if (!this.is_hidden(p[i])) { + this.select_node(p[i], true, false, e); + } + } + else { + this.deselect_node(p[i], true, e); + } + } + this.trigger('changed', { 'action' : 'select_node', 'node' : this.get_node(obj), 'selected' : this._data.core.selected, 'event' : e }); + } + else { + if(!this.is_selected(obj)) { + this.select_node(obj, false, false, e); + } + else { + this.deselect_node(obj, false, e); + } + } + } + /** + * triggered when an node is clicked or intercated with by the user + * @event + * @name activate_node.jstree + * @param {Object} node + * @param {Object} event the ooriginal event (if any) which triggered the call (may be an empty object) + */ + this.trigger('activate_node', { 'node' : this.get_node(obj), 'event' : e }); + }, + /** + * applies the hover state on a node, called when a node is hovered by the user. Used internally. + * @private + * @name hover_node(obj) + * @param {mixed} obj + * @trigger hover_node.jstree + */ + hover_node : function (obj) { + obj = this.get_node(obj, true); + if(!obj || !obj.length || obj.children('.jstree-hovered').length) { + return false; + } + var o = this.element.find('.jstree-hovered'), t = this.element; + if(o && o.length) { this.dehover_node(o); } + + obj.children('.jstree-anchor').addClass('jstree-hovered'); + /** + * triggered when an node is hovered + * @event + * @name hover_node.jstree + * @param {Object} node + */ + this.trigger('hover_node', { 'node' : this.get_node(obj) }); + setTimeout(function () { t.attr('aria-activedescendant', obj[0].id); }, 0); + }, + /** + * removes the hover state from a nodecalled when a node is no longer hovered by the user. Used internally. + * @private + * @name dehover_node(obj) + * @param {mixed} obj + * @trigger dehover_node.jstree + */ + dehover_node : function (obj) { + obj = this.get_node(obj, true); + if(!obj || !obj.length || !obj.children('.jstree-hovered').length) { + return false; + } + obj.children('.jstree-anchor').removeClass('jstree-hovered'); + /** + * triggered when an node is no longer hovered + * @event + * @name dehover_node.jstree + * @param {Object} node + */ + this.trigger('dehover_node', { 'node' : this.get_node(obj) }); + }, + /** + * select a node + * @name select_node(obj [, supress_event, prevent_open]) + * @param {mixed} obj an array can be used to select multiple nodes + * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered + * @param {Boolean} prevent_open if set to `true` parents of the selected node won't be opened + * @trigger select_node.jstree, changed.jstree + */ + select_node : function (obj, supress_event, prevent_open, e) { + var dom, t1, t2, th; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.select_node(obj[t1], supress_event, prevent_open, e); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + dom = this.get_node(obj, true); + if(!obj.state.selected) { + obj.state.selected = true; + this._data.core.selected.push(obj.id); + if(!prevent_open) { + dom = this._open_to(obj); + } + if(dom && dom.length) { + dom.attr('aria-selected', true).children('.jstree-anchor').addClass('jstree-clicked'); + } + /** + * triggered when an node is selected + * @event + * @name select_node.jstree + * @param {Object} node + * @param {Array} selected the current selection + * @param {Object} event the event (if any) that triggered this select_node + */ + this.trigger('select_node', { 'node' : obj, 'selected' : this._data.core.selected, 'event' : e }); + if(!supress_event) { + /** + * triggered when selection changes + * @event + * @name changed.jstree + * @param {Object} node + * @param {Object} action the action that caused the selection to change + * @param {Array} selected the current selection + * @param {Object} event the event (if any) that triggered this changed event + */ + this.trigger('changed', { 'action' : 'select_node', 'node' : obj, 'selected' : this._data.core.selected, 'event' : e }); + } + } + }, + /** + * deselect a node + * @name deselect_node(obj [, supress_event]) + * @param {mixed} obj an array can be used to deselect multiple nodes + * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered + * @trigger deselect_node.jstree, changed.jstree + */ + deselect_node : function (obj, supress_event, e) { + var t1, t2, dom; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.deselect_node(obj[t1], supress_event, e); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + dom = this.get_node(obj, true); + if(obj.state.selected) { + obj.state.selected = false; + this._data.core.selected = $.vakata.array_remove_item(this._data.core.selected, obj.id); + if(dom.length) { + dom.attr('aria-selected', false).children('.jstree-anchor').removeClass('jstree-clicked'); + } + /** + * triggered when an node is deselected + * @event + * @name deselect_node.jstree + * @param {Object} node + * @param {Array} selected the current selection + * @param {Object} event the event (if any) that triggered this deselect_node + */ + this.trigger('deselect_node', { 'node' : obj, 'selected' : this._data.core.selected, 'event' : e }); + if(!supress_event) { + this.trigger('changed', { 'action' : 'deselect_node', 'node' : obj, 'selected' : this._data.core.selected, 'event' : e }); + } + } + }, + /** + * select all nodes in the tree + * @name select_all([supress_event]) + * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered + * @trigger select_all.jstree, changed.jstree + */ + select_all : function (supress_event) { + var tmp = this._data.core.selected.concat([]), i, j; + this._data.core.selected = this._model.data[$.jstree.root].children_d.concat(); + for(i = 0, j = this._data.core.selected.length; i < j; i++) { + if(this._model.data[this._data.core.selected[i]]) { + this._model.data[this._data.core.selected[i]].state.selected = true; + } + } + this.redraw(true); + /** + * triggered when all nodes are selected + * @event + * @name select_all.jstree + * @param {Array} selected the current selection + */ + this.trigger('select_all', { 'selected' : this._data.core.selected }); + if(!supress_event) { + this.trigger('changed', { 'action' : 'select_all', 'selected' : this._data.core.selected, 'old_selection' : tmp }); + } + }, + /** + * deselect all selected nodes + * @name deselect_all([supress_event]) + * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered + * @trigger deselect_all.jstree, changed.jstree + */ + deselect_all : function (supress_event) { + var tmp = this._data.core.selected.concat([]), i, j; + for(i = 0, j = this._data.core.selected.length; i < j; i++) { + if(this._model.data[this._data.core.selected[i]]) { + this._model.data[this._data.core.selected[i]].state.selected = false; + } + } + this._data.core.selected = []; + this.element.find('.jstree-clicked').removeClass('jstree-clicked').parent().attr('aria-selected', false); + /** + * triggered when all nodes are deselected + * @event + * @name deselect_all.jstree + * @param {Object} node the previous selection + * @param {Array} selected the current selection + */ + this.trigger('deselect_all', { 'selected' : this._data.core.selected, 'node' : tmp }); + if(!supress_event) { + this.trigger('changed', { 'action' : 'deselect_all', 'selected' : this._data.core.selected, 'old_selection' : tmp }); + } + }, + /** + * checks if a node is selected + * @name is_selected(obj) + * @param {mixed} obj + * @return {Boolean} + */ + is_selected : function (obj) { + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + return obj.state.selected; + }, + /** + * get an array of all selected nodes + * @name get_selected([full]) + * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned + * @return {Array} + */ + get_selected : function (full) { + return full ? $.map(this._data.core.selected, $.proxy(function (i) { return this.get_node(i); }, this)) : this._data.core.selected.slice(); + }, + /** + * get an array of all top level selected nodes (ignoring children of selected nodes) + * @name get_top_selected([full]) + * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned + * @return {Array} + */ + get_top_selected : function (full) { + var tmp = this.get_selected(true), + obj = {}, i, j, k, l; + for(i = 0, j = tmp.length; i < j; i++) { + obj[tmp[i].id] = tmp[i]; + } + for(i = 0, j = tmp.length; i < j; i++) { + for(k = 0, l = tmp[i].children_d.length; k < l; k++) { + if(obj[tmp[i].children_d[k]]) { + delete obj[tmp[i].children_d[k]]; + } + } + } + tmp = []; + for(i in obj) { + if(obj.hasOwnProperty(i)) { + tmp.push(i); + } + } + return full ? $.map(tmp, $.proxy(function (i) { return this.get_node(i); }, this)) : tmp; + }, + /** + * get an array of all bottom level selected nodes (ignoring selected parents) + * @name get_bottom_selected([full]) + * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned + * @return {Array} + */ + get_bottom_selected : function (full) { + var tmp = this.get_selected(true), + obj = [], i, j; + for(i = 0, j = tmp.length; i < j; i++) { + if(!tmp[i].children.length) { + obj.push(tmp[i].id); + } + } + return full ? $.map(obj, $.proxy(function (i) { return this.get_node(i); }, this)) : obj; + }, + /** + * gets the current state of the tree so that it can be restored later with `set_state(state)`. Used internally. + * @name get_state() + * @private + * @return {Object} + */ + get_state : function () { + var state = { + 'core' : { + 'open' : [], + 'loaded' : [], + 'scroll' : { + 'left' : this.element.scrollLeft(), + 'top' : this.element.scrollTop() + }, + /*! + 'themes' : { + 'name' : this.get_theme(), + 'icons' : this._data.core.themes.icons, + 'dots' : this._data.core.themes.dots + }, + */ + 'selected' : [] + } + }, i; + for(i in this._model.data) { + if(this._model.data.hasOwnProperty(i)) { + if(i !== $.jstree.root) { + if(this._model.data[i].state.loaded && this.settings.core.loaded_state) { + state.core.loaded.push(i); + } + if(this._model.data[i].state.opened) { + state.core.open.push(i); + } + if(this._model.data[i].state.selected) { + state.core.selected.push(i); + } + } + } + } + return state; + }, + /** + * sets the state of the tree. Used internally. + * @name set_state(state [, callback]) + * @private + * @param {Object} state the state to restore. Keep in mind this object is passed by reference and jstree will modify it. + * @param {Function} callback an optional function to execute once the state is restored. + * @trigger set_state.jstree + */ + set_state : function (state, callback) { + if(state) { + if(state.core && state.core.selected && state.core.initial_selection === undefined) { + state.core.initial_selection = this._data.core.selected.concat([]).sort().join(','); + } + if(state.core) { + var res, n, t, _this, i; + if(state.core.loaded) { + if(!this.settings.core.loaded_state || !$.isArray(state.core.loaded) || !state.core.loaded.length) { + delete state.core.loaded; + this.set_state(state, callback); + } + else { + this._load_nodes(state.core.loaded, function (nodes) { + delete state.core.loaded; + this.set_state(state, callback); + }); + } + return false; + } + if(state.core.open) { + if(!$.isArray(state.core.open) || !state.core.open.length) { + delete state.core.open; + this.set_state(state, callback); + } + else { + this._load_nodes(state.core.open, function (nodes) { + this.open_node(nodes, false, 0); + delete state.core.open; + this.set_state(state, callback); + }); + } + return false; + } + if(state.core.scroll) { + if(state.core.scroll && state.core.scroll.left !== undefined) { + this.element.scrollLeft(state.core.scroll.left); + } + if(state.core.scroll && state.core.scroll.top !== undefined) { + this.element.scrollTop(state.core.scroll.top); + } + delete state.core.scroll; + this.set_state(state, callback); + return false; + } + if(state.core.selected) { + _this = this; + if (state.core.initial_selection === undefined || + state.core.initial_selection === this._data.core.selected.concat([]).sort().join(',') + ) { + this.deselect_all(); + $.each(state.core.selected, function (i, v) { + _this.select_node(v, false, true); + }); + } + delete state.core.initial_selection; + delete state.core.selected; + this.set_state(state, callback); + return false; + } + for(i in state) { + if(state.hasOwnProperty(i) && i !== "core" && $.inArray(i, this.settings.plugins) === -1) { + delete state[i]; + } + } + if($.isEmptyObject(state.core)) { + delete state.core; + this.set_state(state, callback); + return false; + } + } + if($.isEmptyObject(state)) { + state = null; + if(callback) { callback.call(this); } + /** + * triggered when a `set_state` call completes + * @event + * @name set_state.jstree + */ + this.trigger('set_state'); + return false; + } + return true; + } + return false; + }, + /** + * refreshes the tree - all nodes are reloaded with calls to `load_node`. + * @name refresh() + * @param {Boolean} skip_loading an option to skip showing the loading indicator + * @param {Mixed} forget_state if set to `true` state will not be reapplied, if set to a function (receiving the current state as argument) the result of that function will be used as state + * @trigger refresh.jstree + */ + refresh : function (skip_loading, forget_state) { + this._data.core.state = forget_state === true ? {} : this.get_state(); + if(forget_state && $.isFunction(forget_state)) { this._data.core.state = forget_state.call(this, this._data.core.state); } + this._cnt = 0; + this._model.data = {}; + this._model.data[$.jstree.root] = { + id : $.jstree.root, + parent : null, + parents : [], + children : [], + children_d : [], + state : { loaded : false } + }; + this._data.core.selected = []; + this._data.core.last_clicked = null; + this._data.core.focused = null; + + var c = this.get_container_ul()[0].className; + if(!skip_loading) { + this.element.html("<"+"ul class='"+c+"' role='group'><"+"li class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='treeitem' id='j"+this._id+"_loading'><"+"a class='jstree-anchor' href='#'>" + this.get_string("Loading ...") + ""); + this.element.attr('aria-activedescendant','j'+this._id+'_loading'); + } + this.load_node($.jstree.root, function (o, s) { + if(s) { + this.get_container_ul()[0].className = c; + if(this._firstChild(this.get_container_ul()[0])) { + this.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id); + } + this.set_state($.extend(true, {}, this._data.core.state), function () { + /** + * triggered when a `refresh` call completes + * @event + * @name refresh.jstree + */ + this.trigger('refresh'); + }); + } + this._data.core.state = null; + }); + }, + /** + * refreshes a node in the tree (reload its children) all opened nodes inside that node are reloaded with calls to `load_node`. + * @name refresh_node(obj) + * @param {mixed} obj the node + * @trigger refresh_node.jstree + */ + refresh_node : function (obj) { + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + var opened = [], to_load = [], s = this._data.core.selected.concat([]); + to_load.push(obj.id); + if(obj.state.opened === true) { opened.push(obj.id); } + this.get_node(obj, true).find('.jstree-open').each(function() { to_load.push(this.id); opened.push(this.id); }); + this._load_nodes(to_load, $.proxy(function (nodes) { + this.open_node(opened, false, 0); + this.select_node(s); + /** + * triggered when a node is refreshed + * @event + * @name refresh_node.jstree + * @param {Object} node - the refreshed node + * @param {Array} nodes - an array of the IDs of the nodes that were reloaded + */ + this.trigger('refresh_node', { 'node' : obj, 'nodes' : nodes }); + }, this), false, true); + }, + /** + * set (change) the ID of a node + * @name set_id(obj, id) + * @param {mixed} obj the node + * @param {String} id the new ID + * @return {Boolean} + * @trigger set_id.jstree + */ + set_id : function (obj, id) { + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + var i, j, m = this._model.data, old = obj.id; + id = id.toString(); + // update parents (replace current ID with new one in children and children_d) + m[obj.parent].children[$.inArray(obj.id, m[obj.parent].children)] = id; + for(i = 0, j = obj.parents.length; i < j; i++) { + m[obj.parents[i]].children_d[$.inArray(obj.id, m[obj.parents[i]].children_d)] = id; + } + // update children (replace current ID with new one in parent and parents) + for(i = 0, j = obj.children.length; i < j; i++) { + m[obj.children[i]].parent = id; + } + for(i = 0, j = obj.children_d.length; i < j; i++) { + m[obj.children_d[i]].parents[$.inArray(obj.id, m[obj.children_d[i]].parents)] = id; + } + i = $.inArray(obj.id, this._data.core.selected); + if(i !== -1) { this._data.core.selected[i] = id; } + // update model and obj itself (obj.id, this._model.data[KEY]) + i = this.get_node(obj.id, true); + if(i) { + i.attr('id', id); //.children('.jstree-anchor').attr('id', id + '_anchor').end().attr('aria-labelledby', id + '_anchor'); + if(this.element.attr('aria-activedescendant') === obj.id) { + this.element.attr('aria-activedescendant', id); + } + } + delete m[obj.id]; + obj.id = id; + obj.li_attr.id = id; + m[id] = obj; + /** + * triggered when a node id value is changed + * @event + * @name set_id.jstree + * @param {Object} node + * @param {String} old the old id + */ + this.trigger('set_id',{ "node" : obj, "new" : obj.id, "old" : old }); + return true; + }, + /** + * get the text value of a node + * @name get_text(obj) + * @param {mixed} obj the node + * @return {String} + */ + get_text : function (obj) { + obj = this.get_node(obj); + return (!obj || obj.id === $.jstree.root) ? false : obj.text; + }, + /** + * set the text value of a node. Used internally, please use `rename_node(obj, val)`. + * @private + * @name set_text(obj, val) + * @param {mixed} obj the node, you can pass an array to set the text on multiple nodes + * @param {String} val the new text value + * @return {Boolean} + * @trigger set_text.jstree + */ + set_text : function (obj, val) { + var t1, t2; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.set_text(obj[t1], val); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + obj.text = val; + if(this.get_node(obj, true).length) { + this.redraw_node(obj.id); + } + /** + * triggered when a node text value is changed + * @event + * @name set_text.jstree + * @param {Object} obj + * @param {String} text the new value + */ + this.trigger('set_text',{ "obj" : obj, "text" : val }); + return true; + }, + /** + * gets a JSON representation of a node (or the whole tree) + * @name get_json([obj, options]) + * @param {mixed} obj + * @param {Object} options + * @param {Boolean} options.no_state do not return state information + * @param {Boolean} options.no_id do not return ID + * @param {Boolean} options.no_children do not include children + * @param {Boolean} options.no_data do not include node data + * @param {Boolean} options.no_li_attr do not include LI attributes + * @param {Boolean} options.no_a_attr do not include A attributes + * @param {Boolean} options.flat return flat JSON instead of nested + * @return {Object} + */ + get_json : function (obj, options, flat) { + obj = this.get_node(obj || $.jstree.root); + if(!obj) { return false; } + if(options && options.flat && !flat) { flat = []; } + var tmp = { + 'id' : obj.id, + 'text' : obj.text, + 'icon' : this.get_icon(obj), + 'li_attr' : $.extend(true, {}, obj.li_attr), + 'a_attr' : $.extend(true, {}, obj.a_attr), + 'state' : {}, + 'data' : options && options.no_data ? false : $.extend(true, $.isArray(obj.data)?[]:{}, obj.data) + //( this.get_node(obj, true).length ? this.get_node(obj, true).data() : obj.data ), + }, i, j; + if(options && options.flat) { + tmp.parent = obj.parent; + } + else { + tmp.children = []; + } + if(!options || !options.no_state) { + for(i in obj.state) { + if(obj.state.hasOwnProperty(i)) { + tmp.state[i] = obj.state[i]; + } + } + } else { + delete tmp.state; + } + if(options && options.no_li_attr) { + delete tmp.li_attr; + } + if(options && options.no_a_attr) { + delete tmp.a_attr; + } + if(options && options.no_id) { + delete tmp.id; + if(tmp.li_attr && tmp.li_attr.id) { + delete tmp.li_attr.id; + } + if(tmp.a_attr && tmp.a_attr.id) { + delete tmp.a_attr.id; + } + } + if(options && options.flat && obj.id !== $.jstree.root) { + flat.push(tmp); + } + if(!options || !options.no_children) { + for(i = 0, j = obj.children.length; i < j; i++) { + if(options && options.flat) { + this.get_json(obj.children[i], options, flat); + } + else { + tmp.children.push(this.get_json(obj.children[i], options)); + } + } + } + return options && options.flat ? flat : (obj.id === $.jstree.root ? tmp.children : tmp); + }, + /** + * create a new node (do not confuse with load_node) + * @name create_node([par, node, pos, callback, is_loaded]) + * @param {mixed} par the parent node (to create a root node use either "#" (string) or `null`) + * @param {mixed} node the data for the new node (a valid JSON object, or a simple string with the name) + * @param {mixed} pos the index at which to insert the node, "first" and "last" are also supported, default is "last" + * @param {Function} callback a function to be called once the node is created + * @param {Boolean} is_loaded internal argument indicating if the parent node was succesfully loaded + * @return {String} the ID of the newly create node + * @trigger model.jstree, create_node.jstree + */ + create_node : function (par, node, pos, callback, is_loaded) { + if(par === null) { par = $.jstree.root; } + par = this.get_node(par); + if(!par) { return false; } + pos = pos === undefined ? "last" : pos; + if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) { + return this.load_node(par, function () { this.create_node(par, node, pos, callback, true); }); + } + if(!node) { node = { "text" : this.get_string('New node') }; } + if(typeof node === "string") { + node = { "text" : node }; + } else { + node = $.extend(true, {}, node); + } + if(node.text === undefined) { node.text = this.get_string('New node'); } + var tmp, dpc, i, j; + + if(par.id === $.jstree.root) { + if(pos === "before") { pos = "first"; } + if(pos === "after") { pos = "last"; } + } + switch(pos) { + case "before": + tmp = this.get_node(par.parent); + pos = $.inArray(par.id, tmp.children); + par = tmp; + break; + case "after" : + tmp = this.get_node(par.parent); + pos = $.inArray(par.id, tmp.children) + 1; + par = tmp; + break; + case "inside": + case "first": + pos = 0; + break; + case "last": + pos = par.children.length; + break; + default: + if(!pos) { pos = 0; } + break; + } + if(pos > par.children.length) { pos = par.children.length; } + if(!node.id) { node.id = true; } + if(!this.check("create_node", node, par, pos)) { + this.settings.core.error.call(this, this._data.core.last_error); + return false; + } + if(node.id === true) { delete node.id; } + node = this._parse_model_from_json(node, par.id, par.parents.concat()); + if(!node) { return false; } + tmp = this.get_node(node); + dpc = []; + dpc.push(node); + dpc = dpc.concat(tmp.children_d); + this.trigger('model', { "nodes" : dpc, "parent" : par.id }); + + par.children_d = par.children_d.concat(dpc); + for(i = 0, j = par.parents.length; i < j; i++) { + this._model.data[par.parents[i]].children_d = this._model.data[par.parents[i]].children_d.concat(dpc); + } + node = tmp; + tmp = []; + for(i = 0, j = par.children.length; i < j; i++) { + tmp[i >= pos ? i+1 : i] = par.children[i]; + } + tmp[pos] = node.id; + par.children = tmp; + + this.redraw_node(par, true); + /** + * triggered when a node is created + * @event + * @name create_node.jstree + * @param {Object} node + * @param {String} parent the parent's ID + * @param {Number} position the position of the new node among the parent's children + */ + this.trigger('create_node', { "node" : this.get_node(node), "parent" : par.id, "position" : pos }); + if(callback) { callback.call(this, this.get_node(node)); } + return node.id; + }, + /** + * set the text value of a node + * @name rename_node(obj, val) + * @param {mixed} obj the node, you can pass an array to rename multiple nodes to the same name + * @param {String} val the new text value + * @return {Boolean} + * @trigger rename_node.jstree + */ + rename_node : function (obj, val) { + var t1, t2, old; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.rename_node(obj[t1], val); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + old = obj.text; + if(!this.check("rename_node", obj, this.get_parent(obj), val)) { + this.settings.core.error.call(this, this._data.core.last_error); + return false; + } + this.set_text(obj, val); // .apply(this, Array.prototype.slice.call(arguments)) + /** + * triggered when a node is renamed + * @event + * @name rename_node.jstree + * @param {Object} node + * @param {String} text the new value + * @param {String} old the old value + */ + this.trigger('rename_node', { "node" : obj, "text" : val, "old" : old }); + return true; + }, + /** + * remove a node + * @name delete_node(obj) + * @param {mixed} obj the node, you can pass an array to delete multiple nodes + * @return {Boolean} + * @trigger delete_node.jstree, changed.jstree + */ + delete_node : function (obj) { + var t1, t2, par, pos, tmp, i, j, k, l, c, top, lft; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.delete_node(obj[t1]); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + par = this.get_node(obj.parent); + pos = $.inArray(obj.id, par.children); + c = false; + if(!this.check("delete_node", obj, par, pos)) { + this.settings.core.error.call(this, this._data.core.last_error); + return false; + } + if(pos !== -1) { + par.children = $.vakata.array_remove(par.children, pos); + } + tmp = obj.children_d.concat([]); + tmp.push(obj.id); + for(i = 0, j = obj.parents.length; i < j; i++) { + this._model.data[obj.parents[i]].children_d = $.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function (v) { + return $.inArray(v, tmp) === -1; + }); + } + for(k = 0, l = tmp.length; k < l; k++) { + if(this._model.data[tmp[k]].state.selected) { + c = true; + break; + } + } + if (c) { + this._data.core.selected = $.vakata.array_filter(this._data.core.selected, function (v) { + return $.inArray(v, tmp) === -1; + }); + } + /** + * triggered when a node is deleted + * @event + * @name delete_node.jstree + * @param {Object} node + * @param {String} parent the parent's ID + */ + this.trigger('delete_node', { "node" : obj, "parent" : par.id }); + if(c) { + this.trigger('changed', { 'action' : 'delete_node', 'node' : obj, 'selected' : this._data.core.selected, 'parent' : par.id }); + } + for(k = 0, l = tmp.length; k < l; k++) { + delete this._model.data[tmp[k]]; + } + if($.inArray(this._data.core.focused, tmp) !== -1) { + this._data.core.focused = null; + top = this.element[0].scrollTop; + lft = this.element[0].scrollLeft; + if(par.id === $.jstree.root) { + if (this._model.data[$.jstree.root].children[0]) { + this.get_node(this._model.data[$.jstree.root].children[0], true).children('.jstree-anchor').focus(); + } + } + else { + this.get_node(par, true).children('.jstree-anchor').focus(); + } + this.element[0].scrollTop = top; + this.element[0].scrollLeft = lft; + } + this.redraw_node(par, true); + return true; + }, + /** + * check if an operation is premitted on the tree. Used internally. + * @private + * @name check(chk, obj, par, pos) + * @param {String} chk the operation to check, can be "create_node", "rename_node", "delete_node", "copy_node" or "move_node" + * @param {mixed} obj the node + * @param {mixed} par the parent + * @param {mixed} pos the position to insert at, or if "rename_node" - the new name + * @param {mixed} more some various additional information, for example if a "move_node" operations is triggered by DND this will be the hovered node + * @return {Boolean} + */ + check : function (chk, obj, par, pos, more) { + obj = obj && obj.id ? obj : this.get_node(obj); + par = par && par.id ? par : this.get_node(par); + var tmp = chk.match(/^move_node|copy_node|create_node$/i) ? par : obj, + chc = this.settings.core.check_callback; + if(chk === "move_node" || chk === "copy_node") { + if((!more || !more.is_multi) && (obj.id === par.id || (chk === "move_node" && $.inArray(obj.id, par.children) === pos) || $.inArray(par.id, obj.children_d) !== -1)) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_01', 'reason' : 'Moving parent inside child', 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + return false; + } + } + if(tmp && tmp.data) { tmp = tmp.data; } + if(tmp && tmp.functions && (tmp.functions[chk] === false || tmp.functions[chk] === true)) { + if(tmp.functions[chk] === false) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_02', 'reason' : 'Node data prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + } + return tmp.functions[chk]; + } + if(chc === false || ($.isFunction(chc) && chc.call(this, chk, obj, par, pos, more) === false) || (chc && chc[chk] === false)) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_03', 'reason' : 'User config for core.check_callback prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + return false; + } + return true; + }, + /** + * get the last error + * @name last_error() + * @return {Object} + */ + last_error : function () { + return this._data.core.last_error; + }, + /** + * move a node to a new parent + * @name move_node(obj, par [, pos, callback, is_loaded]) + * @param {mixed} obj the node to move, pass an array to move multiple nodes + * @param {mixed} par the new parent + * @param {mixed} pos the position to insert at (besides integer values, "first" and "last" are supported, as well as "before" and "after"), defaults to integer `0` + * @param {function} callback a function to call once the move is completed, receives 3 arguments - the node, the new parent and the position + * @param {Boolean} is_loaded internal parameter indicating if the parent node has been loaded + * @param {Boolean} skip_redraw internal parameter indicating if the tree should be redrawn + * @param {Boolean} instance internal parameter indicating if the node comes from another instance + * @trigger move_node.jstree + */ + move_node : function (obj, par, pos, callback, is_loaded, skip_redraw, origin) { + var t1, t2, old_par, old_pos, new_par, old_ins, is_multi, dpc, tmp, i, j, k, l, p; + + par = this.get_node(par); + pos = pos === undefined ? 0 : pos; + if(!par) { return false; } + if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) { + return this.load_node(par, function () { this.move_node(obj, par, pos, callback, true, false, origin); }); + } + + if($.isArray(obj)) { + if(obj.length === 1) { + obj = obj[0]; + } + else { + //obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + if((tmp = this.move_node(obj[t1], par, pos, callback, is_loaded, false, origin))) { + par = tmp; + pos = "after"; + } + } + this.redraw(); + return true; + } + } + obj = obj && obj.id ? obj : this.get_node(obj); + + if(!obj || obj.id === $.jstree.root) { return false; } + + old_par = (obj.parent || $.jstree.root).toString(); + new_par = (!pos.toString().match(/^(before|after)$/) || par.id === $.jstree.root) ? par : this.get_node(par.parent); + old_ins = origin ? origin : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id)); + is_multi = !old_ins || !old_ins._id || (this._id !== old_ins._id); + old_pos = old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id, old_ins._model.data[old_par].children) : -1; + if(old_ins && old_ins._id) { + obj = old_ins._model.data[obj.id]; + } + + if(is_multi) { + if((tmp = this.copy_node(obj, par, pos, callback, is_loaded, false, origin))) { + if(old_ins) { old_ins.delete_node(obj); } + return tmp; + } + return false; + } + //var m = this._model.data; + if(par.id === $.jstree.root) { + if(pos === "before") { pos = "first"; } + if(pos === "after") { pos = "last"; } + } + switch(pos) { + case "before": + pos = $.inArray(par.id, new_par.children); + break; + case "after" : + pos = $.inArray(par.id, new_par.children) + 1; + break; + case "inside": + case "first": + pos = 0; + break; + case "last": + pos = new_par.children.length; + break; + default: + if(!pos) { pos = 0; } + break; + } + if(pos > new_par.children.length) { pos = new_par.children.length; } + if(!this.check("move_node", obj, new_par, pos, { 'core' : true, 'origin' : origin, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) { + this.settings.core.error.call(this, this._data.core.last_error); + return false; + } + if(obj.parent === new_par.id) { + dpc = new_par.children.concat(); + tmp = $.inArray(obj.id, dpc); + if(tmp !== -1) { + dpc = $.vakata.array_remove(dpc, tmp); + if(pos > tmp) { pos--; } + } + tmp = []; + for(i = 0, j = dpc.length; i < j; i++) { + tmp[i >= pos ? i+1 : i] = dpc[i]; + } + tmp[pos] = obj.id; + new_par.children = tmp; + this._node_changed(new_par.id); + this.redraw(new_par.id === $.jstree.root); + } + else { + // clean old parent and up + tmp = obj.children_d.concat(); + tmp.push(obj.id); + for(i = 0, j = obj.parents.length; i < j; i++) { + dpc = []; + p = old_ins._model.data[obj.parents[i]].children_d; + for(k = 0, l = p.length; k < l; k++) { + if($.inArray(p[k], tmp) === -1) { + dpc.push(p[k]); + } + } + old_ins._model.data[obj.parents[i]].children_d = dpc; + } + old_ins._model.data[old_par].children = $.vakata.array_remove_item(old_ins._model.data[old_par].children, obj.id); + + // insert into new parent and up + for(i = 0, j = new_par.parents.length; i < j; i++) { + this._model.data[new_par.parents[i]].children_d = this._model.data[new_par.parents[i]].children_d.concat(tmp); + } + dpc = []; + for(i = 0, j = new_par.children.length; i < j; i++) { + dpc[i >= pos ? i+1 : i] = new_par.children[i]; + } + dpc[pos] = obj.id; + new_par.children = dpc; + new_par.children_d.push(obj.id); + new_par.children_d = new_par.children_d.concat(obj.children_d); + + // update object + obj.parent = new_par.id; + tmp = new_par.parents.concat(); + tmp.unshift(new_par.id); + p = obj.parents.length; + obj.parents = tmp; + + // update object children + tmp = tmp.concat(); + for(i = 0, j = obj.children_d.length; i < j; i++) { + this._model.data[obj.children_d[i]].parents = this._model.data[obj.children_d[i]].parents.slice(0,p*-1); + Array.prototype.push.apply(this._model.data[obj.children_d[i]].parents, tmp); + } + + if(old_par === $.jstree.root || new_par.id === $.jstree.root) { + this._model.force_full_redraw = true; + } + if(!this._model.force_full_redraw) { + this._node_changed(old_par); + this._node_changed(new_par.id); + } + if(!skip_redraw) { + this.redraw(); + } + } + if(callback) { callback.call(this, obj, new_par, pos); } + /** + * triggered when a node is moved + * @event + * @name move_node.jstree + * @param {Object} node + * @param {String} parent the parent's ID + * @param {Number} position the position of the node among the parent's children + * @param {String} old_parent the old parent of the node + * @param {Number} old_position the old position of the node + * @param {Boolean} is_multi do the node and new parent belong to different instances + * @param {jsTree} old_instance the instance the node came from + * @param {jsTree} new_instance the instance of the new parent + */ + this.trigger('move_node', { "node" : obj, "parent" : new_par.id, "position" : pos, "old_parent" : old_par, "old_position" : old_pos, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this }); + return obj.id; + }, + /** + * copy a node to a new parent + * @name copy_node(obj, par [, pos, callback, is_loaded]) + * @param {mixed} obj the node to copy, pass an array to copy multiple nodes + * @param {mixed} par the new parent + * @param {mixed} pos the position to insert at (besides integer values, "first" and "last" are supported, as well as "before" and "after"), defaults to integer `0` + * @param {function} callback a function to call once the move is completed, receives 3 arguments - the node, the new parent and the position + * @param {Boolean} is_loaded internal parameter indicating if the parent node has been loaded + * @param {Boolean} skip_redraw internal parameter indicating if the tree should be redrawn + * @param {Boolean} instance internal parameter indicating if the node comes from another instance + * @trigger model.jstree copy_node.jstree + */ + copy_node : function (obj, par, pos, callback, is_loaded, skip_redraw, origin) { + var t1, t2, dpc, tmp, i, j, node, old_par, new_par, old_ins, is_multi; + + par = this.get_node(par); + pos = pos === undefined ? 0 : pos; + if(!par) { return false; } + if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) { + return this.load_node(par, function () { this.copy_node(obj, par, pos, callback, true, false, origin); }); + } + + if($.isArray(obj)) { + if(obj.length === 1) { + obj = obj[0]; + } + else { + //obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + if((tmp = this.copy_node(obj[t1], par, pos, callback, is_loaded, true, origin))) { + par = tmp; + pos = "after"; + } + } + this.redraw(); + return true; + } + } + obj = obj && obj.id ? obj : this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + + old_par = (obj.parent || $.jstree.root).toString(); + new_par = (!pos.toString().match(/^(before|after)$/) || par.id === $.jstree.root) ? par : this.get_node(par.parent); + old_ins = origin ? origin : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id)); + is_multi = !old_ins || !old_ins._id || (this._id !== old_ins._id); + + if(old_ins && old_ins._id) { + obj = old_ins._model.data[obj.id]; + } + + if(par.id === $.jstree.root) { + if(pos === "before") { pos = "first"; } + if(pos === "after") { pos = "last"; } + } + switch(pos) { + case "before": + pos = $.inArray(par.id, new_par.children); + break; + case "after" : + pos = $.inArray(par.id, new_par.children) + 1; + break; + case "inside": + case "first": + pos = 0; + break; + case "last": + pos = new_par.children.length; + break; + default: + if(!pos) { pos = 0; } + break; + } + if(pos > new_par.children.length) { pos = new_par.children.length; } + if(!this.check("copy_node", obj, new_par, pos, { 'core' : true, 'origin' : origin, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) { + this.settings.core.error.call(this, this._data.core.last_error); + return false; + } + node = old_ins ? old_ins.get_json(obj, { no_id : true, no_data : true, no_state : true }) : obj; + if(!node) { return false; } + if(node.id === true) { delete node.id; } + node = this._parse_model_from_json(node, new_par.id, new_par.parents.concat()); + if(!node) { return false; } + tmp = this.get_node(node); + if(obj && obj.state && obj.state.loaded === false) { tmp.state.loaded = false; } + dpc = []; + dpc.push(node); + dpc = dpc.concat(tmp.children_d); + this.trigger('model', { "nodes" : dpc, "parent" : new_par.id }); + + // insert into new parent and up + for(i = 0, j = new_par.parents.length; i < j; i++) { + this._model.data[new_par.parents[i]].children_d = this._model.data[new_par.parents[i]].children_d.concat(dpc); + } + dpc = []; + for(i = 0, j = new_par.children.length; i < j; i++) { + dpc[i >= pos ? i+1 : i] = new_par.children[i]; + } + dpc[pos] = tmp.id; + new_par.children = dpc; + new_par.children_d.push(tmp.id); + new_par.children_d = new_par.children_d.concat(tmp.children_d); + + if(new_par.id === $.jstree.root) { + this._model.force_full_redraw = true; + } + if(!this._model.force_full_redraw) { + this._node_changed(new_par.id); + } + if(!skip_redraw) { + this.redraw(new_par.id === $.jstree.root); + } + if(callback) { callback.call(this, tmp, new_par, pos); } + /** + * triggered when a node is copied + * @event + * @name copy_node.jstree + * @param {Object} node the copied node + * @param {Object} original the original node + * @param {String} parent the parent's ID + * @param {Number} position the position of the node among the parent's children + * @param {String} old_parent the old parent of the node + * @param {Number} old_position the position of the original node + * @param {Boolean} is_multi do the node and new parent belong to different instances + * @param {jsTree} old_instance the instance the node came from + * @param {jsTree} new_instance the instance of the new parent + */ + this.trigger('copy_node', { "node" : tmp, "original" : obj, "parent" : new_par.id, "position" : pos, "old_parent" : old_par, "old_position" : old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id, old_ins._model.data[old_par].children) : -1,'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this }); + return tmp.id; + }, + /** + * cut a node (a later call to `paste(obj)` would move the node) + * @name cut(obj) + * @param {mixed} obj multiple objects can be passed using an array + * @trigger cut.jstree + */ + cut : function (obj) { + if(!obj) { obj = this._data.core.selected.concat(); } + if(!$.isArray(obj)) { obj = [obj]; } + if(!obj.length) { return false; } + var tmp = [], o, t1, t2; + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + o = this.get_node(obj[t1]); + if(o && o.id && o.id !== $.jstree.root) { tmp.push(o); } + } + if(!tmp.length) { return false; } + ccp_node = tmp; + ccp_inst = this; + ccp_mode = 'move_node'; + /** + * triggered when nodes are added to the buffer for moving + * @event + * @name cut.jstree + * @param {Array} node + */ + this.trigger('cut', { "node" : obj }); + }, + /** + * copy a node (a later call to `paste(obj)` would copy the node) + * @name copy(obj) + * @param {mixed} obj multiple objects can be passed using an array + * @trigger copy.jstree + */ + copy : function (obj) { + if(!obj) { obj = this._data.core.selected.concat(); } + if(!$.isArray(obj)) { obj = [obj]; } + if(!obj.length) { return false; } + var tmp = [], o, t1, t2; + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + o = this.get_node(obj[t1]); + if(o && o.id && o.id !== $.jstree.root) { tmp.push(o); } + } + if(!tmp.length) { return false; } + ccp_node = tmp; + ccp_inst = this; + ccp_mode = 'copy_node'; + /** + * triggered when nodes are added to the buffer for copying + * @event + * @name copy.jstree + * @param {Array} node + */ + this.trigger('copy', { "node" : obj }); + }, + /** + * get the current buffer (any nodes that are waiting for a paste operation) + * @name get_buffer() + * @return {Object} an object consisting of `mode` ("copy_node" or "move_node"), `node` (an array of objects) and `inst` (the instance) + */ + get_buffer : function () { + return { 'mode' : ccp_mode, 'node' : ccp_node, 'inst' : ccp_inst }; + }, + /** + * check if there is something in the buffer to paste + * @name can_paste() + * @return {Boolean} + */ + can_paste : function () { + return ccp_mode !== false && ccp_node !== false; // && ccp_inst._model.data[ccp_node]; + }, + /** + * copy or move the previously cut or copied nodes to a new parent + * @name paste(obj [, pos]) + * @param {mixed} obj the new parent + * @param {mixed} pos the position to insert at (besides integer, "first" and "last" are supported), defaults to integer `0` + * @trigger paste.jstree + */ + paste : function (obj, pos) { + obj = this.get_node(obj); + if(!obj || !ccp_mode || !ccp_mode.match(/^(copy_node|move_node)$/) || !ccp_node) { return false; } + if(this[ccp_mode](ccp_node, obj, pos, false, false, false, ccp_inst)) { + /** + * triggered when paste is invoked + * @event + * @name paste.jstree + * @param {String} parent the ID of the receiving node + * @param {Array} node the nodes in the buffer + * @param {String} mode the performed operation - "copy_node" or "move_node" + */ + this.trigger('paste', { "parent" : obj.id, "node" : ccp_node, "mode" : ccp_mode }); + } + ccp_node = false; + ccp_mode = false; + ccp_inst = false; + }, + /** + * clear the buffer of previously copied or cut nodes + * @name clear_buffer() + * @trigger clear_buffer.jstree + */ + clear_buffer : function () { + ccp_node = false; + ccp_mode = false; + ccp_inst = false; + /** + * triggered when the copy / cut buffer is cleared + * @event + * @name clear_buffer.jstree + */ + this.trigger('clear_buffer'); + }, + /** + * put a node in edit mode (input field to rename the node) + * @name edit(obj [, default_text, callback]) + * @param {mixed} obj + * @param {String} default_text the text to populate the input with (if omitted or set to a non-string value the node's text value is used) + * @param {Function} callback a function to be called once the text box is blurred, it is called in the instance's scope and receives the node, a status parameter (true if the rename is successful, false otherwise) and a boolean indicating if the user cancelled the edit. You can access the node's title using .text + */ + edit : function (obj, default_text, callback) { + var rtl, w, a, s, t, h1, h2, fn, tmp, cancel = false; + obj = this.get_node(obj); + if(!obj) { return false; } + if(!this.check("edit", obj, this.get_parent(obj))) { + this.settings.core.error.call(this, this._data.core.last_error); + return false; + } + tmp = obj; + default_text = typeof default_text === 'string' ? default_text : obj.text; + this.set_text(obj, ""); + obj = this._open_to(obj); + tmp.text = default_text; + + rtl = this._data.core.rtl; + w = this.element.width(); + this._data.core.focused = tmp.id; + a = obj.children('.jstree-anchor').focus(); + s = $(''); + /*! + oi = obj.children("i:visible"), + ai = a.children("i:visible"), + w1 = oi.width() * oi.length, + w2 = ai.width() * ai.length, + */ + t = default_text; + h1 = $("<"+"div />", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo(document.body); + h2 = $("<"+"input />", { + "value" : t, + "class" : "jstree-rename-input", + // "size" : t.length, + "css" : { + "padding" : "0", + "border" : "1px solid silver", + "box-sizing" : "border-box", + "display" : "inline-block", + "height" : (this._data.core.li_height) + "px", + "lineHeight" : (this._data.core.li_height) + "px", + "width" : "150px" // will be set a bit further down + }, + "blur" : $.proxy(function (e) { + e.stopImmediatePropagation(); + e.preventDefault(); + var i = s.children(".jstree-rename-input"), + v = i.val(), + f = this.settings.core.force_text, + nv; + if(v === "") { v = t; } + h1.remove(); + s.replaceWith(a); + s.remove(); + t = f ? t : $('
').append($.parseHTML(t)).html(); + this.set_text(obj, t); + nv = !!this.rename_node(obj, f ? $('
').text(v).text() : $('
').append($.parseHTML(v)).html()); + if(!nv) { + this.set_text(obj, t); // move this up? and fix #483 + } + this._data.core.focused = tmp.id; + setTimeout($.proxy(function () { + var node = this.get_node(tmp.id, true); + if(node.length) { + this._data.core.focused = tmp.id; + node.children('.jstree-anchor').focus(); + } + }, this), 0); + if(callback) { + callback.call(this, tmp, nv, cancel); + } + h2 = null; + }, this), + "keydown" : function (e) { + var key = e.which; + if(key === 27) { + cancel = true; + this.value = t; + } + if(key === 27 || key === 13 || key === 37 || key === 38 || key === 39 || key === 40 || key === 32) { + e.stopImmediatePropagation(); + } + if(key === 27 || key === 13) { + e.preventDefault(); + this.blur(); + } + }, + "click" : function (e) { e.stopImmediatePropagation(); }, + "mousedown" : function (e) { e.stopImmediatePropagation(); }, + "keyup" : function (e) { + h2.width(Math.min(h1.text("pW" + this.value).width(),w)); + }, + "keypress" : function(e) { + if(e.which === 13) { return false; } + } + }); + fn = { + fontFamily : a.css('fontFamily') || '', + fontSize : a.css('fontSize') || '', + fontWeight : a.css('fontWeight') || '', + fontStyle : a.css('fontStyle') || '', + fontStretch : a.css('fontStretch') || '', + fontVariant : a.css('fontVariant') || '', + letterSpacing : a.css('letterSpacing') || '', + wordSpacing : a.css('wordSpacing') || '' + }; + s.attr('class', a.attr('class')).append(a.contents().clone()).append(h2); + a.replaceWith(s); + h1.css(fn); + h2.css(fn).width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select(); + $(document).one('mousedown.jstree touchstart.jstree dnd_start.vakata', function (e) { + if (h2 && e.target !== h2) { + $(h2).blur(); + } + }); + }, + + + /** + * changes the theme + * @name set_theme(theme_name [, theme_url]) + * @param {String} theme_name the name of the new theme to apply + * @param {mixed} theme_url the location of the CSS file for this theme. Omit or set to `false` if you manually included the file. Set to `true` to autoload from the `core.themes.dir` directory. + * @trigger set_theme.jstree + */ + set_theme : function (theme_name, theme_url) { + if(!theme_name) { return false; } + if(theme_url === true) { + var dir = this.settings.core.themes.dir; + if(!dir) { dir = $.jstree.path + '/themes'; } + theme_url = dir + '/' + theme_name + '/style.css'; + } + if(theme_url && $.inArray(theme_url, themes_loaded) === -1) { + $('head').append('<'+'link rel="stylesheet" href="' + theme_url + '" type="text/css" />'); + themes_loaded.push(theme_url); + } + if(this._data.core.themes.name) { + this.element.removeClass('jstree-' + this._data.core.themes.name); + } + this._data.core.themes.name = theme_name; + this.element.addClass('jstree-' + theme_name); + this.element[this.settings.core.themes.responsive ? 'addClass' : 'removeClass' ]('jstree-' + theme_name + '-responsive'); + /** + * triggered when a theme is set + * @event + * @name set_theme.jstree + * @param {String} theme the new theme + */ + this.trigger('set_theme', { 'theme' : theme_name }); + }, + /** + * gets the name of the currently applied theme name + * @name get_theme() + * @return {String} + */ + get_theme : function () { return this._data.core.themes.name; }, + /** + * changes the theme variant (if the theme has variants) + * @name set_theme_variant(variant_name) + * @param {String|Boolean} variant_name the variant to apply (if `false` is used the current variant is removed) + */ + set_theme_variant : function (variant_name) { + if(this._data.core.themes.variant) { + this.element.removeClass('jstree-' + this._data.core.themes.name + '-' + this._data.core.themes.variant); + } + this._data.core.themes.variant = variant_name; + if(variant_name) { + this.element.addClass('jstree-' + this._data.core.themes.name + '-' + this._data.core.themes.variant); + } + }, + /** + * gets the name of the currently applied theme variant + * @name get_theme() + * @return {String} + */ + get_theme_variant : function () { return this._data.core.themes.variant; }, + /** + * shows a striped background on the container (if the theme supports it) + * @name show_stripes() + */ + show_stripes : function () { + this._data.core.themes.stripes = true; + this.get_container_ul().addClass("jstree-striped"); + /** + * triggered when stripes are shown + * @event + * @name show_stripes.jstree + */ + this.trigger('show_stripes'); + }, + /** + * hides the striped background on the container + * @name hide_stripes() + */ + hide_stripes : function () { + this._data.core.themes.stripes = false; + this.get_container_ul().removeClass("jstree-striped"); + /** + * triggered when stripes are hidden + * @event + * @name hide_stripes.jstree + */ + this.trigger('hide_stripes'); + }, + /** + * toggles the striped background on the container + * @name toggle_stripes() + */ + toggle_stripes : function () { if(this._data.core.themes.stripes) { this.hide_stripes(); } else { this.show_stripes(); } }, + /** + * shows the connecting dots (if the theme supports it) + * @name show_dots() + */ + show_dots : function () { + this._data.core.themes.dots = true; + this.get_container_ul().removeClass("jstree-no-dots"); + /** + * triggered when dots are shown + * @event + * @name show_dots.jstree + */ + this.trigger('show_dots'); + }, + /** + * hides the connecting dots + * @name hide_dots() + */ + hide_dots : function () { + this._data.core.themes.dots = false; + this.get_container_ul().addClass("jstree-no-dots"); + /** + * triggered when dots are hidden + * @event + * @name hide_dots.jstree + */ + this.trigger('hide_dots'); + }, + /** + * toggles the connecting dots + * @name toggle_dots() + */ + toggle_dots : function () { if(this._data.core.themes.dots) { this.hide_dots(); } else { this.show_dots(); } }, + /** + * show the node icons + * @name show_icons() + */ + show_icons : function () { + this._data.core.themes.icons = true; + this.get_container_ul().removeClass("jstree-no-icons"); + /** + * triggered when icons are shown + * @event + * @name show_icons.jstree + */ + this.trigger('show_icons'); + }, + /** + * hide the node icons + * @name hide_icons() + */ + hide_icons : function () { + this._data.core.themes.icons = false; + this.get_container_ul().addClass("jstree-no-icons"); + /** + * triggered when icons are hidden + * @event + * @name hide_icons.jstree + */ + this.trigger('hide_icons'); + }, + /** + * toggle the node icons + * @name toggle_icons() + */ + toggle_icons : function () { if(this._data.core.themes.icons) { this.hide_icons(); } else { this.show_icons(); } }, + /** + * show the node ellipsis + * @name show_icons() + */ + show_ellipsis : function () { + this._data.core.themes.ellipsis = true; + this.get_container_ul().addClass("jstree-ellipsis"); + /** + * triggered when ellisis is shown + * @event + * @name show_ellipsis.jstree + */ + this.trigger('show_ellipsis'); + }, + /** + * hide the node ellipsis + * @name hide_ellipsis() + */ + hide_ellipsis : function () { + this._data.core.themes.ellipsis = false; + this.get_container_ul().removeClass("jstree-ellipsis"); + /** + * triggered when ellisis is hidden + * @event + * @name hide_ellipsis.jstree + */ + this.trigger('hide_ellipsis'); + }, + /** + * toggle the node ellipsis + * @name toggle_icons() + */ + toggle_ellipsis : function () { if(this._data.core.themes.ellipsis) { this.hide_ellipsis(); } else { this.show_ellipsis(); } }, + /** + * set the node icon for a node + * @name set_icon(obj, icon) + * @param {mixed} obj + * @param {String} icon the new icon - can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class + */ + set_icon : function (obj, icon) { + var t1, t2, dom, old; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.set_icon(obj[t1], icon); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + old = obj.icon; + obj.icon = icon === true || icon === null || icon === undefined || icon === '' ? true : icon; + dom = this.get_node(obj, true).children(".jstree-anchor").children(".jstree-themeicon"); + if(icon === false) { + dom.removeClass('jstree-themeicon-custom ' + old).css("background","").removeAttr("rel"); + this.hide_icon(obj); + } + else if(icon === true || icon === null || icon === undefined || icon === '') { + dom.removeClass('jstree-themeicon-custom ' + old).css("background","").removeAttr("rel"); + if(old === false) { this.show_icon(obj); } + } + else if(icon.indexOf("/") === -1 && icon.indexOf(".") === -1) { + dom.removeClass(old).css("background",""); + dom.addClass(icon + ' jstree-themeicon-custom').attr("rel",icon); + if(old === false) { this.show_icon(obj); } + } + else { + dom.removeClass(old).css("background",""); + dom.addClass('jstree-themeicon-custom').css("background", "url('" + icon + "') center center no-repeat").attr("rel",icon); + if(old === false) { this.show_icon(obj); } + } + return true; + }, + /** + * get the node icon for a node + * @name get_icon(obj) + * @param {mixed} obj + * @return {String} + */ + get_icon : function (obj) { + obj = this.get_node(obj); + return (!obj || obj.id === $.jstree.root) ? false : obj.icon; + }, + /** + * hide the icon on an individual node + * @name hide_icon(obj) + * @param {mixed} obj + */ + hide_icon : function (obj) { + var t1, t2; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.hide_icon(obj[t1]); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj === $.jstree.root) { return false; } + obj.icon = false; + this.get_node(obj, true).children(".jstree-anchor").children(".jstree-themeicon").addClass('jstree-themeicon-hidden'); + return true; + }, + /** + * show the icon on an individual node + * @name show_icon(obj) + * @param {mixed} obj + */ + show_icon : function (obj) { + var t1, t2, dom; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.show_icon(obj[t1]); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj === $.jstree.root) { return false; } + dom = this.get_node(obj, true); + obj.icon = dom.length ? dom.children(".jstree-anchor").children(".jstree-themeicon").attr('rel') : true; + if(!obj.icon) { obj.icon = true; } + dom.children(".jstree-anchor").children(".jstree-themeicon").removeClass('jstree-themeicon-hidden'); + return true; + } + }; + + // helpers + $.vakata = {}; + // collect attributes + $.vakata.attributes = function(node, with_values) { + node = $(node)[0]; + var attr = with_values ? {} : []; + if(node && node.attributes) { + $.each(node.attributes, function (i, v) { + if($.inArray(v.name.toLowerCase(),['style','contenteditable','hasfocus','tabindex']) !== -1) { return; } + if(v.value !== null && $.trim(v.value) !== '') { + if(with_values) { attr[v.name] = v.value; } + else { attr.push(v.name); } + } + }); + } + return attr; + }; + $.vakata.array_unique = function(array) { + var a = [], i, j, l, o = {}; + for(i = 0, l = array.length; i < l; i++) { + if(o[array[i]] === undefined) { + a.push(array[i]); + o[array[i]] = true; + } + } + return a; + }; + // remove item from array + $.vakata.array_remove = function(array, from) { + array.splice(from, 1); + return array; + //var rest = array.slice((to || from) + 1 || array.length); + //array.length = from < 0 ? array.length + from : from; + //array.push.apply(array, rest); + //return array; + }; + // remove item from array + $.vakata.array_remove_item = function(array, item) { + var tmp = $.inArray(item, array); + return tmp !== -1 ? $.vakata.array_remove(array, tmp) : array; + }; + $.vakata.array_filter = function(c,a,b,d,e) { + if (c.filter) { + return c.filter(a, b); + } + d=[]; + for (e in c) { + if (~~e+''===e+'' && e>=0 && a.call(b,c[e],+e,c)) { + d.push(c[e]); + } + } + return d; + }; + + +/** + * ### Changed plugin + * + * This plugin adds more information to the `changed.jstree` event. The new data is contained in the `changed` event data property, and contains a lists of `selected` and `deselected` nodes. + */ + + $.jstree.plugins.changed = function (options, parent) { + var last = []; + this.trigger = function (ev, data) { + var i, j; + if(!data) { + data = {}; + } + if(ev.replace('.jstree','') === 'changed') { + data.changed = { selected : [], deselected : [] }; + var tmp = {}; + for(i = 0, j = last.length; i < j; i++) { + tmp[last[i]] = 1; + } + for(i = 0, j = data.selected.length; i < j; i++) { + if(!tmp[data.selected[i]]) { + data.changed.selected.push(data.selected[i]); + } + else { + tmp[data.selected[i]] = 2; + } + } + for(i = 0, j = last.length; i < j; i++) { + if(tmp[last[i]] === 1) { + data.changed.deselected.push(last[i]); + } + } + last = data.selected.slice(); + } + /** + * triggered when selection changes (the "changed" plugin enhances the original event with more data) + * @event + * @name changed.jstree + * @param {Object} node + * @param {Object} action the action that caused the selection to change + * @param {Array} selected the current selection + * @param {Object} changed an object containing two properties `selected` and `deselected` - both arrays of node IDs, which were selected or deselected since the last changed event + * @param {Object} event the event (if any) that triggered this changed event + * @plugin changed + */ + parent.trigger.call(this, ev, data); + }; + this.refresh = function (skip_loading, forget_state) { + last = []; + return parent.refresh.apply(this, arguments); + }; + }; + +/** + * ### Checkbox plugin + * + * This plugin renders checkbox icons in front of each node, making multiple selection much easier. + * It also supports tri-state behavior, meaning that if a node has a few of its children checked it will be rendered as undetermined, and state will be propagated up. + */ + + var _i = document.createElement('I'); + _i.className = 'jstree-icon jstree-checkbox'; + _i.setAttribute('role', 'presentation'); + /** + * stores all defaults for the checkbox plugin + * @name $.jstree.defaults.checkbox + * @plugin checkbox + */ + $.jstree.defaults.checkbox = { + /** + * a boolean indicating if checkboxes should be visible (can be changed at a later time using `show_checkboxes()` and `hide_checkboxes`). Defaults to `true`. + * @name $.jstree.defaults.checkbox.visible + * @plugin checkbox + */ + visible : true, + /** + * a boolean indicating if checkboxes should cascade down and have an undetermined state. Defaults to `true`. + * @name $.jstree.defaults.checkbox.three_state + * @plugin checkbox + */ + three_state : true, + /** + * a boolean indicating if clicking anywhere on the node should act as clicking on the checkbox. Defaults to `true`. + * @name $.jstree.defaults.checkbox.whole_node + * @plugin checkbox + */ + whole_node : true, + /** + * a boolean indicating if the selected style of a node should be kept, or removed. Defaults to `true`. + * @name $.jstree.defaults.checkbox.keep_selected_style + * @plugin checkbox + */ + keep_selected_style : true, + /** + * This setting controls how cascading and undetermined nodes are applied. + * If 'up' is in the string - cascading up is enabled, if 'down' is in the string - cascading down is enabled, if 'undetermined' is in the string - undetermined nodes will be used. + * If `three_state` is set to `true` this setting is automatically set to 'up+down+undetermined'. Defaults to ''. + * @name $.jstree.defaults.checkbox.cascade + * @plugin checkbox + */ + cascade : '', + /** + * This setting controls if checkbox are bound to the general tree selection or to an internal array maintained by the checkbox plugin. Defaults to `true`, only set to `false` if you know exactly what you are doing. + * @name $.jstree.defaults.checkbox.tie_selection + * @plugin checkbox + */ + tie_selection : true, + + /** + * This setting controls if cascading down affects disabled checkboxes + * @name $.jstree.defaults.checkbox.cascade_to_disabled + * @plugin checkbox + */ + cascade_to_disabled : true, + + /** + * This setting controls if cascading down affects hidden checkboxes + * @name $.jstree.defaults.checkbox.cascade_to_hidden + * @plugin checkbox + */ + cascade_to_hidden : true + }; + $.jstree.plugins.checkbox = function (options, parent) { + this.bind = function () { + parent.bind.call(this); + this._data.checkbox.uto = false; + this._data.checkbox.selected = []; + if(this.settings.checkbox.three_state) { + this.settings.checkbox.cascade = 'up+down+undetermined'; + } + this.element + .on("init.jstree", $.proxy(function () { + this._data.checkbox.visible = this.settings.checkbox.visible; + if(!this.settings.checkbox.keep_selected_style) { + this.element.addClass('jstree-checkbox-no-clicked'); + } + if(this.settings.checkbox.tie_selection) { + this.element.addClass('jstree-checkbox-selection'); + } + }, this)) + .on("loading.jstree", $.proxy(function () { + this[ this._data.checkbox.visible ? 'show_checkboxes' : 'hide_checkboxes' ](); + }, this)); + if(this.settings.checkbox.cascade.indexOf('undetermined') !== -1) { + this.element + .on('changed.jstree uncheck_node.jstree check_node.jstree uncheck_all.jstree check_all.jstree move_node.jstree copy_node.jstree redraw.jstree open_node.jstree', $.proxy(function () { + // only if undetermined is in setting + if(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); } + this._data.checkbox.uto = setTimeout($.proxy(this._undetermined, this), 50); + }, this)); + } + if(!this.settings.checkbox.tie_selection) { + this.element + .on('model.jstree', $.proxy(function (e, data) { + var m = this._model.data, + p = m[data.parent], + dpc = data.nodes, + i, j; + for(i = 0, j = dpc.length; i < j; i++) { + m[dpc[i]].state.checked = m[dpc[i]].state.checked || (m[dpc[i]].original && m[dpc[i]].original.state && m[dpc[i]].original.state.checked); + if(m[dpc[i]].state.checked) { + this._data.checkbox.selected.push(dpc[i]); + } + } + }, this)); + } + if(this.settings.checkbox.cascade.indexOf('up') !== -1 || this.settings.checkbox.cascade.indexOf('down') !== -1) { + this.element + .on('model.jstree', $.proxy(function (e, data) { + var m = this._model.data, + p = m[data.parent], + dpc = data.nodes, + chd = [], + c, i, j, k, l, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection; + + if(s.indexOf('down') !== -1) { + // apply down + if(p.state[ t ? 'selected' : 'checked' ]) { + for(i = 0, j = dpc.length; i < j; i++) { + m[dpc[i]].state[ t ? 'selected' : 'checked' ] = true; + } + + this._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(dpc); + } + else { + for(i = 0, j = dpc.length; i < j; i++) { + if(m[dpc[i]].state[ t ? 'selected' : 'checked' ]) { + for(k = 0, l = m[dpc[i]].children_d.length; k < l; k++) { + m[m[dpc[i]].children_d[k]].state[ t ? 'selected' : 'checked' ] = true; + } + this._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(m[dpc[i]].children_d); + } + } + } + } + + if(s.indexOf('up') !== -1) { + // apply up + for(i = 0, j = p.children_d.length; i < j; i++) { + if(!m[p.children_d[i]].children.length) { + chd.push(m[p.children_d[i]].parent); + } + } + chd = $.vakata.array_unique(chd); + for(k = 0, l = chd.length; k < l; k++) { + p = m[chd[k]]; + while(p && p.id !== $.jstree.root) { + c = 0; + for(i = 0, j = p.children.length; i < j; i++) { + c += m[p.children[i]].state[ t ? 'selected' : 'checked' ]; + } + if(c === j) { + p.state[ t ? 'selected' : 'checked' ] = true; + this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id); + tmp = this.get_node(p, true); + if(tmp && tmp.length) { + tmp.attr('aria-selected', true).children('.jstree-anchor').addClass( t ? 'jstree-clicked' : 'jstree-checked'); + } + } + else { + break; + } + p = this.get_node(p.parent); + } + } + } + + this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected); + }, this)) + .on(this.settings.checkbox.tie_selection ? 'select_node.jstree' : 'check_node.jstree', $.proxy(function (e, data) { + var self = this, + obj = data.node, + m = this._model.data, + par = this.get_node(obj.parent), + i, j, c, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection, + sel = {}, cur = this._data[ t ? 'core' : 'checkbox' ].selected; + + for (i = 0, j = cur.length; i < j; i++) { + sel[cur[i]] = true; + } + + // apply down + if(s.indexOf('down') !== -1) { + //this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected.concat(obj.children_d)); + var selectedIds = this._cascade_new_checked_state(obj.id, true); + var temp = obj.children_d.concat(obj.id); + for (i = 0, j = temp.length; i < j; i++) { + if (selectedIds.indexOf(temp[i]) > -1) { + sel[temp[i]] = true; + } + else { + delete sel[temp[i]]; + } + } + } + + // apply up + if(s.indexOf('up') !== -1) { + while(par && par.id !== $.jstree.root) { + c = 0; + for(i = 0, j = par.children.length; i < j; i++) { + c += m[par.children[i]].state[ t ? 'selected' : 'checked' ]; + } + if(c === j) { + par.state[ t ? 'selected' : 'checked' ] = true; + sel[par.id] = true; + //this._data[ t ? 'core' : 'checkbox' ].selected.push(par.id); + tmp = this.get_node(par, true); + if(tmp && tmp.length) { + tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + } + else { + break; + } + par = this.get_node(par.parent); + } + } + + cur = []; + for (i in sel) { + if (sel.hasOwnProperty(i)) { + cur.push(i); + } + } + this._data[ t ? 'core' : 'checkbox' ].selected = cur; + }, this)) + .on(this.settings.checkbox.tie_selection ? 'deselect_all.jstree' : 'uncheck_all.jstree', $.proxy(function (e, data) { + var obj = this.get_node($.jstree.root), + m = this._model.data, + i, j, tmp; + for(i = 0, j = obj.children_d.length; i < j; i++) { + tmp = m[obj.children_d[i]]; + if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) { + tmp.original.state.undetermined = false; + } + } + }, this)) + .on(this.settings.checkbox.tie_selection ? 'deselect_node.jstree' : 'uncheck_node.jstree', $.proxy(function (e, data) { + var self = this, + obj = data.node, + dom = this.get_node(obj, true), + i, j, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection, + cur = this._data[ t ? 'core' : 'checkbox' ].selected, sel = {}, + stillSelectedIds = [], + allIds = obj.children_d.concat(obj.id); + + // apply down + if(s.indexOf('down') !== -1) { + var selectedIds = this._cascade_new_checked_state(obj.id, false); + + cur = cur.filter(function(id) { + return allIds.indexOf(id) === -1 || selectedIds.indexOf(id) > -1; + }); + } + + // only apply up if cascade up is enabled and if this node is not selected + // (if all child nodes are disabled and cascade_to_disabled === false then this node will till be selected). + if(s.indexOf('up') !== -1 && cur.indexOf(obj.id) === -1) { + for(i = 0, j = obj.parents.length; i < j; i++) { + tmp = this._model.data[obj.parents[i]]; + tmp.state[ t ? 'selected' : 'checked' ] = false; + if(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) { + tmp.original.state.undetermined = false; + } + tmp = this.get_node(obj.parents[i], true); + if(tmp && tmp.length) { + tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + } + + cur = cur.filter(function(id) { + return obj.parents.indexOf(id) === -1; + }); + } + + this._data[ t ? 'core' : 'checkbox' ].selected = cur; + }, this)); + } + if(this.settings.checkbox.cascade.indexOf('up') !== -1) { + this.element + .on('delete_node.jstree', $.proxy(function (e, data) { + // apply up (whole handler) + var p = this.get_node(data.parent), + m = this._model.data, + i, j, c, tmp, t = this.settings.checkbox.tie_selection; + while(p && p.id !== $.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) { + c = 0; + for(i = 0, j = p.children.length; i < j; i++) { + c += m[p.children[i]].state[ t ? 'selected' : 'checked' ]; + } + if(j > 0 && c === j) { + p.state[ t ? 'selected' : 'checked' ] = true; + this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id); + tmp = this.get_node(p, true); + if(tmp && tmp.length) { + tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + } + else { + break; + } + p = this.get_node(p.parent); + } + }, this)) + .on('move_node.jstree', $.proxy(function (e, data) { + // apply up (whole handler) + var is_multi = data.is_multi, + old_par = data.old_parent, + new_par = this.get_node(data.parent), + m = this._model.data, + p, c, i, j, tmp, t = this.settings.checkbox.tie_selection; + if(!is_multi) { + p = this.get_node(old_par); + while(p && p.id !== $.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) { + c = 0; + for(i = 0, j = p.children.length; i < j; i++) { + c += m[p.children[i]].state[ t ? 'selected' : 'checked' ]; + } + if(j > 0 && c === j) { + p.state[ t ? 'selected' : 'checked' ] = true; + this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id); + tmp = this.get_node(p, true); + if(tmp && tmp.length) { + tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + } + else { + break; + } + p = this.get_node(p.parent); + } + } + p = new_par; + while(p && p.id !== $.jstree.root) { + c = 0; + for(i = 0, j = p.children.length; i < j; i++) { + c += m[p.children[i]].state[ t ? 'selected' : 'checked' ]; + } + if(c === j) { + if(!p.state[ t ? 'selected' : 'checked' ]) { + p.state[ t ? 'selected' : 'checked' ] = true; + this._data[ t ? 'core' : 'checkbox' ].selected.push(p.id); + tmp = this.get_node(p, true); + if(tmp && tmp.length) { + tmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + } + } + else { + if(p.state[ t ? 'selected' : 'checked' ]) { + p.state[ t ? 'selected' : 'checked' ] = false; + this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_remove_item(this._data[ t ? 'core' : 'checkbox' ].selected, p.id); + tmp = this.get_node(p, true); + if(tmp && tmp.length) { + tmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + } + else { + break; + } + } + p = this.get_node(p.parent); + } + }, this)); + } + }; + /** + * get an array of all nodes whose state is "undetermined" + * @name get_undetermined([full]) + * @param {boolean} full: if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned + * @return {Array} + * @plugin checkbox + */ + this.get_undetermined = function (full) { + if (this.settings.checkbox.cascade.indexOf('undetermined') === -1) { + return []; + } + var i, j, k, l, o = {}, m = this._model.data, t = this.settings.checkbox.tie_selection, s = this._data[ t ? 'core' : 'checkbox' ].selected, p = [], tt = this, r = []; + for(i = 0, j = s.length; i < j; i++) { + if(m[s[i]] && m[s[i]].parents) { + for(k = 0, l = m[s[i]].parents.length; k < l; k++) { + if(o[m[s[i]].parents[k]] !== undefined) { + break; + } + if(m[s[i]].parents[k] !== $.jstree.root) { + o[m[s[i]].parents[k]] = true; + p.push(m[s[i]].parents[k]); + } + } + } + } + // attempt for server side undetermined state + this.element.find('.jstree-closed').not(':has(.jstree-children)') + .each(function () { + var tmp = tt.get_node(this), tmp2; + + if(!tmp) { return; } + + if(!tmp.state.loaded) { + if(tmp.original && tmp.original.state && tmp.original.state.undetermined && tmp.original.state.undetermined === true) { + if(o[tmp.id] === undefined && tmp.id !== $.jstree.root) { + o[tmp.id] = true; + p.push(tmp.id); + } + for(k = 0, l = tmp.parents.length; k < l; k++) { + if(o[tmp.parents[k]] === undefined && tmp.parents[k] !== $.jstree.root) { + o[tmp.parents[k]] = true; + p.push(tmp.parents[k]); + } + } + } + } + else { + for(i = 0, j = tmp.children_d.length; i < j; i++) { + tmp2 = m[tmp.children_d[i]]; + if(!tmp2.state.loaded && tmp2.original && tmp2.original.state && tmp2.original.state.undetermined && tmp2.original.state.undetermined === true) { + if(o[tmp2.id] === undefined && tmp2.id !== $.jstree.root) { + o[tmp2.id] = true; + p.push(tmp2.id); + } + for(k = 0, l = tmp2.parents.length; k < l; k++) { + if(o[tmp2.parents[k]] === undefined && tmp2.parents[k] !== $.jstree.root) { + o[tmp2.parents[k]] = true; + p.push(tmp2.parents[k]); + } + } + } + } + } + }); + for (i = 0, j = p.length; i < j; i++) { + if(!m[p[i]].state[ t ? 'selected' : 'checked' ]) { + r.push(full ? m[p[i]] : p[i]); + } + } + return r; + }; + /** + * set the undetermined state where and if necessary. Used internally. + * @private + * @name _undetermined() + * @plugin checkbox + */ + this._undetermined = function () { + if(this.element === null) { return; } + var p = this.get_undetermined(false), i, j, s; + + this.element.find('.jstree-undetermined').removeClass('jstree-undetermined'); + for (i = 0, j = p.length; i < j; i++) { + s = this.get_node(p[i], true); + if(s && s.length) { + s.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-undetermined'); + } + } + }; + this.redraw_node = function(obj, deep, is_callback, force_render) { + obj = parent.redraw_node.apply(this, arguments); + if(obj) { + var i, j, tmp = null, icon = null; + for(i = 0, j = obj.childNodes.length; i < j; i++) { + if(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf("jstree-anchor") !== -1) { + tmp = obj.childNodes[i]; + break; + } + } + if(tmp) { + if(!this.settings.checkbox.tie_selection && this._model.data[obj.id].state.checked) { tmp.className += ' jstree-checked'; } + icon = _i.cloneNode(false); + if(this._model.data[obj.id].state.checkbox_disabled) { icon.className += ' jstree-checkbox-disabled'; } + tmp.insertBefore(icon, tmp.childNodes[0]); + } + } + if(!is_callback && this.settings.checkbox.cascade.indexOf('undetermined') !== -1) { + if(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); } + this._data.checkbox.uto = setTimeout($.proxy(this._undetermined, this), 50); + } + return obj; + }; + /** + * show the node checkbox icons + * @name show_checkboxes() + * @plugin checkbox + */ + this.show_checkboxes = function () { this._data.core.themes.checkboxes = true; this.get_container_ul().removeClass("jstree-no-checkboxes"); }; + /** + * hide the node checkbox icons + * @name hide_checkboxes() + * @plugin checkbox + */ + this.hide_checkboxes = function () { this._data.core.themes.checkboxes = false; this.get_container_ul().addClass("jstree-no-checkboxes"); }; + /** + * toggle the node icons + * @name toggle_checkboxes() + * @plugin checkbox + */ + this.toggle_checkboxes = function () { if(this._data.core.themes.checkboxes) { this.hide_checkboxes(); } else { this.show_checkboxes(); } }; + /** + * checks if a node is in an undetermined state + * @name is_undetermined(obj) + * @param {mixed} obj + * @return {Boolean} + */ + this.is_undetermined = function (obj) { + obj = this.get_node(obj); + var s = this.settings.checkbox.cascade, i, j, t = this.settings.checkbox.tie_selection, d = this._data[ t ? 'core' : 'checkbox' ].selected, m = this._model.data; + if(!obj || obj.state[ t ? 'selected' : 'checked' ] === true || s.indexOf('undetermined') === -1 || (s.indexOf('down') === -1 && s.indexOf('up') === -1)) { + return false; + } + if(!obj.state.loaded && obj.original.state.undetermined === true) { + return true; + } + for(i = 0, j = obj.children_d.length; i < j; i++) { + if($.inArray(obj.children_d[i], d) !== -1 || (!m[obj.children_d[i]].state.loaded && m[obj.children_d[i]].original.state.undetermined)) { + return true; + } + } + return false; + }; + /** + * disable a node's checkbox + * @name disable_checkbox(obj) + * @param {mixed} obj an array can be used too + * @trigger disable_checkbox.jstree + * @plugin checkbox + */ + this.disable_checkbox = function (obj) { + var t1, t2, dom; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.disable_checkbox(obj[t1]); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + dom = this.get_node(obj, true); + if(!obj.state.checkbox_disabled) { + obj.state.checkbox_disabled = true; + if(dom && dom.length) { + dom.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-checkbox-disabled'); + } + /** + * triggered when an node's checkbox is disabled + * @event + * @name disable_checkbox.jstree + * @param {Object} node + * @plugin checkbox + */ + this.trigger('disable_checkbox', { 'node' : obj }); + } + }; + /** + * enable a node's checkbox + * @name disable_checkbox(obj) + * @param {mixed} obj an array can be used too + * @trigger enable_checkbox.jstree + * @plugin checkbox + */ + this.enable_checkbox = function (obj) { + var t1, t2, dom; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.enable_checkbox(obj[t1]); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + dom = this.get_node(obj, true); + if(obj.state.checkbox_disabled) { + obj.state.checkbox_disabled = false; + if(dom && dom.length) { + dom.children('.jstree-anchor').children('.jstree-checkbox').removeClass('jstree-checkbox-disabled'); + } + /** + * triggered when an node's checkbox is enabled + * @event + * @name enable_checkbox.jstree + * @param {Object} node + * @plugin checkbox + */ + this.trigger('enable_checkbox', { 'node' : obj }); + } + }; + + this.activate_node = function (obj, e) { + if($(e.target).hasClass('jstree-checkbox-disabled')) { + return false; + } + if(this.settings.checkbox.tie_selection && (this.settings.checkbox.whole_node || $(e.target).hasClass('jstree-checkbox'))) { + e.ctrlKey = true; + } + if(this.settings.checkbox.tie_selection || (!this.settings.checkbox.whole_node && !$(e.target).hasClass('jstree-checkbox'))) { + return parent.activate_node.call(this, obj, e); + } + if(this.is_disabled(obj)) { + return false; + } + if(this.is_checked(obj)) { + this.uncheck_node(obj, e); + } + else { + this.check_node(obj, e); + } + this.trigger('activate_node', { 'node' : this.get_node(obj) }); + }; + + /** + * Cascades checked state to a node and all its descendants. This function does NOT affect hidden and disabled nodes (or their descendants). + * However if these unaffected nodes are already selected their ids will be included in the returned array. + * @private + * @param {string} id the node ID + * @param {bool} checkedState should the nodes be checked or not + * @returns {Array} Array of all node id's (in this tree branch) that are checked. + */ + this._cascade_new_checked_state = function (id, checkedState) { + var self = this; + var t = this.settings.checkbox.tie_selection; + var node = this._model.data[id]; + var selectedNodeIds = []; + var selectedChildrenIds = [], i, j, selectedChildIds; + + if ( + (this.settings.checkbox.cascade_to_disabled || !node.state.disabled) && + (this.settings.checkbox.cascade_to_hidden || !node.state.hidden) + ) { + //First try and check/uncheck the children + if (node.children) { + for (i = 0, j = node.children.length; i < j; i++) { + var childId = node.children[i]; + selectedChildIds = self._cascade_new_checked_state(childId, checkedState); + selectedNodeIds = selectedNodeIds.concat(selectedChildIds); + if (selectedChildIds.indexOf(childId) > -1) { + selectedChildrenIds.push(childId); + } + } + } + + var dom = self.get_node(node, true); + + //A node's state is undetermined if some but not all of it's children are checked/selected . + var undetermined = selectedChildrenIds.length > 0 && selectedChildrenIds.length < node.children.length; + + if(node.original && node.original.state && node.original.state.undetermined) { + node.original.state.undetermined = undetermined; + } + + //If a node is undetermined then remove selected class + if (undetermined) { + node.state[ t ? 'selected' : 'checked' ] = false; + dom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + //Otherwise, if the checkedState === true (i.e. the node is being checked now) and all of the node's children are checked (if it has any children), + //check the node and style it correctly. + else if (checkedState && selectedChildrenIds.length === node.children.length) { + node.state[ t ? 'selected' : 'checked' ] = checkedState; + selectedNodeIds.push(node.id); + + dom.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + else { + node.state[ t ? 'selected' : 'checked' ] = false; + dom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked'); + } + } + else { + selectedChildIds = this.get_checked_descendants(id); + + if (node.state[ t ? 'selected' : 'checked' ]) { + selectedChildIds.push(node.id); + } + + selectedNodeIds = selectedNodeIds.concat(selectedChildIds); + } + + return selectedNodeIds; + }; + + /** + * Gets ids of nodes selected in branch (of tree) specified by id (does not include the node specified by id) + * @name get_checked_descendants(obj) + * @param {string} id the node ID + * @return {Array} array of IDs + * @plugin checkbox + */ + this.get_checked_descendants = function (id) { + var self = this; + var t = self.settings.checkbox.tie_selection; + var node = self._model.data[id]; + + return node.children_d.filter(function(_id) { + return self._model.data[_id].state[ t ? 'selected' : 'checked' ]; + }); + }; + + /** + * check a node (only if tie_selection in checkbox settings is false, otherwise select_node will be called internally) + * @name check_node(obj) + * @param {mixed} obj an array can be used to check multiple nodes + * @trigger check_node.jstree + * @plugin checkbox + */ + this.check_node = function (obj, e) { + if(this.settings.checkbox.tie_selection) { return this.select_node(obj, false, true, e); } + var dom, t1, t2, th; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.check_node(obj[t1], e); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + dom = this.get_node(obj, true); + if(!obj.state.checked) { + obj.state.checked = true; + this._data.checkbox.selected.push(obj.id); + if(dom && dom.length) { + dom.children('.jstree-anchor').addClass('jstree-checked'); + } + /** + * triggered when an node is checked (only if tie_selection in checkbox settings is false) + * @event + * @name check_node.jstree + * @param {Object} node + * @param {Array} selected the current selection + * @param {Object} event the event (if any) that triggered this check_node + * @plugin checkbox + */ + this.trigger('check_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e }); + } + }; + /** + * uncheck a node (only if tie_selection in checkbox settings is false, otherwise deselect_node will be called internally) + * @name uncheck_node(obj) + * @param {mixed} obj an array can be used to uncheck multiple nodes + * @trigger uncheck_node.jstree + * @plugin checkbox + */ + this.uncheck_node = function (obj, e) { + if(this.settings.checkbox.tie_selection) { return this.deselect_node(obj, false, e); } + var t1, t2, dom; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.uncheck_node(obj[t1], e); + } + return true; + } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { + return false; + } + dom = this.get_node(obj, true); + if(obj.state.checked) { + obj.state.checked = false; + this._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, obj.id); + if(dom.length) { + dom.children('.jstree-anchor').removeClass('jstree-checked'); + } + /** + * triggered when an node is unchecked (only if tie_selection in checkbox settings is false) + * @event + * @name uncheck_node.jstree + * @param {Object} node + * @param {Array} selected the current selection + * @param {Object} event the event (if any) that triggered this uncheck_node + * @plugin checkbox + */ + this.trigger('uncheck_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e }); + } + }; + + /** + * checks all nodes in the tree (only if tie_selection in checkbox settings is false, otherwise select_all will be called internally) + * @name check_all() + * @trigger check_all.jstree, changed.jstree + * @plugin checkbox + */ + this.check_all = function () { + if(this.settings.checkbox.tie_selection) { return this.select_all(); } + var tmp = this._data.checkbox.selected.concat([]), i, j; + this._data.checkbox.selected = this._model.data[$.jstree.root].children_d.concat(); + for(i = 0, j = this._data.checkbox.selected.length; i < j; i++) { + if(this._model.data[this._data.checkbox.selected[i]]) { + this._model.data[this._data.checkbox.selected[i]].state.checked = true; + } + } + this.redraw(true); + /** + * triggered when all nodes are checked (only if tie_selection in checkbox settings is false) + * @event + * @name check_all.jstree + * @param {Array} selected the current selection + * @plugin checkbox + */ + this.trigger('check_all', { 'selected' : this._data.checkbox.selected }); + }; + /** + * uncheck all checked nodes (only if tie_selection in checkbox settings is false, otherwise deselect_all will be called internally) + * @name uncheck_all() + * @trigger uncheck_all.jstree + * @plugin checkbox + */ + this.uncheck_all = function () { + if(this.settings.checkbox.tie_selection) { return this.deselect_all(); } + var tmp = this._data.checkbox.selected.concat([]), i, j; + for(i = 0, j = this._data.checkbox.selected.length; i < j; i++) { + if(this._model.data[this._data.checkbox.selected[i]]) { + this._model.data[this._data.checkbox.selected[i]].state.checked = false; + } + } + this._data.checkbox.selected = []; + this.element.find('.jstree-checked').removeClass('jstree-checked'); + /** + * triggered when all nodes are unchecked (only if tie_selection in checkbox settings is false) + * @event + * @name uncheck_all.jstree + * @param {Object} node the previous selection + * @param {Array} selected the current selection + * @plugin checkbox + */ + this.trigger('uncheck_all', { 'selected' : this._data.checkbox.selected, 'node' : tmp }); + }; + /** + * checks if a node is checked (if tie_selection is on in the settings this function will return the same as is_selected) + * @name is_checked(obj) + * @param {mixed} obj + * @return {Boolean} + * @plugin checkbox + */ + this.is_checked = function (obj) { + if(this.settings.checkbox.tie_selection) { return this.is_selected(obj); } + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + return obj.state.checked; + }; + /** + * get an array of all checked nodes (if tie_selection is on in the settings this function will return the same as get_selected) + * @name get_checked([full]) + * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned + * @return {Array} + * @plugin checkbox + */ + this.get_checked = function (full) { + if(this.settings.checkbox.tie_selection) { return this.get_selected(full); } + return full ? $.map(this._data.checkbox.selected, $.proxy(function (i) { return this.get_node(i); }, this)) : this._data.checkbox.selected; + }; + /** + * get an array of all top level checked nodes (ignoring children of checked nodes) (if tie_selection is on in the settings this function will return the same as get_top_selected) + * @name get_top_checked([full]) + * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned + * @return {Array} + * @plugin checkbox + */ + this.get_top_checked = function (full) { + if(this.settings.checkbox.tie_selection) { return this.get_top_selected(full); } + var tmp = this.get_checked(true), + obj = {}, i, j, k, l; + for(i = 0, j = tmp.length; i < j; i++) { + obj[tmp[i].id] = tmp[i]; + } + for(i = 0, j = tmp.length; i < j; i++) { + for(k = 0, l = tmp[i].children_d.length; k < l; k++) { + if(obj[tmp[i].children_d[k]]) { + delete obj[tmp[i].children_d[k]]; + } + } + } + tmp = []; + for(i in obj) { + if(obj.hasOwnProperty(i)) { + tmp.push(i); + } + } + return full ? $.map(tmp, $.proxy(function (i) { return this.get_node(i); }, this)) : tmp; + }; + /** + * get an array of all bottom level checked nodes (ignoring selected parents) (if tie_selection is on in the settings this function will return the same as get_bottom_selected) + * @name get_bottom_checked([full]) + * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned + * @return {Array} + * @plugin checkbox + */ + this.get_bottom_checked = function (full) { + if(this.settings.checkbox.tie_selection) { return this.get_bottom_selected(full); } + var tmp = this.get_checked(true), + obj = [], i, j; + for(i = 0, j = tmp.length; i < j; i++) { + if(!tmp[i].children.length) { + obj.push(tmp[i].id); + } + } + return full ? $.map(obj, $.proxy(function (i) { return this.get_node(i); }, this)) : obj; + }; + this.load_node = function (obj, callback) { + var k, l, i, j, c, tmp; + if(!$.isArray(obj) && !this.settings.checkbox.tie_selection) { + tmp = this.get_node(obj); + if(tmp && tmp.state.loaded) { + for(k = 0, l = tmp.children_d.length; k < l; k++) { + if(this._model.data[tmp.children_d[k]].state.checked) { + c = true; + this._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, tmp.children_d[k]); + } + } + } + } + return parent.load_node.apply(this, arguments); + }; + this.get_state = function () { + var state = parent.get_state.apply(this, arguments); + if(this.settings.checkbox.tie_selection) { return state; } + state.checkbox = this._data.checkbox.selected.slice(); + return state; + }; + this.set_state = function (state, callback) { + var res = parent.set_state.apply(this, arguments); + if(res && state.checkbox) { + if(!this.settings.checkbox.tie_selection) { + this.uncheck_all(); + var _this = this; + $.each(state.checkbox, function (i, v) { + _this.check_node(v); + }); + } + delete state.checkbox; + this.set_state(state, callback); + return false; + } + return res; + }; + this.refresh = function (skip_loading, forget_state) { + if(!this.settings.checkbox.tie_selection) { + this._data.checkbox.selected = []; + } + return parent.refresh.apply(this, arguments); + }; + }; + + // include the checkbox plugin by default + // $.jstree.defaults.plugins.push("checkbox"); + + +/** + * ### Conditionalselect plugin + * + * This plugin allows defining a callback to allow or deny node selection by user input (activate node method). + */ + + /** + * a callback (function) which is invoked in the instance's scope and receives two arguments - the node and the event that triggered the `activate_node` call. Returning false prevents working with the node, returning true allows invoking activate_node. Defaults to returning `true`. + * @name $.jstree.defaults.checkbox.visible + * @plugin checkbox + */ + $.jstree.defaults.conditionalselect = function () { return true; }; + $.jstree.plugins.conditionalselect = function (options, parent) { + // own function + this.activate_node = function (obj, e) { + if(this.settings.conditionalselect.call(this, this.get_node(obj), e)) { + return parent.activate_node.call(this, obj, e); + } + }; + }; + + +/** + * ### Contextmenu plugin + * + * Shows a context menu when a node is right-clicked. + */ + + /** + * stores all defaults for the contextmenu plugin + * @name $.jstree.defaults.contextmenu + * @plugin contextmenu + */ + $.jstree.defaults.contextmenu = { + /** + * a boolean indicating if the node should be selected when the context menu is invoked on it. Defaults to `true`. + * @name $.jstree.defaults.contextmenu.select_node + * @plugin contextmenu + */ + select_node : true, + /** + * a boolean indicating if the menu should be shown aligned with the node. Defaults to `true`, otherwise the mouse coordinates are used. + * @name $.jstree.defaults.contextmenu.show_at_node + * @plugin contextmenu + */ + show_at_node : true, + /** + * an object of actions, or a function that accepts a node and a callback function and calls the callback function with an object of actions available for that node (you can also return the items too). + * + * Each action consists of a key (a unique name) and a value which is an object with the following properties (only label and action are required). Once a menu item is activated the `action` function will be invoked with an object containing the following keys: item - the contextmenu item definition as seen below, reference - the DOM node that was used (the tree node), element - the contextmenu DOM element, position - an object with x/y properties indicating the position of the menu. + * + * * `separator_before` - a boolean indicating if there should be a separator before this item + * * `separator_after` - a boolean indicating if there should be a separator after this item + * * `_disabled` - a boolean indicating if this action should be disabled + * * `label` - a string - the name of the action (could be a function returning a string) + * * `title` - a string - an optional tooltip for the item + * * `action` - a function to be executed if this item is chosen, the function will receive + * * `icon` - a string, can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class + * * `shortcut` - keyCode which will trigger the action if the menu is open (for example `113` for rename, which equals F2) + * * `shortcut_label` - shortcut label (like for example `F2` for rename) + * * `submenu` - an object with the same structure as $.jstree.defaults.contextmenu.items which can be used to create a submenu - each key will be rendered as a separate option in a submenu that will appear once the current item is hovered + * + * @name $.jstree.defaults.contextmenu.items + * @plugin contextmenu + */ + items : function (o, cb) { // Could be an object directly + return { + "create" : { + "separator_before" : false, + "separator_after" : true, + "_disabled" : false, //(this.check("create_node", data.reference, {}, "last")), + "label" : "Create", + "action" : function (data) { + var inst = $.jstree.reference(data.reference), + obj = inst.get_node(data.reference); + inst.create_node(obj, {}, "last", function (new_node) { + try { + inst.edit(new_node); + } catch (ex) { + setTimeout(function () { inst.edit(new_node); },0); + } + }); + } + }, + "rename" : { + "separator_before" : false, + "separator_after" : false, + "_disabled" : false, //(this.check("rename_node", data.reference, this.get_parent(data.reference), "")), + "label" : "Rename", + /*! + "shortcut" : 113, + "shortcut_label" : 'F2', + "icon" : "glyphicon glyphicon-leaf", + */ + "action" : function (data) { + var inst = $.jstree.reference(data.reference), + obj = inst.get_node(data.reference); + inst.edit(obj); + } + }, + "remove" : { + "separator_before" : false, + "icon" : false, + "separator_after" : false, + "_disabled" : false, //(this.check("delete_node", data.reference, this.get_parent(data.reference), "")), + "label" : "Delete", + "action" : function (data) { + var inst = $.jstree.reference(data.reference), + obj = inst.get_node(data.reference); + if(inst.is_selected(obj)) { + inst.delete_node(inst.get_selected()); + } + else { + inst.delete_node(obj); + } + } + }, + "ccp" : { + "separator_before" : true, + "icon" : false, + "separator_after" : false, + "label" : "Edit", + "action" : false, + "submenu" : { + "cut" : { + "separator_before" : false, + "separator_after" : false, + "label" : "Cut", + "action" : function (data) { + var inst = $.jstree.reference(data.reference), + obj = inst.get_node(data.reference); + if(inst.is_selected(obj)) { + inst.cut(inst.get_top_selected()); + } + else { + inst.cut(obj); + } + } + }, + "copy" : { + "separator_before" : false, + "icon" : false, + "separator_after" : false, + "label" : "Copy", + "action" : function (data) { + var inst = $.jstree.reference(data.reference), + obj = inst.get_node(data.reference); + if(inst.is_selected(obj)) { + inst.copy(inst.get_top_selected()); + } + else { + inst.copy(obj); + } + } + }, + "paste" : { + "separator_before" : false, + "icon" : false, + "_disabled" : function (data) { + return !$.jstree.reference(data.reference).can_paste(); + }, + "separator_after" : false, + "label" : "Paste", + "action" : function (data) { + var inst = $.jstree.reference(data.reference), + obj = inst.get_node(data.reference); + inst.paste(obj); + } + } + } + } + }; + } + }; + + $.jstree.plugins.contextmenu = function (options, parent) { + this.bind = function () { + parent.bind.call(this); + + var last_ts = 0, cto = null, ex, ey; + this.element + .on("init.jstree loading.jstree ready.jstree", $.proxy(function () { + this.get_container_ul().addClass('jstree-contextmenu'); + }, this)) + .on("contextmenu.jstree", ".jstree-anchor", $.proxy(function (e, data) { + if (e.target.tagName.toLowerCase() === 'input') { + return; + } + e.preventDefault(); + last_ts = e.ctrlKey ? +new Date() : 0; + if(data || cto) { + last_ts = (+new Date()) + 10000; + } + if(cto) { + clearTimeout(cto); + } + if(!this.is_loading(e.currentTarget)) { + this.show_contextmenu(e.currentTarget, e.pageX, e.pageY, e); + } + }, this)) + .on("click.jstree", ".jstree-anchor", $.proxy(function (e) { + if(this._data.contextmenu.visible && (!last_ts || (+new Date()) - last_ts > 250)) { // work around safari & macOS ctrl+click + $.vakata.context.hide(); + } + last_ts = 0; + }, this)) + .on("touchstart.jstree", ".jstree-anchor", function (e) { + if(!e.originalEvent || !e.originalEvent.changedTouches || !e.originalEvent.changedTouches[0]) { + return; + } + ex = e.originalEvent.changedTouches[0].clientX; + ey = e.originalEvent.changedTouches[0].clientY; + cto = setTimeout(function () { + $(e.currentTarget).trigger('contextmenu', true); + }, 750); + }) + .on('touchmove.vakata.jstree', function (e) { + if(cto && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && (Math.abs(ex - e.originalEvent.changedTouches[0].clientX) > 10 || Math.abs(ey - e.originalEvent.changedTouches[0].clientY) > 10)) { + clearTimeout(cto); + $.vakata.context.hide(); + } + }) + .on('touchend.vakata.jstree', function (e) { + if(cto) { + clearTimeout(cto); + } + }); + + /*! + if(!('oncontextmenu' in document.body) && ('ontouchstart' in document.body)) { + var el = null, tm = null; + this.element + .on("touchstart", ".jstree-anchor", function (e) { + el = e.currentTarget; + tm = +new Date(); + $(document).one("touchend", function (e) { + e.target = document.elementFromPoint(e.originalEvent.targetTouches[0].pageX - window.pageXOffset, e.originalEvent.targetTouches[0].pageY - window.pageYOffset); + e.currentTarget = e.target; + tm = ((+(new Date())) - tm); + if(e.target === el && tm > 600 && tm < 1000) { + e.preventDefault(); + $(el).trigger('contextmenu', e); + } + el = null; + tm = null; + }); + }); + } + */ + $(document).on("context_hide.vakata.jstree", $.proxy(function (e, data) { + this._data.contextmenu.visible = false; + $(data.reference).removeClass('jstree-context'); + }, this)); + }; + this.teardown = function () { + if(this._data.contextmenu.visible) { + $.vakata.context.hide(); + } + parent.teardown.call(this); + }; + + /** + * prepare and show the context menu for a node + * @name show_contextmenu(obj [, x, y]) + * @param {mixed} obj the node + * @param {Number} x the x-coordinate relative to the document to show the menu at + * @param {Number} y the y-coordinate relative to the document to show the menu at + * @param {Object} e the event if available that triggered the contextmenu + * @plugin contextmenu + * @trigger show_contextmenu.jstree + */ + this.show_contextmenu = function (obj, x, y, e) { + obj = this.get_node(obj); + if(!obj || obj.id === $.jstree.root) { return false; } + var s = this.settings.contextmenu, + d = this.get_node(obj, true), + a = d.children(".jstree-anchor"), + o = false, + i = false; + if(s.show_at_node || x === undefined || y === undefined) { + o = a.offset(); + x = o.left; + y = o.top + this._data.core.li_height; + } + if(this.settings.contextmenu.select_node && !this.is_selected(obj)) { + this.activate_node(obj, e); + } + + i = s.items; + if($.isFunction(i)) { + i = i.call(this, obj, $.proxy(function (i) { + this._show_contextmenu(obj, x, y, i); + }, this)); + } + if($.isPlainObject(i)) { + this._show_contextmenu(obj, x, y, i); + } + }; + /** + * show the prepared context menu for a node + * @name _show_contextmenu(obj, x, y, i) + * @param {mixed} obj the node + * @param {Number} x the x-coordinate relative to the document to show the menu at + * @param {Number} y the y-coordinate relative to the document to show the menu at + * @param {Number} i the object of items to show + * @plugin contextmenu + * @trigger show_contextmenu.jstree + * @private + */ + this._show_contextmenu = function (obj, x, y, i) { + var d = this.get_node(obj, true), + a = d.children(".jstree-anchor"); + $(document).one("context_show.vakata.jstree", $.proxy(function (e, data) { + var cls = 'jstree-contextmenu jstree-' + this.get_theme() + '-contextmenu'; + $(data.element).addClass(cls); + a.addClass('jstree-context'); + }, this)); + this._data.contextmenu.visible = true; + $.vakata.context.show(a, { 'x' : x, 'y' : y }, i); + /** + * triggered when the contextmenu is shown for a node + * @event + * @name show_contextmenu.jstree + * @param {Object} node the node + * @param {Number} x the x-coordinate of the menu relative to the document + * @param {Number} y the y-coordinate of the menu relative to the document + * @plugin contextmenu + */ + this.trigger('show_contextmenu', { "node" : obj, "x" : x, "y" : y }); + }; + }; + + // contextmenu helper + (function ($) { + var right_to_left = false, + vakata_context = { + element : false, + reference : false, + position_x : 0, + position_y : 0, + items : [], + html : "", + is_visible : false + }; + + $.vakata.context = { + settings : { + hide_onmouseleave : 0, + icons : true + }, + _trigger : function (event_name) { + $(document).triggerHandler("context_" + event_name + ".vakata", { + "reference" : vakata_context.reference, + "element" : vakata_context.element, + "position" : { + "x" : vakata_context.position_x, + "y" : vakata_context.position_y + } + }); + }, + _execute : function (i) { + i = vakata_context.items[i]; + return i && (!i._disabled || ($.isFunction(i._disabled) && !i._disabled({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }))) && i.action ? i.action.call(null, { + "item" : i, + "reference" : vakata_context.reference, + "element" : vakata_context.element, + "position" : { + "x" : vakata_context.position_x, + "y" : vakata_context.position_y + } + }) : false; + }, + _parse : function (o, is_callback) { + if(!o) { return false; } + if(!is_callback) { + vakata_context.html = ""; + vakata_context.items = []; + } + var str = "", + sep = false, + tmp; + + if(is_callback) { str += "<"+"ul>"; } + $.each(o, function (i, val) { + if(!val) { return true; } + vakata_context.items.push(val); + if(!sep && val.separator_before) { + str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + "> <"+"/a><"+"/li>"; + } + sep = false; + str += "<"+"li class='" + (val._class || "") + (val._disabled === true || ($.isFunction(val._disabled) && val._disabled({ "item" : val, "reference" : vakata_context.reference, "element" : vakata_context.element })) ? " vakata-contextmenu-disabled " : "") + "' "+(val.shortcut?" data-shortcut='"+val.shortcut+"' ":'')+">"; + str += "<"+"a href='#' rel='" + (vakata_context.items.length - 1) + "' " + (val.title ? "title='" + val.title + "'" : "") + ">"; + if($.vakata.context.settings.icons) { + str += "<"+"i "; + if(val.icon) { + if(val.icon.indexOf("/") !== -1 || val.icon.indexOf(".") !== -1) { str += " style='background:url(\"" + val.icon + "\") center center no-repeat' "; } + else { str += " class='" + val.icon + "' "; } + } + str += "><"+"/i><"+"span class='vakata-contextmenu-sep'> <"+"/span>"; + } + str += ($.isFunction(val.label) ? val.label({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }) : val.label) + (val.shortcut?' '+ (val.shortcut_label || '') +'':'') + "<"+"/a>"; + if(val.submenu) { + tmp = $.vakata.context._parse(val.submenu, true); + if(tmp) { str += tmp; } + } + str += "<"+"/li>"; + if(val.separator_after) { + str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + "> <"+"/a><"+"/li>"; + sep = true; + } + }); + str = str.replace(/
  • <\/li\>$/,""); + if(is_callback) { str += ""; } + /** + * triggered on the document when the contextmenu is parsed (HTML is built) + * @event + * @plugin contextmenu + * @name context_parse.vakata + * @param {jQuery} reference the element that was right clicked + * @param {jQuery} element the DOM element of the menu itself + * @param {Object} position the x & y coordinates of the menu + */ + if(!is_callback) { vakata_context.html = str; $.vakata.context._trigger("parse"); } + return str.length > 10 ? str : false; + }, + _show_submenu : function (o) { + o = $(o); + if(!o.length || !o.children("ul").length) { return; } + var e = o.children("ul"), + xl = o.offset().left, + x = xl + o.outerWidth(), + y = o.offset().top, + w = e.width(), + h = e.height(), + dw = $(window).width() + $(window).scrollLeft(), + dh = $(window).height() + $(window).scrollTop(); + // може да се спести е една проверка - дали няма някой от класовете вече нагоре + if(right_to_left) { + o[x - (w + 10 + o.outerWidth()) < 0 ? "addClass" : "removeClass"]("vakata-context-left"); + } + else { + o[x + w > dw && xl > dw - x ? "addClass" : "removeClass"]("vakata-context-right"); + } + if(y + h + 10 > dh) { + e.css("bottom","-1px"); + } + + //if does not fit - stick it to the side + if (o.hasClass('vakata-context-right')) { + if (xl < w) { + e.css("margin-right", xl - w); + } + } else { + if (dw - x < w) { + e.css("margin-left", dw - x - w); + } + } + + e.show(); + }, + show : function (reference, position, data) { + var o, e, x, y, w, h, dw, dh, cond = true; + if(vakata_context.element && vakata_context.element.length) { + vakata_context.element.width(''); + } + switch(cond) { + case (!position && !reference): + return false; + case (!!position && !!reference): + vakata_context.reference = reference; + vakata_context.position_x = position.x; + vakata_context.position_y = position.y; + break; + case (!position && !!reference): + vakata_context.reference = reference; + o = reference.offset(); + vakata_context.position_x = o.left + reference.outerHeight(); + vakata_context.position_y = o.top; + break; + case (!!position && !reference): + vakata_context.position_x = position.x; + vakata_context.position_y = position.y; + break; + } + if(!!reference && !data && $(reference).data('vakata_contextmenu')) { + data = $(reference).data('vakata_contextmenu'); + } + if($.vakata.context._parse(data)) { + vakata_context.element.html(vakata_context.html); + } + if(vakata_context.items.length) { + vakata_context.element.appendTo(document.body); + e = vakata_context.element; + x = vakata_context.position_x; + y = vakata_context.position_y; + w = e.width(); + h = e.height(); + dw = $(window).width() + $(window).scrollLeft(); + dh = $(window).height() + $(window).scrollTop(); + if(right_to_left) { + x -= (e.outerWidth() - $(reference).outerWidth()); + if(x < $(window).scrollLeft() + 20) { + x = $(window).scrollLeft() + 20; + } + } + if(x + w + 20 > dw) { + x = dw - (w + 20); + } + if(y + h + 20 > dh) { + y = dh - (h + 20); + } + + vakata_context.element + .css({ "left" : x, "top" : y }) + .show() + .find('a').first().focus().parent().addClass("vakata-context-hover"); + vakata_context.is_visible = true; + /** + * triggered on the document when the contextmenu is shown + * @event + * @plugin contextmenu + * @name context_show.vakata + * @param {jQuery} reference the element that was right clicked + * @param {jQuery} element the DOM element of the menu itself + * @param {Object} position the x & y coordinates of the menu + */ + $.vakata.context._trigger("show"); + } + }, + hide : function () { + if(vakata_context.is_visible) { + vakata_context.element.hide().find("ul").hide().end().find(':focus').blur().end().detach(); + vakata_context.is_visible = false; + /** + * triggered on the document when the contextmenu is hidden + * @event + * @plugin contextmenu + * @name context_hide.vakata + * @param {jQuery} reference the element that was right clicked + * @param {jQuery} element the DOM element of the menu itself + * @param {Object} position the x & y coordinates of the menu + */ + $.vakata.context._trigger("hide"); + } + } + }; + $(function () { + right_to_left = $(document.body).css("direction") === "rtl"; + var to = false; + + vakata_context.element = $("
      "); + vakata_context.element + .on("mouseenter", "li", function (e) { + e.stopImmediatePropagation(); + + if($.contains(this, e.relatedTarget)) { + // премахнато заради delegate mouseleave по-долу + // $(this).find(".vakata-context-hover").removeClass("vakata-context-hover"); + return; + } + + if(to) { clearTimeout(to); } + vakata_context.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end(); + + $(this) + .siblings().find("ul").hide().end().end() + .parentsUntil(".vakata-context", "li").addBack().addClass("vakata-context-hover"); + $.vakata.context._show_submenu(this); + }) + // тестово - дали не натоварва? + .on("mouseleave", "li", function (e) { + if($.contains(this, e.relatedTarget)) { return; } + $(this).find(".vakata-context-hover").addBack().removeClass("vakata-context-hover"); + }) + .on("mouseleave", function (e) { + $(this).find(".vakata-context-hover").removeClass("vakata-context-hover"); + if($.vakata.context.settings.hide_onmouseleave) { + to = setTimeout( + (function (t) { + return function () { $.vakata.context.hide(); }; + }(this)), $.vakata.context.settings.hide_onmouseleave); + } + }) + .on("click", "a", function (e) { + e.preventDefault(); + //}) + //.on("mouseup", "a", function (e) { + if(!$(this).blur().parent().hasClass("vakata-context-disabled") && $.vakata.context._execute($(this).attr("rel")) !== false) { + $.vakata.context.hide(); + } + }) + .on('keydown', 'a', function (e) { + var o = null; + switch(e.which) { + case 13: + case 32: + e.type = "click"; + e.preventDefault(); + $(e.currentTarget).trigger(e); + break; + case 37: + if(vakata_context.is_visible) { + vakata_context.element.find(".vakata-context-hover").last().closest("li").first().find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover").end().end().children('a').focus(); + e.stopImmediatePropagation(); + e.preventDefault(); + } + break; + case 38: + if(vakata_context.is_visible) { + o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first(); + if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").last(); } + o.addClass("vakata-context-hover").children('a').focus(); + e.stopImmediatePropagation(); + e.preventDefault(); + } + break; + case 39: + if(vakata_context.is_visible) { + vakata_context.element.find(".vakata-context-hover").last().children("ul").show().children("li:not(.vakata-context-separator)").removeClass("vakata-context-hover").first().addClass("vakata-context-hover").children('a').focus(); + e.stopImmediatePropagation(); + e.preventDefault(); + } + break; + case 40: + if(vakata_context.is_visible) { + o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first(); + if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").first(); } + o.addClass("vakata-context-hover").children('a').focus(); + e.stopImmediatePropagation(); + e.preventDefault(); + } + break; + case 27: + $.vakata.context.hide(); + e.preventDefault(); + break; + default: + //console.log(e.which); + break; + } + }) + .on('keydown', function (e) { + e.preventDefault(); + var a = vakata_context.element.find('.vakata-contextmenu-shortcut-' + e.which).parent(); + if(a.parent().not('.vakata-context-disabled')) { + a.click(); + } + }); + + $(document) + .on("mousedown.vakata.jstree", function (e) { + if(vakata_context.is_visible && vakata_context.element[0] !== e.target && !$.contains(vakata_context.element[0], e.target)) { + $.vakata.context.hide(); + } + }) + .on("context_show.vakata.jstree", function (e, data) { + vakata_context.element.find("li:has(ul)").children("a").addClass("vakata-context-parent"); + if(right_to_left) { + vakata_context.element.addClass("vakata-context-rtl").css("direction", "rtl"); + } + // also apply a RTL class? + vakata_context.element.find("ul").hide().end(); + }); + }); + }($)); + // $.jstree.defaults.plugins.push("contextmenu"); + + +/** + * ### Drag'n'drop plugin + * + * Enables dragging and dropping of nodes in the tree, resulting in a move or copy operations. + */ + + /** + * stores all defaults for the drag'n'drop plugin + * @name $.jstree.defaults.dnd + * @plugin dnd + */ + $.jstree.defaults.dnd = { + /** + * a boolean indicating if a copy should be possible while dragging (by pressint the meta key or Ctrl). Defaults to `true`. + * @name $.jstree.defaults.dnd.copy + * @plugin dnd + */ + copy : true, + /** + * a number indicating how long a node should remain hovered while dragging to be opened. Defaults to `500`. + * @name $.jstree.defaults.dnd.open_timeout + * @plugin dnd + */ + open_timeout : 500, + /** + * a function invoked each time a node is about to be dragged, invoked in the tree's scope and receives the nodes about to be dragged as an argument (array) and the event that started the drag - return `false` to prevent dragging + * @name $.jstree.defaults.dnd.is_draggable + * @plugin dnd + */ + is_draggable : true, + /** + * a boolean indicating if checks should constantly be made while the user is dragging the node (as opposed to checking only on drop), default is `true` + * @name $.jstree.defaults.dnd.check_while_dragging + * @plugin dnd + */ + check_while_dragging : true, + /** + * a boolean indicating if nodes from this tree should only be copied with dnd (as opposed to moved), default is `false` + * @name $.jstree.defaults.dnd.always_copy + * @plugin dnd + */ + always_copy : false, + /** + * when dropping a node "inside", this setting indicates the position the node should go to - it can be an integer or a string: "first" (same as 0) or "last", default is `0` + * @name $.jstree.defaults.dnd.inside_pos + * @plugin dnd + */ + inside_pos : 0, + /** + * when starting the drag on a node that is selected this setting controls if all selected nodes are dragged or only the single node, default is `true`, which means all selected nodes are dragged when the drag is started on a selected node + * @name $.jstree.defaults.dnd.drag_selection + * @plugin dnd + */ + drag_selection : true, + /** + * controls whether dnd works on touch devices. If left as boolean true dnd will work the same as in desktop browsers, which in some cases may impair scrolling. If set to boolean false dnd will not work on touch devices. There is a special third option - string "selected" which means only selected nodes can be dragged on touch devices. + * @name $.jstree.defaults.dnd.touch + * @plugin dnd + */ + touch : true, + /** + * controls whether items can be dropped anywhere on the node, not just on the anchor, by default only the node anchor is a valid drop target. Works best with the wholerow plugin. If enabled on mobile depending on the interface it might be hard for the user to cancel the drop, since the whole tree container will be a valid drop target. + * @name $.jstree.defaults.dnd.large_drop_target + * @plugin dnd + */ + large_drop_target : false, + /** + * controls whether a drag can be initiated from any part of the node and not just the text/icon part, works best with the wholerow plugin. Keep in mind it can cause problems with tree scrolling on mobile depending on the interface - in that case set the touch option to "selected". + * @name $.jstree.defaults.dnd.large_drag_target + * @plugin dnd + */ + large_drag_target : false, + /** + * controls whether use HTML5 dnd api instead of classical. That will allow better integration of dnd events with other HTML5 controls. + * @reference http://caniuse.com/#feat=dragndrop + * @name $.jstree.defaults.dnd.use_html5 + * @plugin dnd + */ + use_html5: false + }; + var drg, elm; + // TODO: now check works by checking for each node individually, how about max_children, unique, etc? + $.jstree.plugins.dnd = function (options, parent) { + this.init = function (el, options) { + parent.init.call(this, el, options); + this.settings.dnd.use_html5 = this.settings.dnd.use_html5 && ('draggable' in document.createElement('span')); + }; + this.bind = function () { + parent.bind.call(this); + + this.element + .on(this.settings.dnd.use_html5 ? 'dragstart.jstree' : 'mousedown.jstree touchstart.jstree', this.settings.dnd.large_drag_target ? '.jstree-node' : '.jstree-anchor', $.proxy(function (e) { + if(this.settings.dnd.large_drag_target && $(e.target).closest('.jstree-node')[0] !== e.currentTarget) { + return true; + } + if(e.type === "touchstart" && (!this.settings.dnd.touch || (this.settings.dnd.touch === 'selected' && !$(e.currentTarget).closest('.jstree-node').children('.jstree-anchor').hasClass('jstree-clicked')))) { + return true; + } + var obj = this.get_node(e.target), + mlt = this.is_selected(obj) && this.settings.dnd.drag_selection ? this.get_top_selected().length : 1, + txt = (mlt > 1 ? mlt + ' ' + this.get_string('nodes') : this.get_text(e.currentTarget)); + if(this.settings.core.force_text) { + txt = $.vakata.html.escape(txt); + } + if(obj && obj.id && obj.id !== $.jstree.root && (e.which === 1 || e.type === "touchstart" || e.type === "dragstart") && + (this.settings.dnd.is_draggable === true || ($.isFunction(this.settings.dnd.is_draggable) && this.settings.dnd.is_draggable.call(this, (mlt > 1 ? this.get_top_selected(true) : [obj]), e))) + ) { + drg = { 'jstree' : true, 'origin' : this, 'obj' : this.get_node(obj,true), 'nodes' : mlt > 1 ? this.get_top_selected() : [obj.id] }; + elm = e.currentTarget; + if (this.settings.dnd.use_html5) { + $.vakata.dnd._trigger('start', e, { 'helper': $(), 'element': elm, 'data': drg }); + } else { + this.element.trigger('mousedown.jstree'); + return $.vakata.dnd.start(e, drg, '
      ' + txt + '
      '); + } + } + }, this)); + if (this.settings.dnd.use_html5) { + this.element + .on('dragover.jstree', function (e) { + e.preventDefault(); + $.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg }); + return false; + }) + //.on('dragenter.jstree', this.settings.dnd.large_drop_target ? '.jstree-node' : '.jstree-anchor', $.proxy(function (e) { + // e.preventDefault(); + // $.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg }); + // return false; + // }, this)) + .on('drop.jstree', $.proxy(function (e) { + e.preventDefault(); + $.vakata.dnd._trigger('stop', e, { 'helper': $(), 'element': elm, 'data': drg }); + return false; + }, this)); + } + }; + this.redraw_node = function(obj, deep, callback, force_render) { + obj = parent.redraw_node.apply(this, arguments); + if (obj && this.settings.dnd.use_html5) { + if (this.settings.dnd.large_drag_target) { + obj.setAttribute('draggable', true); + } else { + var i, j, tmp = null; + for(i = 0, j = obj.childNodes.length; i < j; i++) { + if(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf("jstree-anchor") !== -1) { + tmp = obj.childNodes[i]; + break; + } + } + if(tmp) { + tmp.setAttribute('draggable', true); + } + } + } + return obj; + }; + }; + + $(function() { + // bind only once for all instances + var lastmv = false, + laster = false, + lastev = false, + opento = false, + marker = $('
       
      ').hide(); //.appendTo('body'); + + $(document) + .on('dnd_start.vakata.jstree', function (e, data) { + lastmv = false; + lastev = false; + if(!data || !data.data || !data.data.jstree) { return; } + marker.appendTo(document.body); //.show(); + }) + .on('dnd_move.vakata.jstree', function (e, data) { + var isDifferentNode = data.event.target !== lastev.target; + if(opento) { + if (!data.event || data.event.type !== 'dragover' || isDifferentNode) { + clearTimeout(opento); + } + } + if(!data || !data.data || !data.data.jstree) { return; } + + // if we are hovering the marker image do nothing (can happen on "inside" drags) + if(data.event.target.id && data.event.target.id === 'jstree-marker') { + return; + } + lastev = data.event; + + var ins = $.jstree.reference(data.event.target), + ref = false, + off = false, + rel = false, + tmp, l, t, h, p, i, o, ok, t1, t2, op, ps, pr, ip, tm, is_copy, pn; + // if we are over an instance + if(ins && ins._data && ins._data.dnd) { + marker.attr('class', 'jstree-' + ins.get_theme() + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' )); + is_copy = data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))); + data.helper + .children().attr('class', 'jstree-' + ins.get_theme() + ' jstree-' + ins.get_theme() + '-' + ins.get_theme_variant() + ' ' + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' )) + .find('.jstree-copy').first()[ is_copy ? 'show' : 'hide' ](); + + // if are hovering the container itself add a new root node + //console.log(data.event); + if( (data.event.target === ins.element[0] || data.event.target === ins.get_container_ul()[0]) && ins.get_container_ul().children().length === 0) { + ok = true; + for(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) { + ok = ok && ins.check( (data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey)) ) ? "copy_node" : "move_node"), (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), $.jstree.root, 'last', { 'dnd' : true, 'ref' : ins.get_node($.jstree.root), 'pos' : 'i', 'origin' : data.data.origin, 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) }); + if(!ok) { break; } + } + if(ok) { + lastmv = { 'ins' : ins, 'par' : $.jstree.root, 'pos' : 'last' }; + marker.hide(); + data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok'); + if (data.event.originalEvent && data.event.originalEvent.dataTransfer) { + data.event.originalEvent.dataTransfer.dropEffect = is_copy ? 'copy' : 'move'; + } + return; + } + } + else { + // if we are hovering a tree node + ref = ins.settings.dnd.large_drop_target ? $(data.event.target).closest('.jstree-node').children('.jstree-anchor') : $(data.event.target).closest('.jstree-anchor'); + if(ref && ref.length && ref.parent().is('.jstree-closed, .jstree-open, .jstree-leaf')) { + off = ref.offset(); + rel = (data.event.pageY !== undefined ? data.event.pageY : data.event.originalEvent.pageY) - off.top; + h = ref.outerHeight(); + if(rel < h / 3) { + o = ['b', 'i', 'a']; + } + else if(rel > h - h / 3) { + o = ['a', 'i', 'b']; + } + else { + o = rel > h / 2 ? ['i', 'a', 'b'] : ['i', 'b', 'a']; + } + $.each(o, function (j, v) { + switch(v) { + case 'b': + l = off.left - 6; + t = off.top; + p = ins.get_parent(ref); + i = ref.parent().index(); + break; + case 'i': + ip = ins.settings.dnd.inside_pos; + tm = ins.get_node(ref.parent()); + l = off.left - 2; + t = off.top + h / 2 + 1; + p = tm.id; + i = ip === 'first' ? 0 : (ip === 'last' ? tm.children.length : Math.min(ip, tm.children.length)); + break; + case 'a': + l = off.left - 6; + t = off.top + h; + p = ins.get_parent(ref); + i = ref.parent().index() + 1; + break; + } + ok = true; + for(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) { + op = data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? "copy_node" : "move_node"; + ps = i; + if(op === "move_node" && v === 'a' && (data.data.origin && data.data.origin === ins) && p === ins.get_parent(data.data.nodes[t1])) { + pr = ins.get_node(p); + if(ps > $.inArray(data.data.nodes[t1], pr.children)) { + ps -= 1; + } + } + ok = ok && ( (ins && ins.settings && ins.settings.dnd && ins.settings.dnd.check_while_dragging === false) || ins.check(op, (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), p, ps, { 'dnd' : true, 'ref' : ins.get_node(ref.parent()), 'pos' : v, 'origin' : data.data.origin, 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) }) ); + if(!ok) { + if(ins && ins.last_error) { laster = ins.last_error(); } + break; + } + } + if(v === 'i' && ref.parent().is('.jstree-closed') && ins.settings.dnd.open_timeout) { + if (!data.event || data.event.type !== 'dragover' || isDifferentNode) { + if (opento) { clearTimeout(opento); } + opento = setTimeout((function (x, z) { return function () { x.open_node(z); }; }(ins, ref)), ins.settings.dnd.open_timeout); + } + } + if(ok) { + pn = ins.get_node(p, true); + if (!pn.hasClass('.jstree-dnd-parent')) { + $('.jstree-dnd-parent').removeClass('jstree-dnd-parent'); + pn.addClass('jstree-dnd-parent'); + } + lastmv = { 'ins' : ins, 'par' : p, 'pos' : v === 'i' && ip === 'last' && i === 0 && !ins.is_loaded(tm) ? 'last' : i }; + marker.css({ 'left' : l + 'px', 'top' : t + 'px' }).show(); + data.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok'); + if (data.event.originalEvent && data.event.originalEvent.dataTransfer) { + data.event.originalEvent.dataTransfer.dropEffect = is_copy ? 'copy' : 'move'; + } + laster = {}; + o = true; + return false; + } + }); + if(o === true) { return; } + } + } + } + $('.jstree-dnd-parent').removeClass('jstree-dnd-parent'); + lastmv = false; + data.helper.find('.jstree-icon').removeClass('jstree-ok').addClass('jstree-er'); + if (data.event.originalEvent && data.event.originalEvent.dataTransfer) { + data.event.originalEvent.dataTransfer.dropEffect = 'none'; + } + marker.hide(); + }) + .on('dnd_scroll.vakata.jstree', function (e, data) { + if(!data || !data.data || !data.data.jstree) { return; } + marker.hide(); + lastmv = false; + lastev = false; + data.helper.find('.jstree-icon').first().removeClass('jstree-ok').addClass('jstree-er'); + }) + .on('dnd_stop.vakata.jstree', function (e, data) { + $('.jstree-dnd-parent').removeClass('jstree-dnd-parent'); + if(opento) { clearTimeout(opento); } + if(!data || !data.data || !data.data.jstree) { return; } + marker.hide().detach(); + var i, j, nodes = []; + if(lastmv) { + for(i = 0, j = data.data.nodes.length; i < j; i++) { + nodes[i] = data.data.origin ? data.data.origin.get_node(data.data.nodes[i]) : data.data.nodes[i]; + } + lastmv.ins[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? 'copy_node' : 'move_node' ](nodes, lastmv.par, lastmv.pos, false, false, false, data.data.origin); + } + else { + i = $(data.event.target).closest('.jstree'); + if(i.length && laster && laster.error && laster.error === 'check') { + i = i.jstree(true); + if(i) { + i.settings.core.error.call(this, laster); + } + } + } + lastev = false; + lastmv = false; + }) + .on('keyup.jstree keydown.jstree', function (e, data) { + data = $.vakata.dnd._get(); + if(data && data.data && data.data.jstree) { + if (e.type === "keyup" && e.which === 27) { + if (opento) { clearTimeout(opento); } + lastmv = false; + laster = false; + lastev = false; + opento = false; + marker.hide().detach(); + $.vakata.dnd._clean(); + } else { + data.helper.find('.jstree-copy').first()[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (e.metaKey || e.ctrlKey))) ? 'show' : 'hide' ](); + if(lastev) { + lastev.metaKey = e.metaKey; + lastev.ctrlKey = e.ctrlKey; + $.vakata.dnd._trigger('move', lastev); + } + } + } + }); + }); + + // helpers + (function ($) { + $.vakata.html = { + div : $('
      '), + escape : function (str) { + return $.vakata.html.div.text(str).html(); + }, + strip : function (str) { + return $.vakata.html.div.empty().append($.parseHTML(str)).text(); + } + }; + // private variable + var vakata_dnd = { + element : false, + target : false, + is_down : false, + is_drag : false, + helper : false, + helper_w: 0, + data : false, + init_x : 0, + init_y : 0, + scroll_l: 0, + scroll_t: 0, + scroll_e: false, + scroll_i: false, + is_touch: false + }; + $.vakata.dnd = { + settings : { + scroll_speed : 10, + scroll_proximity : 20, + helper_left : 5, + helper_top : 10, + threshold : 5, + threshold_touch : 10 + }, + _trigger : function (event_name, e, data) { + if (data === undefined) { + data = $.vakata.dnd._get(); + } + data.event = e; + $(document).triggerHandler("dnd_" + event_name + ".vakata", data); + }, + _get : function () { + return { + "data" : vakata_dnd.data, + "element" : vakata_dnd.element, + "helper" : vakata_dnd.helper + }; + }, + _clean : function () { + if(vakata_dnd.helper) { vakata_dnd.helper.remove(); } + if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; } + vakata_dnd = { + element : false, + target : false, + is_down : false, + is_drag : false, + helper : false, + helper_w: 0, + data : false, + init_x : 0, + init_y : 0, + scroll_l: 0, + scroll_t: 0, + scroll_e: false, + scroll_i: false, + is_touch: false + }; + $(document).off("mousemove.vakata.jstree touchmove.vakata.jstree", $.vakata.dnd.drag); + $(document).off("mouseup.vakata.jstree touchend.vakata.jstree", $.vakata.dnd.stop); + }, + _scroll : function (init_only) { + if(!vakata_dnd.scroll_e || (!vakata_dnd.scroll_l && !vakata_dnd.scroll_t)) { + if(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; } + return false; + } + if(!vakata_dnd.scroll_i) { + vakata_dnd.scroll_i = setInterval($.vakata.dnd._scroll, 100); + return false; + } + if(init_only === true) { return false; } + + var i = vakata_dnd.scroll_e.scrollTop(), + j = vakata_dnd.scroll_e.scrollLeft(); + vakata_dnd.scroll_e.scrollTop(i + vakata_dnd.scroll_t * $.vakata.dnd.settings.scroll_speed); + vakata_dnd.scroll_e.scrollLeft(j + vakata_dnd.scroll_l * $.vakata.dnd.settings.scroll_speed); + if(i !== vakata_dnd.scroll_e.scrollTop() || j !== vakata_dnd.scroll_e.scrollLeft()) { + /** + * triggered on the document when a drag causes an element to scroll + * @event + * @plugin dnd + * @name dnd_scroll.vakata + * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start + * @param {DOM} element the DOM element being dragged + * @param {jQuery} helper the helper shown next to the mouse + * @param {jQuery} event the element that is scrolling + */ + $.vakata.dnd._trigger("scroll", vakata_dnd.scroll_e); + } + }, + start : function (e, data, html) { + if(e.type === "touchstart" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) { + e.pageX = e.originalEvent.changedTouches[0].pageX; + e.pageY = e.originalEvent.changedTouches[0].pageY; + e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset); + } + if(vakata_dnd.is_drag) { $.vakata.dnd.stop({}); } + try { + e.currentTarget.unselectable = "on"; + e.currentTarget.onselectstart = function() { return false; }; + if(e.currentTarget.style) { + e.currentTarget.style.touchAction = "none"; + e.currentTarget.style.msTouchAction = "none"; + e.currentTarget.style.MozUserSelect = "none"; + } + } catch(ignore) { } + vakata_dnd.init_x = e.pageX; + vakata_dnd.init_y = e.pageY; + vakata_dnd.data = data; + vakata_dnd.is_down = true; + vakata_dnd.element = e.currentTarget; + vakata_dnd.target = e.target; + vakata_dnd.is_touch = e.type === "touchstart"; + if(html !== false) { + vakata_dnd.helper = $("
      ").html(html).css({ + "display" : "block", + "margin" : "0", + "padding" : "0", + "position" : "absolute", + "top" : "-2000px", + "lineHeight" : "16px", + "zIndex" : "10000" + }); + } + $(document).on("mousemove.vakata.jstree touchmove.vakata.jstree", $.vakata.dnd.drag); + $(document).on("mouseup.vakata.jstree touchend.vakata.jstree", $.vakata.dnd.stop); + return false; + }, + drag : function (e) { + if(e.type === "touchmove" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) { + e.pageX = e.originalEvent.changedTouches[0].pageX; + e.pageY = e.originalEvent.changedTouches[0].pageY; + e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset); + } + if(!vakata_dnd.is_down) { return; } + if(!vakata_dnd.is_drag) { + if( + Math.abs(e.pageX - vakata_dnd.init_x) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold) || + Math.abs(e.pageY - vakata_dnd.init_y) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold) + ) { + if(vakata_dnd.helper) { + vakata_dnd.helper.appendTo(document.body); + vakata_dnd.helper_w = vakata_dnd.helper.outerWidth(); + } + vakata_dnd.is_drag = true; + $(vakata_dnd.target).one('click.vakata', false); + /** + * triggered on the document when a drag starts + * @event + * @plugin dnd + * @name dnd_start.vakata + * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start + * @param {DOM} element the DOM element being dragged + * @param {jQuery} helper the helper shown next to the mouse + * @param {Object} event the event that caused the start (probably mousemove) + */ + $.vakata.dnd._trigger("start", e); + } + else { return; } + } + + var d = false, w = false, + dh = false, wh = false, + dw = false, ww = false, + dt = false, dl = false, + ht = false, hl = false; + + vakata_dnd.scroll_t = 0; + vakata_dnd.scroll_l = 0; + vakata_dnd.scroll_e = false; + $($(e.target).parentsUntil("body").addBack().get().reverse()) + .filter(function () { + return (/^auto|scroll$/).test($(this).css("overflow")) && + (this.scrollHeight > this.offsetHeight || this.scrollWidth > this.offsetWidth); + }) + .each(function () { + var t = $(this), o = t.offset(); + if(this.scrollHeight > this.offsetHeight) { + if(o.top + t.height() - e.pageY < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = 1; } + if(e.pageY - o.top < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = -1; } + } + if(this.scrollWidth > this.offsetWidth) { + if(o.left + t.width() - e.pageX < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = 1; } + if(e.pageX - o.left < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = -1; } + } + if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) { + vakata_dnd.scroll_e = $(this); + return false; + } + }); + + if(!vakata_dnd.scroll_e) { + d = $(document); w = $(window); + dh = d.height(); wh = w.height(); + dw = d.width(); ww = w.width(); + dt = d.scrollTop(); dl = d.scrollLeft(); + if(dh > wh && e.pageY - dt < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = -1; } + if(dh > wh && wh - (e.pageY - dt) < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_t = 1; } + if(dw > ww && e.pageX - dl < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = -1; } + if(dw > ww && ww - (e.pageX - dl) < $.vakata.dnd.settings.scroll_proximity) { vakata_dnd.scroll_l = 1; } + if(vakata_dnd.scroll_t || vakata_dnd.scroll_l) { + vakata_dnd.scroll_e = d; + } + } + if(vakata_dnd.scroll_e) { $.vakata.dnd._scroll(true); } + + if(vakata_dnd.helper) { + ht = parseInt(e.pageY + $.vakata.dnd.settings.helper_top, 10); + hl = parseInt(e.pageX + $.vakata.dnd.settings.helper_left, 10); + if(dh && ht + 25 > dh) { ht = dh - 50; } + if(dw && hl + vakata_dnd.helper_w > dw) { hl = dw - (vakata_dnd.helper_w + 2); } + vakata_dnd.helper.css({ + left : hl + "px", + top : ht + "px" + }); + } + /** + * triggered on the document when a drag is in progress + * @event + * @plugin dnd + * @name dnd_move.vakata + * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start + * @param {DOM} element the DOM element being dragged + * @param {jQuery} helper the helper shown next to the mouse + * @param {Object} event the event that caused this to trigger (most likely mousemove) + */ + $.vakata.dnd._trigger("move", e); + return false; + }, + stop : function (e) { + if(e.type === "touchend" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) { + e.pageX = e.originalEvent.changedTouches[0].pageX; + e.pageY = e.originalEvent.changedTouches[0].pageY; + e.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset); + } + if(vakata_dnd.is_drag) { + /** + * triggered on the document when a drag stops (the dragged element is dropped) + * @event + * @plugin dnd + * @name dnd_stop.vakata + * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start + * @param {DOM} element the DOM element being dragged + * @param {jQuery} helper the helper shown next to the mouse + * @param {Object} event the event that caused the stop + */ + if (e.target !== vakata_dnd.target) { + $(vakata_dnd.target).off('click.vakata'); + } + $.vakata.dnd._trigger("stop", e); + } + else { + if(e.type === "touchend" && e.target === vakata_dnd.target) { + var to = setTimeout(function () { $(e.target).click(); }, 100); + $(e.target).one('click', function() { if(to) { clearTimeout(to); } }); + } + } + $.vakata.dnd._clean(); + return false; + } + }; + }($)); + + // include the dnd plugin by default + // $.jstree.defaults.plugins.push("dnd"); + + +/** + * ### Massload plugin + * + * Adds massload functionality to jsTree, so that multiple nodes can be loaded in a single request (only useful with lazy loading). + */ + + /** + * massload configuration + * + * It is possible to set this to a standard jQuery-like AJAX config. + * In addition to the standard jQuery ajax options here you can supply functions for `data` and `url`, the functions will be run in the current instance's scope and a param will be passed indicating which node IDs need to be loaded, the return value of those functions will be used. + * + * You can also set this to a function, that function will receive the node IDs being loaded as argument and a second param which is a function (callback) which should be called with the result. + * + * Both the AJAX and the function approach rely on the same return value - an object where the keys are the node IDs, and the value is the children of that node as an array. + * + * { + * "id1" : [{ "text" : "Child of ID1", "id" : "c1" }, { "text" : "Another child of ID1", "id" : "c2" }], + * "id2" : [{ "text" : "Child of ID2", "id" : "c3" }] + * } + * + * @name $.jstree.defaults.massload + * @plugin massload + */ + $.jstree.defaults.massload = null; + $.jstree.plugins.massload = function (options, parent) { + this.init = function (el, options) { + this._data.massload = {}; + parent.init.call(this, el, options); + }; + this._load_nodes = function (nodes, callback, is_callback, force_reload) { + var s = this.settings.massload, + nodesString = JSON.stringify(nodes), + toLoad = [], + m = this._model.data, + i, j, dom; + if (!is_callback) { + for(i = 0, j = nodes.length; i < j; i++) { + if(!m[nodes[i]] || ( (!m[nodes[i]].state.loaded && !m[nodes[i]].state.failed) || force_reload) ) { + toLoad.push(nodes[i]); + dom = this.get_node(nodes[i], true); + if (dom && dom.length) { + dom.addClass("jstree-loading").attr('aria-busy',true); + } + } + } + this._data.massload = {}; + if (toLoad.length) { + if($.isFunction(s)) { + return s.call(this, toLoad, $.proxy(function (data) { + var i, j; + if(data) { + for(i in data) { + if(data.hasOwnProperty(i)) { + this._data.massload[i] = data[i]; + } + } + } + for(i = 0, j = nodes.length; i < j; i++) { + dom = this.get_node(nodes[i], true); + if (dom && dom.length) { + dom.removeClass("jstree-loading").attr('aria-busy',false); + } + } + parent._load_nodes.call(this, nodes, callback, is_callback, force_reload); + }, this)); + } + if(typeof s === 'object' && s && s.url) { + s = $.extend(true, {}, s); + if($.isFunction(s.url)) { + s.url = s.url.call(this, toLoad); + } + if($.isFunction(s.data)) { + s.data = s.data.call(this, toLoad); + } + return $.ajax(s) + .done($.proxy(function (data,t,x) { + var i, j; + if(data) { + for(i in data) { + if(data.hasOwnProperty(i)) { + this._data.massload[i] = data[i]; + } + } + } + for(i = 0, j = nodes.length; i < j; i++) { + dom = this.get_node(nodes[i], true); + if (dom && dom.length) { + dom.removeClass("jstree-loading").attr('aria-busy',false); + } + } + parent._load_nodes.call(this, nodes, callback, is_callback, force_reload); + }, this)) + .fail($.proxy(function (f) { + parent._load_nodes.call(this, nodes, callback, is_callback, force_reload); + }, this)); + } + } + } + return parent._load_nodes.call(this, nodes, callback, is_callback, force_reload); + }; + this._load_node = function (obj, callback) { + var data = this._data.massload[obj.id], + rslt = null, dom; + if(data) { + rslt = this[typeof data === 'string' ? '_append_html_data' : '_append_json_data']( + obj, + typeof data === 'string' ? $($.parseHTML(data)).filter(function () { return this.nodeType !== 3; }) : data, + function (status) { callback.call(this, status); } + ); + dom = this.get_node(obj.id, true); + if (dom && dom.length) { + dom.removeClass("jstree-loading").attr('aria-busy',false); + } + delete this._data.massload[obj.id]; + return rslt; + } + return parent._load_node.call(this, obj, callback); + }; + }; + +/** + * ### Search plugin + * + * Adds search functionality to jsTree. + */ + + /** + * stores all defaults for the search plugin + * @name $.jstree.defaults.search + * @plugin search + */ + $.jstree.defaults.search = { + /** + * a jQuery-like AJAX config, which jstree uses if a server should be queried for results. + * + * A `str` (which is the search string) parameter will be added with the request, an optional `inside` parameter will be added if the search is limited to a node id. The expected result is a JSON array with nodes that need to be opened so that matching nodes will be revealed. + * Leave this setting as `false` to not query the server. You can also set this to a function, which will be invoked in the instance's scope and receive 3 parameters - the search string, the callback to call with the array of nodes to load, and the optional node ID to limit the search to + * @name $.jstree.defaults.search.ajax + * @plugin search + */ + ajax : false, + /** + * Indicates if the search should be fuzzy or not (should `chnd3` match `child node 3`). Default is `false`. + * @name $.jstree.defaults.search.fuzzy + * @plugin search + */ + fuzzy : false, + /** + * Indicates if the search should be case sensitive. Default is `false`. + * @name $.jstree.defaults.search.case_sensitive + * @plugin search + */ + case_sensitive : false, + /** + * Indicates if the tree should be filtered (by default) to show only matching nodes (keep in mind this can be a heavy on large trees in old browsers). + * This setting can be changed at runtime when calling the search method. Default is `false`. + * @name $.jstree.defaults.search.show_only_matches + * @plugin search + */ + show_only_matches : false, + /** + * Indicates if the children of matched element are shown (when show_only_matches is true) + * This setting can be changed at runtime when calling the search method. Default is `false`. + * @name $.jstree.defaults.search.show_only_matches_children + * @plugin search + */ + show_only_matches_children : false, + /** + * Indicates if all nodes opened to reveal the search result, should be closed when the search is cleared or a new search is performed. Default is `true`. + * @name $.jstree.defaults.search.close_opened_onclear + * @plugin search + */ + close_opened_onclear : true, + /** + * Indicates if only leaf nodes should be included in search results. Default is `false`. + * @name $.jstree.defaults.search.search_leaves_only + * @plugin search + */ + search_leaves_only : false, + /** + * If set to a function it wil be called in the instance's scope with two arguments - search string and node (where node will be every node in the structure, so use with caution). + * If the function returns a truthy value the node will be considered a match (it might not be displayed if search_only_leaves is set to true and the node is not a leaf). Default is `false`. + * @name $.jstree.defaults.search.search_callback + * @plugin search + */ + search_callback : false + }; + + $.jstree.plugins.search = function (options, parent) { + this.bind = function () { + parent.bind.call(this); + + this._data.search.str = ""; + this._data.search.dom = $(); + this._data.search.res = []; + this._data.search.opn = []; + this._data.search.som = false; + this._data.search.smc = false; + this._data.search.hdn = []; + + this.element + .on("search.jstree", $.proxy(function (e, data) { + if(this._data.search.som && data.res.length) { + var m = this._model.data, i, j, p = [], k, l; + for(i = 0, j = data.res.length; i < j; i++) { + if(m[data.res[i]] && !m[data.res[i]].state.hidden) { + p.push(data.res[i]); + p = p.concat(m[data.res[i]].parents); + if(this._data.search.smc) { + for (k = 0, l = m[data.res[i]].children_d.length; k < l; k++) { + if (m[m[data.res[i]].children_d[k]] && !m[m[data.res[i]].children_d[k]].state.hidden) { + p.push(m[data.res[i]].children_d[k]); + } + } + } + } + } + p = $.vakata.array_remove_item($.vakata.array_unique(p), $.jstree.root); + this._data.search.hdn = this.hide_all(true); + this.show_node(p, true); + this.redraw(true); + } + }, this)) + .on("clear_search.jstree", $.proxy(function (e, data) { + if(this._data.search.som && data.res.length) { + this.show_node(this._data.search.hdn, true); + this.redraw(true); + } + }, this)); + }; + /** + * used to search the tree nodes for a given string + * @name search(str [, skip_async]) + * @param {String} str the search string + * @param {Boolean} skip_async if set to true server will not be queried even if configured + * @param {Boolean} show_only_matches if set to true only matching nodes will be shown (keep in mind this can be very slow on large trees or old browsers) + * @param {mixed} inside an optional node to whose children to limit the search + * @param {Boolean} append if set to true the results of this search are appended to the previous search + * @plugin search + * @trigger search.jstree + */ + this.search = function (str, skip_async, show_only_matches, inside, append, show_only_matches_children) { + if(str === false || $.trim(str.toString()) === "") { + return this.clear_search(); + } + inside = this.get_node(inside); + inside = inside && inside.id ? inside.id : null; + str = str.toString(); + var s = this.settings.search, + a = s.ajax ? s.ajax : false, + m = this._model.data, + f = null, + r = [], + p = [], i, j; + if(this._data.search.res.length && !append) { + this.clear_search(); + } + if(show_only_matches === undefined) { + show_only_matches = s.show_only_matches; + } + if(show_only_matches_children === undefined) { + show_only_matches_children = s.show_only_matches_children; + } + if(!skip_async && a !== false) { + if($.isFunction(a)) { + return a.call(this, str, $.proxy(function (d) { + if(d && d.d) { d = d.d; } + this._load_nodes(!$.isArray(d) ? [] : $.vakata.array_unique(d), function () { + this.search(str, true, show_only_matches, inside, append, show_only_matches_children); + }); + }, this), inside); + } + else { + a = $.extend({}, a); + if(!a.data) { a.data = {}; } + a.data.str = str; + if(inside) { + a.data.inside = inside; + } + if (this._data.search.lastRequest) { + this._data.search.lastRequest.abort(); + } + this._data.search.lastRequest = $.ajax(a) + .fail($.proxy(function () { + this._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'search', 'id' : 'search_01', 'reason' : 'Could not load search parents', 'data' : JSON.stringify(a) }; + this.settings.core.error.call(this, this._data.core.last_error); + }, this)) + .done($.proxy(function (d) { + if(d && d.d) { d = d.d; } + this._load_nodes(!$.isArray(d) ? [] : $.vakata.array_unique(d), function () { + this.search(str, true, show_only_matches, inside, append, show_only_matches_children); + }); + }, this)); + return this._data.search.lastRequest; + } + } + if(!append) { + this._data.search.str = str; + this._data.search.dom = $(); + this._data.search.res = []; + this._data.search.opn = []; + this._data.search.som = show_only_matches; + this._data.search.smc = show_only_matches_children; + } + + f = new $.vakata.search(str, true, { caseSensitive : s.case_sensitive, fuzzy : s.fuzzy }); + $.each(m[inside ? inside : $.jstree.root].children_d, function (ii, i) { + var v = m[i]; + if(v.text && !v.state.hidden && (!s.search_leaves_only || (v.state.loaded && v.children.length === 0)) && ( (s.search_callback && s.search_callback.call(this, str, v)) || (!s.search_callback && f.search(v.text).isMatch) ) ) { + r.push(i); + p = p.concat(v.parents); + } + }); + if(r.length) { + p = $.vakata.array_unique(p); + for(i = 0, j = p.length; i < j; i++) { + if(p[i] !== $.jstree.root && m[p[i]] && this.open_node(p[i], null, 0) === true) { + this._data.search.opn.push(p[i]); + } + } + if(!append) { + this._data.search.dom = $(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return "0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\$&') : v.replace($.jstree.idregex,'\\$&'); }).join(', #'))); + this._data.search.res = r; + } + else { + this._data.search.dom = this._data.search.dom.add($(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return "0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\$&') : v.replace($.jstree.idregex,'\\$&'); }).join(', #')))); + this._data.search.res = $.vakata.array_unique(this._data.search.res.concat(r)); + } + this._data.search.dom.children(".jstree-anchor").addClass('jstree-search'); + } + /** + * triggered after search is complete + * @event + * @name search.jstree + * @param {jQuery} nodes a jQuery collection of matching nodes + * @param {String} str the search string + * @param {Array} res a collection of objects represeing the matching nodes + * @plugin search + */ + this.trigger('search', { nodes : this._data.search.dom, str : str, res : this._data.search.res, show_only_matches : show_only_matches }); + }; + /** + * used to clear the last search (removes classes and shows all nodes if filtering is on) + * @name clear_search() + * @plugin search + * @trigger clear_search.jstree + */ + this.clear_search = function () { + if(this.settings.search.close_opened_onclear) { + this.close_node(this._data.search.opn, 0); + } + /** + * triggered after search is complete + * @event + * @name clear_search.jstree + * @param {jQuery} nodes a jQuery collection of matching nodes (the result from the last search) + * @param {String} str the search string (the last search string) + * @param {Array} res a collection of objects represeing the matching nodes (the result from the last search) + * @plugin search + */ + this.trigger('clear_search', { 'nodes' : this._data.search.dom, str : this._data.search.str, res : this._data.search.res }); + if(this._data.search.res.length) { + this._data.search.dom = $(this.element[0].querySelectorAll('#' + $.map(this._data.search.res, function (v) { + return "0123456789".indexOf(v[0]) !== -1 ? '\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\$&') : v.replace($.jstree.idregex,'\\$&'); + }).join(', #'))); + this._data.search.dom.children(".jstree-anchor").removeClass("jstree-search"); + } + this._data.search.str = ""; + this._data.search.res = []; + this._data.search.opn = []; + this._data.search.dom = $(); + }; + + this.redraw_node = function(obj, deep, callback, force_render) { + obj = parent.redraw_node.apply(this, arguments); + if(obj) { + if($.inArray(obj.id, this._data.search.res) !== -1) { + var i, j, tmp = null; + for(i = 0, j = obj.childNodes.length; i < j; i++) { + if(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf("jstree-anchor") !== -1) { + tmp = obj.childNodes[i]; + break; + } + } + if(tmp) { + tmp.className += ' jstree-search'; + } + } + } + return obj; + }; + }; + + // helpers + (function ($) { + // from http://kiro.me/projects/fuse.html + $.vakata.search = function(pattern, txt, options) { + options = options || {}; + options = $.extend({}, $.vakata.search.defaults, options); + if(options.fuzzy !== false) { + options.fuzzy = true; + } + pattern = options.caseSensitive ? pattern : pattern.toLowerCase(); + var MATCH_LOCATION = options.location, + MATCH_DISTANCE = options.distance, + MATCH_THRESHOLD = options.threshold, + patternLen = pattern.length, + matchmask, pattern_alphabet, match_bitapScore, search; + if(patternLen > 32) { + options.fuzzy = false; + } + if(options.fuzzy) { + matchmask = 1 << (patternLen - 1); + pattern_alphabet = (function () { + var mask = {}, + i = 0; + for (i = 0; i < patternLen; i++) { + mask[pattern.charAt(i)] = 0; + } + for (i = 0; i < patternLen; i++) { + mask[pattern.charAt(i)] |= 1 << (patternLen - i - 1); + } + return mask; + }()); + match_bitapScore = function (e, x) { + var accuracy = e / patternLen, + proximity = Math.abs(MATCH_LOCATION - x); + if(!MATCH_DISTANCE) { + return proximity ? 1.0 : accuracy; + } + return accuracy + (proximity / MATCH_DISTANCE); + }; + } + search = function (text) { + text = options.caseSensitive ? text : text.toLowerCase(); + if(pattern === text || text.indexOf(pattern) !== -1) { + return { + isMatch: true, + score: 0 + }; + } + if(!options.fuzzy) { + return { + isMatch: false, + score: 1 + }; + } + var i, j, + textLen = text.length, + scoreThreshold = MATCH_THRESHOLD, + bestLoc = text.indexOf(pattern, MATCH_LOCATION), + binMin, binMid, + binMax = patternLen + textLen, + lastRd, start, finish, rd, charMatch, + score = 1, + locations = []; + if (bestLoc !== -1) { + scoreThreshold = Math.min(match_bitapScore(0, bestLoc), scoreThreshold); + bestLoc = text.lastIndexOf(pattern, MATCH_LOCATION + patternLen); + if (bestLoc !== -1) { + scoreThreshold = Math.min(match_bitapScore(0, bestLoc), scoreThreshold); + } + } + bestLoc = -1; + for (i = 0; i < patternLen; i++) { + binMin = 0; + binMid = binMax; + while (binMin < binMid) { + if (match_bitapScore(i, MATCH_LOCATION + binMid) <= scoreThreshold) { + binMin = binMid; + } else { + binMax = binMid; + } + binMid = Math.floor((binMax - binMin) / 2 + binMin); + } + binMax = binMid; + start = Math.max(1, MATCH_LOCATION - binMid + 1); + finish = Math.min(MATCH_LOCATION + binMid, textLen) + patternLen; + rd = new Array(finish + 2); + rd[finish + 1] = (1 << i) - 1; + for (j = finish; j >= start; j--) { + charMatch = pattern_alphabet[text.charAt(j - 1)]; + if (i === 0) { + rd[j] = ((rd[j + 1] << 1) | 1) & charMatch; + } else { + rd[j] = ((rd[j + 1] << 1) | 1) & charMatch | (((lastRd[j + 1] | lastRd[j]) << 1) | 1) | lastRd[j + 1]; + } + if (rd[j] & matchmask) { + score = match_bitapScore(i, j - 1); + if (score <= scoreThreshold) { + scoreThreshold = score; + bestLoc = j - 1; + locations.push(bestLoc); + if (bestLoc > MATCH_LOCATION) { + start = Math.max(1, 2 * MATCH_LOCATION - bestLoc); + } else { + break; + } + } + } + } + if (match_bitapScore(i + 1, MATCH_LOCATION) > scoreThreshold) { + break; + } + lastRd = rd; + } + return { + isMatch: bestLoc >= 0, + score: score + }; + }; + return txt === true ? { 'search' : search } : search(txt); + }; + $.vakata.search.defaults = { + location : 0, + distance : 100, + threshold : 0.6, + fuzzy : false, + caseSensitive : false + }; + }($)); + + // include the search plugin by default + // $.jstree.defaults.plugins.push("search"); + + +/** + * ### Sort plugin + * + * Automatically sorts all siblings in the tree according to a sorting function. + */ + + /** + * the settings function used to sort the nodes. + * It is executed in the tree's context, accepts two nodes as arguments and should return `1` or `-1`. + * @name $.jstree.defaults.sort + * @plugin sort + */ + $.jstree.defaults.sort = function (a, b) { + //return this.get_type(a) === this.get_type(b) ? (this.get_text(a) > this.get_text(b) ? 1 : -1) : this.get_type(a) >= this.get_type(b); + return this.get_text(a) > this.get_text(b) ? 1 : -1; + }; + $.jstree.plugins.sort = function (options, parent) { + this.bind = function () { + parent.bind.call(this); + this.element + .on("model.jstree", $.proxy(function (e, data) { + this.sort(data.parent, true); + }, this)) + .on("rename_node.jstree create_node.jstree", $.proxy(function (e, data) { + this.sort(data.parent || data.node.parent, false); + this.redraw_node(data.parent || data.node.parent, true); + }, this)) + .on("move_node.jstree copy_node.jstree", $.proxy(function (e, data) { + this.sort(data.parent, false); + this.redraw_node(data.parent, true); + }, this)); + }; + /** + * used to sort a node's children + * @private + * @name sort(obj [, deep]) + * @param {mixed} obj the node + * @param {Boolean} deep if set to `true` nodes are sorted recursively. + * @plugin sort + * @trigger search.jstree + */ + this.sort = function (obj, deep) { + var i, j; + obj = this.get_node(obj); + if(obj && obj.children && obj.children.length) { + obj.children.sort($.proxy(this.settings.sort, this)); + if(deep) { + for(i = 0, j = obj.children_d.length; i < j; i++) { + this.sort(obj.children_d[i], false); + } + } + } + }; + }; + + // include the sort plugin by default + // $.jstree.defaults.plugins.push("sort"); + +/** + * ### State plugin + * + * Saves the state of the tree (selected nodes, opened nodes) on the user's computer using available options (localStorage, cookies, etc) + */ + + var to = false; + /** + * stores all defaults for the state plugin + * @name $.jstree.defaults.state + * @plugin state + */ + $.jstree.defaults.state = { + /** + * A string for the key to use when saving the current tree (change if using multiple trees in your project). Defaults to `jstree`. + * @name $.jstree.defaults.state.key + * @plugin state + */ + key : 'jstree', + /** + * A space separated list of events that trigger a state save. Defaults to `changed.jstree open_node.jstree close_node.jstree`. + * @name $.jstree.defaults.state.events + * @plugin state + */ + events : 'changed.jstree open_node.jstree close_node.jstree check_node.jstree uncheck_node.jstree', + /** + * Time in milliseconds after which the state will expire. Defaults to 'false' meaning - no expire. + * @name $.jstree.defaults.state.ttl + * @plugin state + */ + ttl : false, + /** + * A function that will be executed prior to restoring state with one argument - the state object. Can be used to clear unwanted parts of the state. + * @name $.jstree.defaults.state.filter + * @plugin state + */ + filter : false, + /** + * Should loaded nodes be restored (setting this to true means that it is possible that the whole tree will be loaded for some users - use with caution). Defaults to `false` + * @name $.jstree.defaults.state.preserve_loaded + * @plugin state + */ + preserve_loaded : false + }; + $.jstree.plugins.state = function (options, parent) { + this.bind = function () { + parent.bind.call(this); + var bind = $.proxy(function () { + this.element.on(this.settings.state.events, $.proxy(function () { + if(to) { clearTimeout(to); } + to = setTimeout($.proxy(function () { this.save_state(); }, this), 100); + }, this)); + /** + * triggered when the state plugin is finished restoring the state (and immediately after ready if there is no state to restore). + * @event + * @name state_ready.jstree + * @plugin state + */ + this.trigger('state_ready'); + }, this); + this.element + .on("ready.jstree", $.proxy(function (e, data) { + this.element.one("restore_state.jstree", bind); + if(!this.restore_state()) { bind(); } + }, this)); + }; + /** + * save the state + * @name save_state() + * @plugin state + */ + this.save_state = function () { + var tm = this.get_state(); + if (!this.settings.state.preserve_loaded) { + delete tm.core.loaded; + } + var st = { 'state' : tm, 'ttl' : this.settings.state.ttl, 'sec' : +(new Date()) }; + $.vakata.storage.set(this.settings.state.key, JSON.stringify(st)); + }; + /** + * restore the state from the user's computer + * @name restore_state() + * @plugin state + */ + this.restore_state = function () { + var k = $.vakata.storage.get(this.settings.state.key); + if(!!k) { try { k = JSON.parse(k); } catch(ex) { return false; } } + if(!!k && k.ttl && k.sec && +(new Date()) - k.sec > k.ttl) { return false; } + if(!!k && k.state) { k = k.state; } + if(!!k && $.isFunction(this.settings.state.filter)) { k = this.settings.state.filter.call(this, k); } + if(!!k) { + if (!this.settings.state.preserve_loaded) { + delete k.core.loaded; + } + this.element.one("set_state.jstree", function (e, data) { data.instance.trigger('restore_state', { 'state' : $.extend(true, {}, k) }); }); + this.set_state(k); + return true; + } + return false; + }; + /** + * clear the state on the user's computer + * @name clear_state() + * @plugin state + */ + this.clear_state = function () { + return $.vakata.storage.del(this.settings.state.key); + }; + }; + + (function ($, undefined) { + $.vakata.storage = { + // simply specifying the functions in FF throws an error + set : function (key, val) { return window.localStorage.setItem(key, val); }, + get : function (key) { return window.localStorage.getItem(key); }, + del : function (key) { return window.localStorage.removeItem(key); } + }; + }($)); + + // include the state plugin by default + // $.jstree.defaults.plugins.push("state"); + +/** + * ### Types plugin + * + * Makes it possible to add predefined types for groups of nodes, which make it possible to easily control nesting rules and icon for each group. + */ + + /** + * An object storing all types as key value pairs, where the key is the type name and the value is an object that could contain following keys (all optional). + * + * * `max_children` the maximum number of immediate children this node type can have. Do not specify or set to `-1` for unlimited. + * * `max_depth` the maximum number of nesting this node type can have. A value of `1` would mean that the node can have children, but no grandchildren. Do not specify or set to `-1` for unlimited. + * * `valid_children` an array of node type strings, that nodes of this type can have as children. Do not specify or set to `-1` for no limits. + * * `icon` a string - can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class. Omit to use the default icon from your theme. + * * `li_attr` an object of values which will be used to add HTML attributes on the resulting LI DOM node (merged with the node's own data) + * * `a_attr` an object of values which will be used to add HTML attributes on the resulting A DOM node (merged with the node's own data) + * + * There are two predefined types: + * + * * `#` represents the root of the tree, for example `max_children` would control the maximum number of root nodes. + * * `default` represents the default node - any settings here will be applied to all nodes that do not have a type specified. + * + * @name $.jstree.defaults.types + * @plugin types + */ + $.jstree.defaults.types = { + 'default' : {} + }; + $.jstree.defaults.types[$.jstree.root] = {}; + + $.jstree.plugins.types = function (options, parent) { + this.init = function (el, options) { + var i, j; + if(options && options.types && options.types['default']) { + for(i in options.types) { + if(i !== "default" && i !== $.jstree.root && options.types.hasOwnProperty(i)) { + for(j in options.types['default']) { + if(options.types['default'].hasOwnProperty(j) && options.types[i][j] === undefined) { + options.types[i][j] = options.types['default'][j]; + } + } + } + } + } + parent.init.call(this, el, options); + this._model.data[$.jstree.root].type = $.jstree.root; + }; + this.refresh = function (skip_loading, forget_state) { + parent.refresh.call(this, skip_loading, forget_state); + this._model.data[$.jstree.root].type = $.jstree.root; + }; + this.bind = function () { + this.element + .on('model.jstree', $.proxy(function (e, data) { + var m = this._model.data, + dpc = data.nodes, + t = this.settings.types, + i, j, c = 'default', k; + for(i = 0, j = dpc.length; i < j; i++) { + c = 'default'; + if(m[dpc[i]].original && m[dpc[i]].original.type && t[m[dpc[i]].original.type]) { + c = m[dpc[i]].original.type; + } + if(m[dpc[i]].data && m[dpc[i]].data.jstree && m[dpc[i]].data.jstree.type && t[m[dpc[i]].data.jstree.type]) { + c = m[dpc[i]].data.jstree.type; + } + m[dpc[i]].type = c; + if(m[dpc[i]].icon === true && t[c].icon !== undefined) { + m[dpc[i]].icon = t[c].icon; + } + if(t[c].li_attr !== undefined && typeof t[c].li_attr === 'object') { + for (k in t[c].li_attr) { + if (t[c].li_attr.hasOwnProperty(k)) { + if (k === 'id') { + continue; + } + else if (m[dpc[i]].li_attr[k] === undefined) { + m[dpc[i]].li_attr[k] = t[c].li_attr[k]; + } + else if (k === 'class') { + m[dpc[i]].li_attr['class'] = t[c].li_attr['class'] + ' ' + m[dpc[i]].li_attr['class']; + } + } + } + } + if(t[c].a_attr !== undefined && typeof t[c].a_attr === 'object') { + for (k in t[c].a_attr) { + if (t[c].a_attr.hasOwnProperty(k)) { + if (k === 'id') { + continue; + } + else if (m[dpc[i]].a_attr[k] === undefined) { + m[dpc[i]].a_attr[k] = t[c].a_attr[k]; + } + else if (k === 'href' && m[dpc[i]].a_attr[k] === '#') { + m[dpc[i]].a_attr['href'] = t[c].a_attr['href']; + } + else if (k === 'class') { + m[dpc[i]].a_attr['class'] = t[c].a_attr['class'] + ' ' + m[dpc[i]].a_attr['class']; + } + } + } + } + } + m[$.jstree.root].type = $.jstree.root; + }, this)); + parent.bind.call(this); + }; + this.get_json = function (obj, options, flat) { + var i, j, + m = this._model.data, + opt = options ? $.extend(true, {}, options, {no_id:false}) : {}, + tmp = parent.get_json.call(this, obj, opt, flat); + if(tmp === false) { return false; } + if($.isArray(tmp)) { + for(i = 0, j = tmp.length; i < j; i++) { + tmp[i].type = tmp[i].id && m[tmp[i].id] && m[tmp[i].id].type ? m[tmp[i].id].type : "default"; + if(options && options.no_id) { + delete tmp[i].id; + if(tmp[i].li_attr && tmp[i].li_attr.id) { + delete tmp[i].li_attr.id; + } + if(tmp[i].a_attr && tmp[i].a_attr.id) { + delete tmp[i].a_attr.id; + } + } + } + } + else { + tmp.type = tmp.id && m[tmp.id] && m[tmp.id].type ? m[tmp.id].type : "default"; + if(options && options.no_id) { + tmp = this._delete_ids(tmp); + } + } + return tmp; + }; + this._delete_ids = function (tmp) { + if($.isArray(tmp)) { + for(var i = 0, j = tmp.length; i < j; i++) { + tmp[i] = this._delete_ids(tmp[i]); + } + return tmp; + } + delete tmp.id; + if(tmp.li_attr && tmp.li_attr.id) { + delete tmp.li_attr.id; + } + if(tmp.a_attr && tmp.a_attr.id) { + delete tmp.a_attr.id; + } + if(tmp.children && $.isArray(tmp.children)) { + tmp.children = this._delete_ids(tmp.children); + } + return tmp; + }; + this.check = function (chk, obj, par, pos, more) { + if(parent.check.call(this, chk, obj, par, pos, more) === false) { return false; } + obj = obj && obj.id ? obj : this.get_node(obj); + par = par && par.id ? par : this.get_node(par); + var m = obj && obj.id ? (more && more.origin ? more.origin : $.jstree.reference(obj.id)) : null, tmp, d, i, j; + m = m && m._model && m._model.data ? m._model.data : null; + switch(chk) { + case "create_node": + case "move_node": + case "copy_node": + if(chk !== 'move_node' || $.inArray(obj.id, par.children) === -1) { + tmp = this.get_rules(par); + if(tmp.max_children !== undefined && tmp.max_children !== -1 && tmp.max_children === par.children.length) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_01', 'reason' : 'max_children prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + return false; + } + if(tmp.valid_children !== undefined && tmp.valid_children !== -1 && $.inArray((obj.type || 'default'), tmp.valid_children) === -1) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_02', 'reason' : 'valid_children prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + return false; + } + if(m && obj.children_d && obj.parents) { + d = 0; + for(i = 0, j = obj.children_d.length; i < j; i++) { + d = Math.max(d, m[obj.children_d[i]].parents.length); + } + d = d - obj.parents.length + 1; + } + if(d <= 0 || d === undefined) { d = 1; } + do { + if(tmp.max_depth !== undefined && tmp.max_depth !== -1 && tmp.max_depth < d) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_03', 'reason' : 'max_depth prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + return false; + } + par = this.get_node(par.parent); + tmp = this.get_rules(par); + d++; + } while(par); + } + break; + } + return true; + }; + /** + * used to retrieve the type settings object for a node + * @name get_rules(obj) + * @param {mixed} obj the node to find the rules for + * @return {Object} + * @plugin types + */ + this.get_rules = function (obj) { + obj = this.get_node(obj); + if(!obj) { return false; } + var tmp = this.get_type(obj, true); + if(tmp.max_depth === undefined) { tmp.max_depth = -1; } + if(tmp.max_children === undefined) { tmp.max_children = -1; } + if(tmp.valid_children === undefined) { tmp.valid_children = -1; } + return tmp; + }; + /** + * used to retrieve the type string or settings object for a node + * @name get_type(obj [, rules]) + * @param {mixed} obj the node to find the rules for + * @param {Boolean} rules if set to `true` instead of a string the settings object will be returned + * @return {String|Object} + * @plugin types + */ + this.get_type = function (obj, rules) { + obj = this.get_node(obj); + return (!obj) ? false : ( rules ? $.extend({ 'type' : obj.type }, this.settings.types[obj.type]) : obj.type); + }; + /** + * used to change a node's type + * @name set_type(obj, type) + * @param {mixed} obj the node to change + * @param {String} type the new type + * @plugin types + */ + this.set_type = function (obj, type) { + var m = this._model.data, t, t1, t2, old_type, old_icon, k, d, a; + if($.isArray(obj)) { + obj = obj.slice(); + for(t1 = 0, t2 = obj.length; t1 < t2; t1++) { + this.set_type(obj[t1], type); + } + return true; + } + t = this.settings.types; + obj = this.get_node(obj); + if(!t[type] || !obj) { return false; } + d = this.get_node(obj, true); + if (d && d.length) { + a = d.children('.jstree-anchor'); + } + old_type = obj.type; + old_icon = this.get_icon(obj); + obj.type = type; + if(old_icon === true || !t[old_type] || (t[old_type].icon !== undefined && old_icon === t[old_type].icon)) { + this.set_icon(obj, t[type].icon !== undefined ? t[type].icon : true); + } + + // remove old type props + if(t[old_type] && t[old_type].li_attr !== undefined && typeof t[old_type].li_attr === 'object') { + for (k in t[old_type].li_attr) { + if (t[old_type].li_attr.hasOwnProperty(k)) { + if (k === 'id') { + continue; + } + else if (k === 'class') { + m[obj.id].li_attr['class'] = (m[obj.id].li_attr['class'] || '').replace(t[old_type].li_attr[k], ''); + if (d) { d.removeClass(t[old_type].li_attr[k]); } + } + else if (m[obj.id].li_attr[k] === t[old_type].li_attr[k]) { + m[obj.id].li_attr[k] = null; + if (d) { d.removeAttr(k); } + } + } + } + } + if(t[old_type] && t[old_type].a_attr !== undefined && typeof t[old_type].a_attr === 'object') { + for (k in t[old_type].a_attr) { + if (t[old_type].a_attr.hasOwnProperty(k)) { + if (k === 'id') { + continue; + } + else if (k === 'class') { + m[obj.id].a_attr['class'] = (m[obj.id].a_attr['class'] || '').replace(t[old_type].a_attr[k], ''); + if (a) { a.removeClass(t[old_type].a_attr[k]); } + } + else if (m[obj.id].a_attr[k] === t[old_type].a_attr[k]) { + if (k === 'href') { + m[obj.id].a_attr[k] = '#'; + if (a) { a.attr('href', '#'); } + } + else { + delete m[obj.id].a_attr[k]; + if (a) { a.removeAttr(k); } + } + } + } + } + } + + // add new props + if(t[type].li_attr !== undefined && typeof t[type].li_attr === 'object') { + for (k in t[type].li_attr) { + if (t[type].li_attr.hasOwnProperty(k)) { + if (k === 'id') { + continue; + } + else if (m[obj.id].li_attr[k] === undefined) { + m[obj.id].li_attr[k] = t[type].li_attr[k]; + if (d) { + if (k === 'class') { + d.addClass(t[type].li_attr[k]); + } + else { + d.attr(k, t[type].li_attr[k]); + } + } + } + else if (k === 'class') { + m[obj.id].li_attr['class'] = t[type].li_attr[k] + ' ' + m[obj.id].li_attr['class']; + if (d) { d.addClass(t[type].li_attr[k]); } + } + } + } + } + if(t[type].a_attr !== undefined && typeof t[type].a_attr === 'object') { + for (k in t[type].a_attr) { + if (t[type].a_attr.hasOwnProperty(k)) { + if (k === 'id') { + continue; + } + else if (m[obj.id].a_attr[k] === undefined) { + m[obj.id].a_attr[k] = t[type].a_attr[k]; + if (a) { + if (k === 'class') { + a.addClass(t[type].a_attr[k]); + } + else { + a.attr(k, t[type].a_attr[k]); + } + } + } + else if (k === 'href' && m[obj.id].a_attr[k] === '#') { + m[obj.id].a_attr['href'] = t[type].a_attr['href']; + if (a) { a.attr('href', t[type].a_attr['href']); } + } + else if (k === 'class') { + m[obj.id].a_attr['class'] = t[type].a_attr['class'] + ' ' + m[obj.id].a_attr['class']; + if (a) { a.addClass(t[type].a_attr[k]); } + } + } + } + } + + return true; + }; + }; + // include the types plugin by default + // $.jstree.defaults.plugins.push("types"); + + +/** + * ### Unique plugin + * + * Enforces that no nodes with the same name can coexist as siblings. + */ + + /** + * stores all defaults for the unique plugin + * @name $.jstree.defaults.unique + * @plugin unique + */ + $.jstree.defaults.unique = { + /** + * Indicates if the comparison should be case sensitive. Default is `false`. + * @name $.jstree.defaults.unique.case_sensitive + * @plugin unique + */ + case_sensitive : false, + /** + * Indicates if white space should be trimmed before the comparison. Default is `false`. + * @name $.jstree.defaults.unique.trim_whitespace + * @plugin unique + */ + trim_whitespace : false, + /** + * A callback executed in the instance's scope when a new node is created and the name is already taken, the two arguments are the conflicting name and the counter. The default will produce results like `New node (2)`. + * @name $.jstree.defaults.unique.duplicate + * @plugin unique + */ + duplicate : function (name, counter) { + return name + ' (' + counter + ')'; + } + }; + + $.jstree.plugins.unique = function (options, parent) { + this.check = function (chk, obj, par, pos, more) { + if(parent.check.call(this, chk, obj, par, pos, more) === false) { return false; } + obj = obj && obj.id ? obj : this.get_node(obj); + par = par && par.id ? par : this.get_node(par); + if(!par || !par.children) { return true; } + var n = chk === "rename_node" ? pos : obj.text, + c = [], + s = this.settings.unique.case_sensitive, + w = this.settings.unique.trim_whitespace, + m = this._model.data, i, j, t; + for(i = 0, j = par.children.length; i < j; i++) { + t = m[par.children[i]].text; + if (!s) { + t = t.toLowerCase(); + } + if (w) { + t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + } + c.push(t); + } + if(!s) { n = n.toLowerCase(); } + if (w) { n = n.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); } + switch(chk) { + case "delete_node": + return true; + case "rename_node": + t = obj.text || ''; + if (!s) { + t = t.toLowerCase(); + } + if (w) { + t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + } + i = ($.inArray(n, c) === -1 || (obj.text && t === n)); + if(!i) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_01', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + } + return i; + case "create_node": + i = ($.inArray(n, c) === -1); + if(!i) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_04', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + } + return i; + case "copy_node": + i = ($.inArray(n, c) === -1); + if(!i) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_02', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + } + return i; + case "move_node": + i = ( (obj.parent === par.id && (!more || !more.is_multi)) || $.inArray(n, c) === -1); + if(!i) { + this._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_03', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) }; + } + return i; + } + return true; + }; + this.create_node = function (par, node, pos, callback, is_loaded) { + if(!node || node.text === undefined) { + if(par === null) { + par = $.jstree.root; + } + par = this.get_node(par); + if(!par) { + return parent.create_node.call(this, par, node, pos, callback, is_loaded); + } + pos = pos === undefined ? "last" : pos; + if(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) { + return parent.create_node.call(this, par, node, pos, callback, is_loaded); + } + if(!node) { node = {}; } + var tmp, n, dpc, i, j, m = this._model.data, s = this.settings.unique.case_sensitive, w = this.settings.unique.trim_whitespace, cb = this.settings.unique.duplicate, t; + n = tmp = this.get_string('New node'); + dpc = []; + for(i = 0, j = par.children.length; i < j; i++) { + t = m[par.children[i]].text; + if (!s) { + t = t.toLowerCase(); + } + if (w) { + t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + } + dpc.push(t); + } + i = 1; + t = n; + if (!s) { + t = t.toLowerCase(); + } + if (w) { + t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + } + while($.inArray(t, dpc) !== -1) { + n = cb.call(this, tmp, (++i)).toString(); + t = n; + if (!s) { + t = t.toLowerCase(); + } + if (w) { + t = t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + } + } + node.text = n; + } + return parent.create_node.call(this, par, node, pos, callback, is_loaded); + }; + }; + + // include the unique plugin by default + // $.jstree.defaults.plugins.push("unique"); + + +/** + * ### Wholerow plugin + * + * Makes each node appear block level. Making selection easier. May cause slow down for large trees in old browsers. + */ + + var div = document.createElement('DIV'); + div.setAttribute('unselectable','on'); + div.setAttribute('role','presentation'); + div.className = 'jstree-wholerow'; + div.innerHTML = ' '; + $.jstree.plugins.wholerow = function (options, parent) { + this.bind = function () { + parent.bind.call(this); + + this.element + .on('ready.jstree set_state.jstree', $.proxy(function () { + this.hide_dots(); + }, this)) + .on("init.jstree loading.jstree ready.jstree", $.proxy(function () { + //div.style.height = this._data.core.li_height + 'px'; + this.get_container_ul().addClass('jstree-wholerow-ul'); + }, this)) + .on("deselect_all.jstree", $.proxy(function (e, data) { + this.element.find('.jstree-wholerow-clicked').removeClass('jstree-wholerow-clicked'); + }, this)) + .on("changed.jstree", $.proxy(function (e, data) { + this.element.find('.jstree-wholerow-clicked').removeClass('jstree-wholerow-clicked'); + var tmp = false, i, j; + for(i = 0, j = data.selected.length; i < j; i++) { + tmp = this.get_node(data.selected[i], true); + if(tmp && tmp.length) { + tmp.children('.jstree-wholerow').addClass('jstree-wholerow-clicked'); + } + } + }, this)) + .on("open_node.jstree", $.proxy(function (e, data) { + this.get_node(data.node, true).find('.jstree-clicked').parent().children('.jstree-wholerow').addClass('jstree-wholerow-clicked'); + }, this)) + .on("hover_node.jstree dehover_node.jstree", $.proxy(function (e, data) { + if(e.type === "hover_node" && this.is_disabled(data.node)) { return; } + this.get_node(data.node, true).children('.jstree-wholerow')[e.type === "hover_node"?"addClass":"removeClass"]('jstree-wholerow-hovered'); + }, this)) + .on("contextmenu.jstree", ".jstree-wholerow", $.proxy(function (e) { + if (this._data.contextmenu) { + e.preventDefault(); + var tmp = $.Event('contextmenu', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey, pageX : e.pageX, pageY : e.pageY }); + $(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp); + } + }, this)) + /*! + .on("mousedown.jstree touchstart.jstree", ".jstree-wholerow", function (e) { + if(e.target === e.currentTarget) { + var a = $(e.currentTarget).closest(".jstree-node").children(".jstree-anchor"); + e.target = a[0]; + a.trigger(e); + } + }) + */ + .on("click.jstree", ".jstree-wholerow", function (e) { + e.stopImmediatePropagation(); + var tmp = $.Event('click', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey }); + $(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp).focus(); + }) + .on("dblclick.jstree", ".jstree-wholerow", function (e) { + e.stopImmediatePropagation(); + var tmp = $.Event('dblclick', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey }); + $(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp).focus(); + }) + .on("click.jstree", ".jstree-leaf > .jstree-ocl", $.proxy(function (e) { + e.stopImmediatePropagation(); + var tmp = $.Event('click', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey }); + $(e.currentTarget).closest(".jstree-node").children(".jstree-anchor").first().trigger(tmp).focus(); + }, this)) + .on("mouseover.jstree", ".jstree-wholerow, .jstree-icon", $.proxy(function (e) { + e.stopImmediatePropagation(); + if(!this.is_disabled(e.currentTarget)) { + this.hover_node(e.currentTarget); + } + return false; + }, this)) + .on("mouseleave.jstree", ".jstree-node", $.proxy(function (e) { + this.dehover_node(e.currentTarget); + }, this)); + }; + this.teardown = function () { + if(this.settings.wholerow) { + this.element.find(".jstree-wholerow").remove(); + } + parent.teardown.call(this); + }; + this.redraw_node = function(obj, deep, callback, force_render) { + obj = parent.redraw_node.apply(this, arguments); + if(obj) { + var tmp = div.cloneNode(true); + //tmp.style.height = this._data.core.li_height + 'px'; + if($.inArray(obj.id, this._data.core.selected) !== -1) { tmp.className += ' jstree-wholerow-clicked'; } + if(this._data.core.focused && this._data.core.focused === obj.id) { tmp.className += ' jstree-wholerow-hovered'; } + obj.insertBefore(tmp, obj.childNodes[0]); + } + return obj; + }; + }; + // include the wholerow plugin by default + // $.jstree.defaults.plugins.push("wholerow"); + if(document.registerElement && Object && Object.create) { + var proto = Object.create(HTMLElement.prototype); + proto.createdCallback = function () { + var c = { core : {}, plugins : [] }, i; + for(i in $.jstree.plugins) { + if($.jstree.plugins.hasOwnProperty(i) && this.attributes[i]) { + c.plugins.push(i); + if(this.getAttribute(i) && JSON.parse(this.getAttribute(i))) { + c[i] = JSON.parse(this.getAttribute(i)); + } + } + } + for(i in $.jstree.defaults.core) { + if($.jstree.defaults.core.hasOwnProperty(i) && this.attributes[i]) { + c.core[i] = JSON.parse(this.getAttribute(i)) || this.getAttribute(i); + } + } + $(this).jstree(c); + }; + // proto.attributeChangedCallback = function (name, previous, value) { }; + try { + document.registerElement("vakata-jstree", { prototype: proto }); + } catch(ignore) { } + } + +})); \ No newline at end of file diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/32px.png b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/32px.png new file mode 100644 index 000000000000..d6fd72114f82 Binary files /dev/null and b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/32px.png differ diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/40px.png b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/40px.png new file mode 100644 index 000000000000..4fc88e41e665 Binary files /dev/null and b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/40px.png differ diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/style.css b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/style.css new file mode 100644 index 000000000000..7cde4aa28994 --- /dev/null +++ b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/style.css @@ -0,0 +1,1152 @@ +/* jsTree default dark theme */ +.jstree-node, +.jstree-children, +.jstree-container-ul { + display: block; + margin: 0; + padding: 0; + list-style-type: none; + list-style-image: none; +} +.jstree-node { + white-space: nowrap; +} +.jstree-anchor { + display: inline-block; + color: black; + white-space: nowrap; + padding: 0 4px 0 1px; + margin: 0; + vertical-align: top; +} +.jstree-anchor:focus { + outline: 0; +} +.jstree-anchor, +.jstree-anchor:link, +.jstree-anchor:visited, +.jstree-anchor:hover, +.jstree-anchor:active { + text-decoration: none; + color: inherit; +} +.jstree-icon { + display: inline-block; + text-decoration: none; + margin: 0; + padding: 0; + vertical-align: top; + text-align: center; +} +.jstree-icon:empty { + display: inline-block; + text-decoration: none; + margin: 0; + padding: 0; + vertical-align: top; + text-align: center; +} +.jstree-ocl { + cursor: pointer; +} +.jstree-leaf > .jstree-ocl { + cursor: default; +} +.jstree .jstree-open > .jstree-children { + display: block; +} +.jstree .jstree-closed > .jstree-children, +.jstree .jstree-leaf > .jstree-children { + display: none; +} +.jstree-anchor > .jstree-themeicon { + margin-right: 2px; +} +.jstree-no-icons .jstree-themeicon, +.jstree-anchor > .jstree-themeicon-hidden { + display: none; +} +.jstree-hidden, +.jstree-node.jstree-hidden { + display: none; +} +.jstree-rtl .jstree-anchor { + padding: 0 1px 0 4px; +} +.jstree-rtl .jstree-anchor > .jstree-themeicon { + margin-left: 2px; + margin-right: 0; +} +.jstree-rtl .jstree-node { + margin-left: 0; +} +.jstree-rtl .jstree-container-ul > .jstree-node { + margin-right: 0; +} +.jstree-wholerow-ul { + position: relative; + display: inline-block; + min-width: 100%; +} +.jstree-wholerow-ul .jstree-leaf > .jstree-ocl { + cursor: pointer; +} +.jstree-wholerow-ul .jstree-anchor, +.jstree-wholerow-ul .jstree-icon { + position: relative; +} +.jstree-wholerow-ul .jstree-wholerow { + width: 100%; + cursor: pointer; + position: absolute; + left: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.jstree-contextmenu .jstree-anchor { + -webkit-user-select: none; + /* disable selection/Copy of UIWebView */ + -webkit-touch-callout: none; + /* disable the IOS popup when long-press on a link */ +} +.vakata-context { + display: none; +} +.vakata-context, +.vakata-context ul { + margin: 0; + padding: 2px; + position: absolute; + background: #f5f5f5; + border: 1px solid #979797; + box-shadow: 2px 2px 2px #999999; +} +.vakata-context ul { + list-style: none; + left: 100%; + margin-top: -2.7em; + margin-left: -4px; +} +.vakata-context .vakata-context-right ul { + left: auto; + right: 100%; + margin-left: auto; + margin-right: -4px; +} +.vakata-context li { + list-style: none; +} +.vakata-context li > a { + display: block; + padding: 0 2em 0 2em; + text-decoration: none; + width: auto; + color: black; + white-space: nowrap; + line-height: 2.4em; + text-shadow: 1px 1px 0 white; + border-radius: 1px; +} +.vakata-context li > a:hover { + position: relative; + background-color: #e8eff7; + box-shadow: 0 0 2px #0a6aa1; +} +.vakata-context li > a.vakata-context-parent { + background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw=="); + background-position: right center; + background-repeat: no-repeat; +} +.vakata-context li > a:focus { + outline: 0; +} +.vakata-context .vakata-context-hover > a { + position: relative; + background-color: #e8eff7; + box-shadow: 0 0 2px #0a6aa1; +} +.vakata-context .vakata-context-separator > a, +.vakata-context .vakata-context-separator > a:hover { + background: white; + border: 0; + border-top: 1px solid #e2e3e3; + height: 1px; + min-height: 1px; + max-height: 1px; + padding: 0; + margin: 0 0 0 2.4em; + border-left: 1px solid #e0e0e0; + text-shadow: 0 0 0 transparent; + box-shadow: 0 0 0 transparent; + border-radius: 0; +} +.vakata-context .vakata-contextmenu-disabled a, +.vakata-context .vakata-contextmenu-disabled a:hover { + color: silver; + background-color: transparent; + border: 0; + box-shadow: 0 0 0; +} +.vakata-context li > a > i { + text-decoration: none; + display: inline-block; + width: 2.4em; + height: 2.4em; + background: transparent; + margin: 0 0 0 -2em; + vertical-align: top; + text-align: center; + line-height: 2.4em; +} +.vakata-context li > a > i:empty { + width: 2.4em; + line-height: 2.4em; +} +.vakata-context li > a .vakata-contextmenu-sep { + display: inline-block; + width: 1px; + height: 2.4em; + background: white; + margin: 0 0.5em 0 0; + border-left: 1px solid #e2e3e3; +} +.vakata-context .vakata-contextmenu-shortcut { + font-size: 0.8em; + color: silver; + opacity: 0.5; + display: none; +} +.vakata-context-rtl ul { + left: auto; + right: 100%; + margin-left: auto; + margin-right: -4px; +} +.vakata-context-rtl li > a.vakata-context-parent { + background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7"); + background-position: left center; + background-repeat: no-repeat; +} +.vakata-context-rtl .vakata-context-separator > a { + margin: 0 2.4em 0 0; + border-left: 0; + border-right: 1px solid #e2e3e3; +} +.vakata-context-rtl .vakata-context-left ul { + right: auto; + left: 100%; + margin-left: -4px; + margin-right: auto; +} +.vakata-context-rtl li > a > i { + margin: 0 -2em 0 0; +} +.vakata-context-rtl li > a .vakata-contextmenu-sep { + margin: 0 0 0 0.5em; + border-left-color: white; + background: #e2e3e3; +} +#jstree-marker { + position: absolute; + top: 0; + left: 0; + margin: -5px 0 0 0; + padding: 0; + border-right: 0; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid; + width: 0; + height: 0; + font-size: 0; + line-height: 0; +} +#jstree-dnd { + line-height: 16px; + margin: 0; + padding: 4px; +} +#jstree-dnd .jstree-icon, +#jstree-dnd .jstree-copy { + display: inline-block; + text-decoration: none; + margin: 0 2px 0 0; + padding: 0; + width: 16px; + height: 16px; +} +#jstree-dnd .jstree-ok { + background: green; +} +#jstree-dnd .jstree-er { + background: red; +} +#jstree-dnd .jstree-copy { + margin: 0 2px 0 2px; +} +.jstree-default-dark .jstree-node, +.jstree-default-dark .jstree-icon { + background-repeat: no-repeat; + background-color: transparent; +} +.jstree-default-dark .jstree-anchor, +.jstree-default-dark .jstree-animated, +.jstree-default-dark .jstree-wholerow { + transition: background-color 0.15s, box-shadow 0.15s; +} +.jstree-default-dark .jstree-hovered { + background: #555555; + border-radius: 2px; + box-shadow: inset 0 0 1px #555555; +} +.jstree-default-dark .jstree-context { + background: #555555; + border-radius: 2px; + box-shadow: inset 0 0 1px #555555; +} +.jstree-default-dark .jstree-clicked { + background: #5fa2db; + border-radius: 2px; + box-shadow: inset 0 0 1px #666666; +} +.jstree-default-dark .jstree-no-icons .jstree-anchor > .jstree-themeicon { + display: none; +} +.jstree-default-dark .jstree-disabled { + background: transparent; + color: #666666; +} +.jstree-default-dark .jstree-disabled.jstree-hovered { + background: transparent; + box-shadow: none; +} +.jstree-default-dark .jstree-disabled.jstree-clicked { + background: #333333; +} +.jstree-default-dark .jstree-disabled > .jstree-icon { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default-dark .jstree-search { + font-style: italic; + color: #ffffff; + font-weight: bold; +} +.jstree-default-dark .jstree-no-checkboxes .jstree-checkbox { + display: none !important; +} +.jstree-default-dark.jstree-checkbox-no-clicked .jstree-clicked { + background: transparent; + box-shadow: none; +} +.jstree-default-dark.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered { + background: #555555; +} +.jstree-default-dark.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked { + background: transparent; +} +.jstree-default-dark.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered { + background: #555555; +} +.jstree-default-dark > .jstree-striped { + min-width: 100%; + display: inline-block; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==") left top repeat; +} +.jstree-default-dark > .jstree-wholerow-ul .jstree-hovered, +.jstree-default-dark > .jstree-wholerow-ul .jstree-clicked { + background: transparent; + box-shadow: none; + border-radius: 0; +} +.jstree-default-dark .jstree-wholerow { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.jstree-default-dark .jstree-wholerow-hovered { + background: #555555; +} +.jstree-default-dark .jstree-wholerow-clicked { + background: #5fa2db; + background: -webkit-linear-gradient(top, #5fa2db 0%, #5fa2db 100%); + background: linear-gradient(to bottom, #5fa2db 0%, #5fa2db 100%); +} +.jstree-default-dark .jstree-node { + min-height: 24px; + line-height: 24px; + margin-left: 24px; + min-width: 24px; +} +.jstree-default-dark .jstree-anchor { + line-height: 24px; + height: 24px; +} +.jstree-default-dark .jstree-icon { + width: 24px; + height: 24px; + line-height: 24px; +} +.jstree-default-dark .jstree-icon:empty { + width: 24px; + height: 24px; + line-height: 24px; +} +.jstree-default-dark.jstree-rtl .jstree-node { + margin-right: 24px; +} +.jstree-default-dark .jstree-wholerow { + height: 24px; +} +.jstree-default-dark .jstree-node, +.jstree-default-dark .jstree-icon { + background-image: url("32px.png"); +} +.jstree-default-dark .jstree-node { + background-position: -292px -4px; + background-repeat: repeat-y; +} +.jstree-default-dark .jstree-last { + background: transparent; +} +.jstree-default-dark .jstree-open > .jstree-ocl { + background-position: -132px -4px; +} +.jstree-default-dark .jstree-closed > .jstree-ocl { + background-position: -100px -4px; +} +.jstree-default-dark .jstree-leaf > .jstree-ocl { + background-position: -68px -4px; +} +.jstree-default-dark .jstree-themeicon { + background-position: -260px -4px; +} +.jstree-default-dark > .jstree-no-dots .jstree-node, +.jstree-default-dark > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-dark > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -36px -4px; +} +.jstree-default-dark > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -4px -4px; +} +.jstree-default-dark .jstree-disabled { + background: transparent; +} +.jstree-default-dark .jstree-disabled.jstree-hovered { + background: transparent; +} +.jstree-default-dark .jstree-disabled.jstree-clicked { + background: #efefef; +} +.jstree-default-dark .jstree-checkbox { + background-position: -164px -4px; +} +.jstree-default-dark .jstree-checkbox:hover { + background-position: -164px -36px; +} +.jstree-default-dark.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, +.jstree-default-dark .jstree-checked > .jstree-checkbox { + background-position: -228px -4px; +} +.jstree-default-dark.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, +.jstree-default-dark .jstree-checked > .jstree-checkbox:hover { + background-position: -228px -36px; +} +.jstree-default-dark .jstree-anchor > .jstree-undetermined { + background-position: -196px -4px; +} +.jstree-default-dark .jstree-anchor > .jstree-undetermined:hover { + background-position: -196px -36px; +} +.jstree-default-dark .jstree-checkbox-disabled { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default-dark > .jstree-striped { + background-size: auto 48px; +} +.jstree-default-dark.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); + background-position: 100% 1px; + background-repeat: repeat-y; +} +.jstree-default-dark.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-dark.jstree-rtl .jstree-open > .jstree-ocl { + background-position: -132px -36px; +} +.jstree-default-dark.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -100px -36px; +} +.jstree-default-dark.jstree-rtl .jstree-leaf > .jstree-ocl { + background-position: -68px -36px; +} +.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-node, +.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -36px -36px; +} +.jstree-default-dark.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -4px -36px; +} +.jstree-default-dark .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; +} +.jstree-default-dark > .jstree-container-ul .jstree-loading > .jstree-ocl { + background: url("throbber.gif") center center no-repeat; +} +.jstree-default-dark .jstree-file { + background: url("32px.png") -100px -68px no-repeat; +} +.jstree-default-dark .jstree-folder { + background: url("32px.png") -260px -4px no-repeat; +} +.jstree-default-dark > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; +} +#jstree-dnd.jstree-default-dark { + line-height: 24px; + padding: 0 4px; +} +#jstree-dnd.jstree-default-dark .jstree-ok, +#jstree-dnd.jstree-default-dark .jstree-er { + background-image: url("32px.png"); + background-repeat: no-repeat; + background-color: transparent; +} +#jstree-dnd.jstree-default-dark i { + background: transparent; + width: 24px; + height: 24px; + line-height: 24px; +} +#jstree-dnd.jstree-default-dark .jstree-ok { + background-position: -4px -68px; +} +#jstree-dnd.jstree-default-dark .jstree-er { + background-position: -36px -68px; +} +.jstree-default-dark .jstree-ellipsis { + overflow: hidden; +} +.jstree-default-dark .jstree-ellipsis .jstree-anchor { + width: calc(100% - 29px); + text-overflow: ellipsis; + overflow: hidden; +} +.jstree-default-dark .jstree-ellipsis.jstree-no-icons .jstree-anchor { + width: calc(100% - 5px); +} +.jstree-default-dark.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); +} +.jstree-default-dark.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-dark-small .jstree-node { + min-height: 18px; + line-height: 18px; + margin-left: 18px; + min-width: 18px; +} +.jstree-default-dark-small .jstree-anchor { + line-height: 18px; + height: 18px; +} +.jstree-default-dark-small .jstree-icon { + width: 18px; + height: 18px; + line-height: 18px; +} +.jstree-default-dark-small .jstree-icon:empty { + width: 18px; + height: 18px; + line-height: 18px; +} +.jstree-default-dark-small.jstree-rtl .jstree-node { + margin-right: 18px; +} +.jstree-default-dark-small .jstree-wholerow { + height: 18px; +} +.jstree-default-dark-small .jstree-node, +.jstree-default-dark-small .jstree-icon { + background-image: url("32px.png"); +} +.jstree-default-dark-small .jstree-node { + background-position: -295px -7px; + background-repeat: repeat-y; +} +.jstree-default-dark-small .jstree-last { + background: transparent; +} +.jstree-default-dark-small .jstree-open > .jstree-ocl { + background-position: -135px -7px; +} +.jstree-default-dark-small .jstree-closed > .jstree-ocl { + background-position: -103px -7px; +} +.jstree-default-dark-small .jstree-leaf > .jstree-ocl { + background-position: -71px -7px; +} +.jstree-default-dark-small .jstree-themeicon { + background-position: -263px -7px; +} +.jstree-default-dark-small > .jstree-no-dots .jstree-node, +.jstree-default-dark-small > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-dark-small > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -39px -7px; +} +.jstree-default-dark-small > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -7px -7px; +} +.jstree-default-dark-small .jstree-disabled { + background: transparent; +} +.jstree-default-dark-small .jstree-disabled.jstree-hovered { + background: transparent; +} +.jstree-default-dark-small .jstree-disabled.jstree-clicked { + background: #efefef; +} +.jstree-default-dark-small .jstree-checkbox { + background-position: -167px -7px; +} +.jstree-default-dark-small .jstree-checkbox:hover { + background-position: -167px -39px; +} +.jstree-default-dark-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, +.jstree-default-dark-small .jstree-checked > .jstree-checkbox { + background-position: -231px -7px; +} +.jstree-default-dark-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, +.jstree-default-dark-small .jstree-checked > .jstree-checkbox:hover { + background-position: -231px -39px; +} +.jstree-default-dark-small .jstree-anchor > .jstree-undetermined { + background-position: -199px -7px; +} +.jstree-default-dark-small .jstree-anchor > .jstree-undetermined:hover { + background-position: -199px -39px; +} +.jstree-default-dark-small .jstree-checkbox-disabled { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default-dark-small > .jstree-striped { + background-size: auto 36px; +} +.jstree-default-dark-small.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); + background-position: 100% 1px; + background-repeat: repeat-y; +} +.jstree-default-dark-small.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-dark-small.jstree-rtl .jstree-open > .jstree-ocl { + background-position: -135px -39px; +} +.jstree-default-dark-small.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -103px -39px; +} +.jstree-default-dark-small.jstree-rtl .jstree-leaf > .jstree-ocl { + background-position: -71px -39px; +} +.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-node, +.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -39px -39px; +} +.jstree-default-dark-small.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -7px -39px; +} +.jstree-default-dark-small .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; +} +.jstree-default-dark-small > .jstree-container-ul .jstree-loading > .jstree-ocl { + background: url("throbber.gif") center center no-repeat; +} +.jstree-default-dark-small .jstree-file { + background: url("32px.png") -103px -71px no-repeat; +} +.jstree-default-dark-small .jstree-folder { + background: url("32px.png") -263px -7px no-repeat; +} +.jstree-default-dark-small > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; +} +#jstree-dnd.jstree-default-dark-small { + line-height: 18px; + padding: 0 4px; +} +#jstree-dnd.jstree-default-dark-small .jstree-ok, +#jstree-dnd.jstree-default-dark-small .jstree-er { + background-image: url("32px.png"); + background-repeat: no-repeat; + background-color: transparent; +} +#jstree-dnd.jstree-default-dark-small i { + background: transparent; + width: 18px; + height: 18px; + line-height: 18px; +} +#jstree-dnd.jstree-default-dark-small .jstree-ok { + background-position: -7px -71px; +} +#jstree-dnd.jstree-default-dark-small .jstree-er { + background-position: -39px -71px; +} +.jstree-default-dark-small .jstree-ellipsis { + overflow: hidden; +} +.jstree-default-dark-small .jstree-ellipsis .jstree-anchor { + width: calc(100% - 23px); + text-overflow: ellipsis; + overflow: hidden; +} +.jstree-default-dark-small .jstree-ellipsis.jstree-no-icons .jstree-anchor { + width: calc(100% - 5px); +} +.jstree-default-dark-small.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg=="); +} +.jstree-default-dark-small.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-dark-large .jstree-node { + min-height: 32px; + line-height: 32px; + margin-left: 32px; + min-width: 32px; +} +.jstree-default-dark-large .jstree-anchor { + line-height: 32px; + height: 32px; +} +.jstree-default-dark-large .jstree-icon { + width: 32px; + height: 32px; + line-height: 32px; +} +.jstree-default-dark-large .jstree-icon:empty { + width: 32px; + height: 32px; + line-height: 32px; +} +.jstree-default-dark-large.jstree-rtl .jstree-node { + margin-right: 32px; +} +.jstree-default-dark-large .jstree-wholerow { + height: 32px; +} +.jstree-default-dark-large .jstree-node, +.jstree-default-dark-large .jstree-icon { + background-image: url("32px.png"); +} +.jstree-default-dark-large .jstree-node { + background-position: -288px 0px; + background-repeat: repeat-y; +} +.jstree-default-dark-large .jstree-last { + background: transparent; +} +.jstree-default-dark-large .jstree-open > .jstree-ocl { + background-position: -128px 0px; +} +.jstree-default-dark-large .jstree-closed > .jstree-ocl { + background-position: -96px 0px; +} +.jstree-default-dark-large .jstree-leaf > .jstree-ocl { + background-position: -64px 0px; +} +.jstree-default-dark-large .jstree-themeicon { + background-position: -256px 0px; +} +.jstree-default-dark-large > .jstree-no-dots .jstree-node, +.jstree-default-dark-large > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-dark-large > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -32px 0px; +} +.jstree-default-dark-large > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: 0px 0px; +} +.jstree-default-dark-large .jstree-disabled { + background: transparent; +} +.jstree-default-dark-large .jstree-disabled.jstree-hovered { + background: transparent; +} +.jstree-default-dark-large .jstree-disabled.jstree-clicked { + background: #efefef; +} +.jstree-default-dark-large .jstree-checkbox { + background-position: -160px 0px; +} +.jstree-default-dark-large .jstree-checkbox:hover { + background-position: -160px -32px; +} +.jstree-default-dark-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, +.jstree-default-dark-large .jstree-checked > .jstree-checkbox { + background-position: -224px 0px; +} +.jstree-default-dark-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, +.jstree-default-dark-large .jstree-checked > .jstree-checkbox:hover { + background-position: -224px -32px; +} +.jstree-default-dark-large .jstree-anchor > .jstree-undetermined { + background-position: -192px 0px; +} +.jstree-default-dark-large .jstree-anchor > .jstree-undetermined:hover { + background-position: -192px -32px; +} +.jstree-default-dark-large .jstree-checkbox-disabled { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default-dark-large > .jstree-striped { + background-size: auto 64px; +} +.jstree-default-dark-large.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); + background-position: 100% 1px; + background-repeat: repeat-y; +} +.jstree-default-dark-large.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-dark-large.jstree-rtl .jstree-open > .jstree-ocl { + background-position: -128px -32px; +} +.jstree-default-dark-large.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -96px -32px; +} +.jstree-default-dark-large.jstree-rtl .jstree-leaf > .jstree-ocl { + background-position: -64px -32px; +} +.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-node, +.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -32px -32px; +} +.jstree-default-dark-large.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: 0px -32px; +} +.jstree-default-dark-large .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; +} +.jstree-default-dark-large > .jstree-container-ul .jstree-loading > .jstree-ocl { + background: url("throbber.gif") center center no-repeat; +} +.jstree-default-dark-large .jstree-file { + background: url("32px.png") -96px -64px no-repeat; +} +.jstree-default-dark-large .jstree-folder { + background: url("32px.png") -256px 0px no-repeat; +} +.jstree-default-dark-large > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; +} +#jstree-dnd.jstree-default-dark-large { + line-height: 32px; + padding: 0 4px; +} +#jstree-dnd.jstree-default-dark-large .jstree-ok, +#jstree-dnd.jstree-default-dark-large .jstree-er { + background-image: url("32px.png"); + background-repeat: no-repeat; + background-color: transparent; +} +#jstree-dnd.jstree-default-dark-large i { + background: transparent; + width: 32px; + height: 32px; + line-height: 32px; +} +#jstree-dnd.jstree-default-dark-large .jstree-ok { + background-position: 0px -64px; +} +#jstree-dnd.jstree-default-dark-large .jstree-er { + background-position: -32px -64px; +} +.jstree-default-dark-large .jstree-ellipsis { + overflow: hidden; +} +.jstree-default-dark-large .jstree-ellipsis .jstree-anchor { + width: calc(100% - 37px); + text-overflow: ellipsis; + overflow: hidden; +} +.jstree-default-dark-large .jstree-ellipsis.jstree-no-icons .jstree-anchor { + width: calc(100% - 5px); +} +.jstree-default-dark-large.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg=="); +} +.jstree-default-dark-large.jstree-rtl .jstree-last { + background: transparent; +} +@media (max-width: 768px) { + #jstree-dnd.jstree-dnd-responsive { + line-height: 40px; + font-weight: bold; + font-size: 1.1em; + text-shadow: 1px 1px white; + } + #jstree-dnd.jstree-dnd-responsive > i { + background: transparent; + width: 40px; + height: 40px; + } + #jstree-dnd.jstree-dnd-responsive > .jstree-ok { + background-image: url("40px.png"); + background-position: 0 -200px; + background-size: 120px 240px; + } + #jstree-dnd.jstree-dnd-responsive > .jstree-er { + background-image: url("40px.png"); + background-position: -40px -200px; + background-size: 120px 240px; + } + #jstree-marker.jstree-dnd-responsive { + border-left-width: 10px; + border-top-width: 10px; + border-bottom-width: 10px; + margin-top: -10px; + } +} +@media (max-width: 768px) { + .jstree-default-dark-responsive { + /* + .jstree-open > .jstree-ocl, + .jstree-closed > .jstree-ocl { border-radius:20px; background-color:white; } + */ + } + .jstree-default-dark-responsive .jstree-icon { + background-image: url("40px.png"); + } + .jstree-default-dark-responsive .jstree-node, + .jstree-default-dark-responsive .jstree-leaf > .jstree-ocl { + background: transparent; + } + .jstree-default-dark-responsive .jstree-node { + min-height: 40px; + line-height: 40px; + margin-left: 40px; + min-width: 40px; + white-space: nowrap; + } + .jstree-default-dark-responsive .jstree-anchor { + line-height: 40px; + height: 40px; + } + .jstree-default-dark-responsive .jstree-icon, + .jstree-default-dark-responsive .jstree-icon:empty { + width: 40px; + height: 40px; + line-height: 40px; + } + .jstree-default-dark-responsive > .jstree-container-ul > .jstree-node { + margin-left: 0; + } + .jstree-default-dark-responsive.jstree-rtl .jstree-node { + margin-left: 0; + margin-right: 40px; + background: transparent; + } + .jstree-default-dark-responsive.jstree-rtl .jstree-container-ul > .jstree-node { + margin-right: 0; + } + .jstree-default-dark-responsive .jstree-ocl, + .jstree-default-dark-responsive .jstree-themeicon, + .jstree-default-dark-responsive .jstree-checkbox { + background-size: 120px 240px; + } + .jstree-default-dark-responsive .jstree-leaf > .jstree-ocl, + .jstree-default-dark-responsive.jstree-rtl .jstree-leaf > .jstree-ocl { + background: transparent; + } + .jstree-default-dark-responsive .jstree-open > .jstree-ocl { + background-position: 0 0px !important; + } + .jstree-default-dark-responsive .jstree-closed > .jstree-ocl { + background-position: 0 -40px !important; + } + .jstree-default-dark-responsive.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -40px 0px !important; + } + .jstree-default-dark-responsive .jstree-themeicon { + background-position: -40px -40px; + } + .jstree-default-dark-responsive .jstree-checkbox, + .jstree-default-dark-responsive .jstree-checkbox:hover { + background-position: -40px -80px; + } + .jstree-default-dark-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, + .jstree-default-dark-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, + .jstree-default-dark-responsive .jstree-checked > .jstree-checkbox, + .jstree-default-dark-responsive .jstree-checked > .jstree-checkbox:hover { + background-position: 0 -80px; + } + .jstree-default-dark-responsive .jstree-anchor > .jstree-undetermined, + .jstree-default-dark-responsive .jstree-anchor > .jstree-undetermined:hover { + background-position: 0 -120px; + } + .jstree-default-dark-responsive .jstree-anchor { + font-weight: bold; + font-size: 1.1em; + text-shadow: 1px 1px white; + } + .jstree-default-dark-responsive > .jstree-striped { + background: transparent; + } + .jstree-default-dark-responsive .jstree-wholerow { + border-top: 1px solid #666666; + border-bottom: 1px solid #000000; + background: #333333; + height: 40px; + } + .jstree-default-dark-responsive .jstree-wholerow-hovered { + background: #555555; + } + .jstree-default-dark-responsive .jstree-wholerow-clicked { + background: #5fa2db; + } + .jstree-default-dark-responsive .jstree-children .jstree-last > .jstree-wholerow { + box-shadow: inset 0 -6px 3px -5px #111111; + } + .jstree-default-dark-responsive .jstree-children .jstree-open > .jstree-wholerow { + box-shadow: inset 0 6px 3px -5px #111111; + border-top: 0; + } + .jstree-default-dark-responsive .jstree-children .jstree-open + .jstree-open { + box-shadow: none; + } + .jstree-default-dark-responsive .jstree-node, + .jstree-default-dark-responsive .jstree-icon, + .jstree-default-dark-responsive .jstree-node > .jstree-ocl, + .jstree-default-dark-responsive .jstree-themeicon, + .jstree-default-dark-responsive .jstree-checkbox { + background-image: url("40px.png"); + background-size: 120px 240px; + } + .jstree-default-dark-responsive .jstree-node { + background-position: -80px 0; + background-repeat: repeat-y; + } + .jstree-default-dark-responsive .jstree-last { + background: transparent; + } + .jstree-default-dark-responsive .jstree-leaf > .jstree-ocl { + background-position: -40px -120px; + } + .jstree-default-dark-responsive .jstree-last > .jstree-ocl { + background-position: -40px -160px; + } + .jstree-default-dark-responsive .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; + } + .jstree-default-dark-responsive .jstree-file { + background: url("40px.png") 0 -160px no-repeat; + background-size: 120px 240px; + } + .jstree-default-dark-responsive .jstree-folder { + background: url("40px.png") -40px -40px no-repeat; + background-size: 120px 240px; + } + .jstree-default-dark-responsive > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; + } +} +.jstree-default-dark { + background: #333; +} +.jstree-default-dark .jstree-anchor { + color: #999; + text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.5); +} +.jstree-default-dark .jstree-clicked, +.jstree-default-dark .jstree-checked { + color: white; +} +.jstree-default-dark .jstree-hovered { + color: white; +} +#jstree-marker.jstree-default-dark { + border-left-color: #999; + background: transparent; +} +.jstree-default-dark .jstree-anchor > .jstree-icon { + opacity: 0.75; +} +.jstree-default-dark .jstree-clicked > .jstree-icon, +.jstree-default-dark .jstree-hovered > .jstree-icon, +.jstree-default-dark .jstree-checked > .jstree-icon { + opacity: 1; +} +.jstree-default-dark.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); +} +.jstree-default-dark.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-dark-small.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg=="); +} +.jstree-default-dark-small.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-dark-large.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAACZmZl+9SADAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg=="); +} +.jstree-default-dark-large.jstree-rtl .jstree-last { + background: transparent; +} diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/throbber.gif b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/throbber.gif new file mode 100644 index 000000000000..cd75035ce808 Binary files /dev/null and b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default-dark/throbber.gif differ diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/32px.png b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/32px.png new file mode 100644 index 000000000000..153271524817 Binary files /dev/null and b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/32px.png differ diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/40px.png b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/40px.png new file mode 100644 index 000000000000..1959347aea04 Binary files /dev/null and b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/40px.png differ diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/style.css b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/style.css new file mode 100644 index 000000000000..674f87cc0f86 --- /dev/null +++ b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/style.css @@ -0,0 +1,1108 @@ +/* jsTree default theme */ +.jstree-node, +.jstree-children, +.jstree-container-ul { + display: block; + margin: 0; + padding: 0; + list-style-type: none; + list-style-image: none; +} +.jstree-node { + white-space: nowrap; +} +.jstree-anchor { + display: inline-block; + color: black; + white-space: nowrap; + padding: 0 4px 0 1px; + margin: 0; + vertical-align: top; +} +.jstree-anchor:focus { + outline: 0; +} +.jstree-anchor, +.jstree-anchor:link, +.jstree-anchor:visited, +.jstree-anchor:hover, +.jstree-anchor:active { + text-decoration: none; + color: inherit; +} +.jstree-icon { + display: inline-block; + text-decoration: none; + margin: 0; + padding: 0; + vertical-align: top; + text-align: center; +} +.jstree-icon:empty { + display: inline-block; + text-decoration: none; + margin: 0; + padding: 0; + vertical-align: top; + text-align: center; +} +.jstree-ocl { + cursor: pointer; +} +.jstree-leaf > .jstree-ocl { + cursor: default; +} +.jstree .jstree-open > .jstree-children { + display: block; +} +.jstree .jstree-closed > .jstree-children, +.jstree .jstree-leaf > .jstree-children { + display: none; +} +.jstree-anchor > .jstree-themeicon { + margin-right: 2px; +} +.jstree-no-icons .jstree-themeicon, +.jstree-anchor > .jstree-themeicon-hidden { + display: none; +} +.jstree-hidden, +.jstree-node.jstree-hidden { + display: none; +} +.jstree-rtl .jstree-anchor { + padding: 0 1px 0 4px; +} +.jstree-rtl .jstree-anchor > .jstree-themeicon { + margin-left: 2px; + margin-right: 0; +} +.jstree-rtl .jstree-node { + margin-left: 0; +} +.jstree-rtl .jstree-container-ul > .jstree-node { + margin-right: 0; +} +.jstree-wholerow-ul { + position: relative; + display: inline-block; + min-width: 100%; +} +.jstree-wholerow-ul .jstree-leaf > .jstree-ocl { + cursor: pointer; +} +.jstree-wholerow-ul .jstree-anchor, +.jstree-wholerow-ul .jstree-icon { + position: relative; +} +.jstree-wholerow-ul .jstree-wholerow { + width: 100%; + cursor: pointer; + position: absolute; + left: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.jstree-contextmenu .jstree-anchor { + -webkit-user-select: none; + /* disable selection/Copy of UIWebView */ + -webkit-touch-callout: none; + /* disable the IOS popup when long-press on a link */ +} +.vakata-context { + display: none; +} +.vakata-context, +.vakata-context ul { + margin: 0; + padding: 2px; + position: absolute; + background: #f5f5f5; + border: 1px solid #979797; + box-shadow: 2px 2px 2px #999999; +} +.vakata-context ul { + list-style: none; + left: 100%; + margin-top: -2.7em; + margin-left: -4px; +} +.vakata-context .vakata-context-right ul { + left: auto; + right: 100%; + margin-left: auto; + margin-right: -4px; +} +.vakata-context li { + list-style: none; +} +.vakata-context li > a { + display: block; + padding: 0 2em 0 2em; + text-decoration: none; + width: auto; + color: black; + white-space: nowrap; + line-height: 2.4em; + text-shadow: 1px 1px 0 white; + border-radius: 1px; +} +.vakata-context li > a:hover { + position: relative; + background-color: #e8eff7; + box-shadow: 0 0 2px #0a6aa1; +} +.vakata-context li > a.vakata-context-parent { + background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw=="); + background-position: right center; + background-repeat: no-repeat; +} +.vakata-context li > a:focus { + outline: 0; +} +.vakata-context .vakata-context-hover > a { + position: relative; + background-color: #e8eff7; + box-shadow: 0 0 2px #0a6aa1; +} +.vakata-context .vakata-context-separator > a, +.vakata-context .vakata-context-separator > a:hover { + background: white; + border: 0; + border-top: 1px solid #e2e3e3; + height: 1px; + min-height: 1px; + max-height: 1px; + padding: 0; + margin: 0 0 0 2.4em; + border-left: 1px solid #e0e0e0; + text-shadow: 0 0 0 transparent; + box-shadow: 0 0 0 transparent; + border-radius: 0; +} +.vakata-context .vakata-contextmenu-disabled a, +.vakata-context .vakata-contextmenu-disabled a:hover { + color: silver; + background-color: transparent; + border: 0; + box-shadow: 0 0 0; +} +.vakata-context li > a > i { + text-decoration: none; + display: inline-block; + width: 2.4em; + height: 2.4em; + background: transparent; + margin: 0 0 0 -2em; + vertical-align: top; + text-align: center; + line-height: 2.4em; +} +.vakata-context li > a > i:empty { + width: 2.4em; + line-height: 2.4em; +} +.vakata-context li > a .vakata-contextmenu-sep { + display: inline-block; + width: 1px; + height: 2.4em; + background: white; + margin: 0 0.5em 0 0; + border-left: 1px solid #e2e3e3; +} +.vakata-context .vakata-contextmenu-shortcut { + font-size: 0.8em; + color: silver; + opacity: 0.5; + display: none; +} +.vakata-context-rtl ul { + left: auto; + right: 100%; + margin-left: auto; + margin-right: -4px; +} +.vakata-context-rtl li > a.vakata-context-parent { + background-image: url("data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7"); + background-position: left center; + background-repeat: no-repeat; +} +.vakata-context-rtl .vakata-context-separator > a { + margin: 0 2.4em 0 0; + border-left: 0; + border-right: 1px solid #e2e3e3; +} +.vakata-context-rtl .vakata-context-left ul { + right: auto; + left: 100%; + margin-left: -4px; + margin-right: auto; +} +.vakata-context-rtl li > a > i { + margin: 0 -2em 0 0; +} +.vakata-context-rtl li > a .vakata-contextmenu-sep { + margin: 0 0 0 0.5em; + border-left-color: white; + background: #e2e3e3; +} +#jstree-marker { + position: absolute; + top: 0; + left: 0; + margin: -5px 0 0 0; + padding: 0; + border-right: 0; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid; + width: 0; + height: 0; + font-size: 0; + line-height: 0; +} +#jstree-dnd { + line-height: 16px; + margin: 0; + padding: 4px; +} +#jstree-dnd .jstree-icon, +#jstree-dnd .jstree-copy { + display: inline-block; + text-decoration: none; + margin: 0 2px 0 0; + padding: 0; + width: 16px; + height: 16px; +} +#jstree-dnd .jstree-ok { + background: green; +} +#jstree-dnd .jstree-er { + background: red; +} +#jstree-dnd .jstree-copy { + margin: 0 2px 0 2px; +} +.jstree-default .jstree-node, +.jstree-default .jstree-icon { + background-repeat: no-repeat; + background-color: transparent; +} +.jstree-default .jstree-anchor, +.jstree-default .jstree-animated, +.jstree-default .jstree-wholerow { + transition: background-color 0.15s, box-shadow 0.15s; +} +.jstree-default .jstree-hovered { + background: #e7f4f9; + border-radius: 2px; + box-shadow: inset 0 0 1px #cccccc; +} +.jstree-default .jstree-context { + background: #e7f4f9; + border-radius: 2px; + box-shadow: inset 0 0 1px #cccccc; +} +.jstree-default .jstree-clicked { + background: #beebff; + border-radius: 2px; + box-shadow: inset 0 0 1px #999999; +} +.jstree-default .jstree-no-icons .jstree-anchor > .jstree-themeicon { + display: none; +} +.jstree-default .jstree-disabled { + background: transparent; + color: #666666; +} +.jstree-default .jstree-disabled.jstree-hovered { + background: transparent; + box-shadow: none; +} +.jstree-default .jstree-disabled.jstree-clicked { + background: #efefef; +} +.jstree-default .jstree-disabled > .jstree-icon { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default .jstree-search { + font-style: italic; + color: #8b0000; + font-weight: bold; +} +.jstree-default .jstree-no-checkboxes .jstree-checkbox { + display: none !important; +} +.jstree-default.jstree-checkbox-no-clicked .jstree-clicked { + background: transparent; + box-shadow: none; +} +.jstree-default.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered { + background: #e7f4f9; +} +.jstree-default.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked { + background: transparent; +} +.jstree-default.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered { + background: #e7f4f9; +} +.jstree-default > .jstree-striped { + min-width: 100%; + display: inline-block; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==") left top repeat; +} +.jstree-default > .jstree-wholerow-ul .jstree-hovered, +.jstree-default > .jstree-wholerow-ul .jstree-clicked { + background: transparent; + box-shadow: none; + border-radius: 0; +} +.jstree-default .jstree-wholerow { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.jstree-default .jstree-wholerow-hovered { + background: #e7f4f9; +} +.jstree-default .jstree-wholerow-clicked { + background: #beebff; + background: -webkit-linear-gradient(top, #beebff 0%, #a8e4ff 100%); + background: linear-gradient(to bottom, #beebff 0%, #a8e4ff 100%); +} +.jstree-default .jstree-node { + min-height: 24px; + line-height: 24px; + margin-left: 24px; + min-width: 24px; +} +.jstree-default .jstree-anchor { + line-height: 24px; + height: 24px; +} +.jstree-default .jstree-icon { + width: 24px; + height: 24px; + line-height: 24px; +} +.jstree-default .jstree-icon:empty { + width: 24px; + height: 24px; + line-height: 24px; +} +.jstree-default.jstree-rtl .jstree-node { + margin-right: 24px; +} +.jstree-default .jstree-wholerow { + height: 24px; +} +.jstree-default .jstree-node, +.jstree-default .jstree-icon { + background-image: url("32px.png"); +} +.jstree-default .jstree-node { + background-position: -292px -4px; + background-repeat: repeat-y; +} +.jstree-default .jstree-last { + background: transparent; +} +.jstree-default .jstree-open > .jstree-ocl { + background-position: -132px -4px; +} +.jstree-default .jstree-closed > .jstree-ocl { + background-position: -100px -4px; +} +.jstree-default .jstree-leaf > .jstree-ocl { + background-position: -68px -4px; +} +.jstree-default .jstree-themeicon { + background-position: -260px -4px; +} +.jstree-default > .jstree-no-dots .jstree-node, +.jstree-default > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -36px -4px; +} +.jstree-default > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -4px -4px; +} +.jstree-default .jstree-disabled { + background: transparent; +} +.jstree-default .jstree-disabled.jstree-hovered { + background: transparent; +} +.jstree-default .jstree-disabled.jstree-clicked { + background: #efefef; +} +.jstree-default .jstree-checkbox { + background-position: -164px -4px; +} +.jstree-default .jstree-checkbox:hover { + background-position: -164px -36px; +} +.jstree-default.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, +.jstree-default .jstree-checked > .jstree-checkbox { + background-position: -228px -4px; +} +.jstree-default.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, +.jstree-default .jstree-checked > .jstree-checkbox:hover { + background-position: -228px -36px; +} +.jstree-default .jstree-anchor > .jstree-undetermined { + background-position: -196px -4px; +} +.jstree-default .jstree-anchor > .jstree-undetermined:hover { + background-position: -196px -36px; +} +.jstree-default .jstree-checkbox-disabled { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default > .jstree-striped { + background-size: auto 48px; +} +.jstree-default.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); + background-position: 100% 1px; + background-repeat: repeat-y; +} +.jstree-default.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default.jstree-rtl .jstree-open > .jstree-ocl { + background-position: -132px -36px; +} +.jstree-default.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -100px -36px; +} +.jstree-default.jstree-rtl .jstree-leaf > .jstree-ocl { + background-position: -68px -36px; +} +.jstree-default.jstree-rtl > .jstree-no-dots .jstree-node, +.jstree-default.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -36px -36px; +} +.jstree-default.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -4px -36px; +} +.jstree-default .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; +} +.jstree-default > .jstree-container-ul .jstree-loading > .jstree-ocl { + background: url("throbber.gif") center center no-repeat; +} +.jstree-default .jstree-file { + background: url("32px.png") -100px -68px no-repeat; +} +.jstree-default .jstree-folder { + background: url("32px.png") -260px -4px no-repeat; +} +.jstree-default > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; +} +#jstree-dnd.jstree-default { + line-height: 24px; + padding: 0 4px; +} +#jstree-dnd.jstree-default .jstree-ok, +#jstree-dnd.jstree-default .jstree-er { + background-image: url("32px.png"); + background-repeat: no-repeat; + background-color: transparent; +} +#jstree-dnd.jstree-default i { + background: transparent; + width: 24px; + height: 24px; + line-height: 24px; +} +#jstree-dnd.jstree-default .jstree-ok { + background-position: -4px -68px; +} +#jstree-dnd.jstree-default .jstree-er { + background-position: -36px -68px; +} +.jstree-default .jstree-ellipsis { + overflow: hidden; +} +.jstree-default .jstree-ellipsis .jstree-anchor { + width: calc(100% - 29px); + text-overflow: ellipsis; + overflow: hidden; +} +.jstree-default .jstree-ellipsis.jstree-no-icons .jstree-anchor { + width: calc(100% - 5px); +} +.jstree-default.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); +} +.jstree-default.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-small .jstree-node { + min-height: 18px; + line-height: 18px; + margin-left: 18px; + min-width: 18px; +} +.jstree-default-small .jstree-anchor { + line-height: 18px; + height: 18px; +} +.jstree-default-small .jstree-icon { + width: 18px; + height: 18px; + line-height: 18px; +} +.jstree-default-small .jstree-icon:empty { + width: 18px; + height: 18px; + line-height: 18px; +} +.jstree-default-small.jstree-rtl .jstree-node { + margin-right: 18px; +} +.jstree-default-small .jstree-wholerow { + height: 18px; +} +.jstree-default-small .jstree-node, +.jstree-default-small .jstree-icon { + background-image: url("32px.png"); +} +.jstree-default-small .jstree-node { + background-position: -295px -7px; + background-repeat: repeat-y; +} +.jstree-default-small .jstree-last { + background: transparent; +} +.jstree-default-small .jstree-open > .jstree-ocl { + background-position: -135px -7px; +} +.jstree-default-small .jstree-closed > .jstree-ocl { + background-position: -103px -7px; +} +.jstree-default-small .jstree-leaf > .jstree-ocl { + background-position: -71px -7px; +} +.jstree-default-small .jstree-themeicon { + background-position: -263px -7px; +} +.jstree-default-small > .jstree-no-dots .jstree-node, +.jstree-default-small > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-small > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -39px -7px; +} +.jstree-default-small > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -7px -7px; +} +.jstree-default-small .jstree-disabled { + background: transparent; +} +.jstree-default-small .jstree-disabled.jstree-hovered { + background: transparent; +} +.jstree-default-small .jstree-disabled.jstree-clicked { + background: #efefef; +} +.jstree-default-small .jstree-checkbox { + background-position: -167px -7px; +} +.jstree-default-small .jstree-checkbox:hover { + background-position: -167px -39px; +} +.jstree-default-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, +.jstree-default-small .jstree-checked > .jstree-checkbox { + background-position: -231px -7px; +} +.jstree-default-small.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, +.jstree-default-small .jstree-checked > .jstree-checkbox:hover { + background-position: -231px -39px; +} +.jstree-default-small .jstree-anchor > .jstree-undetermined { + background-position: -199px -7px; +} +.jstree-default-small .jstree-anchor > .jstree-undetermined:hover { + background-position: -199px -39px; +} +.jstree-default-small .jstree-checkbox-disabled { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default-small > .jstree-striped { + background-size: auto 36px; +} +.jstree-default-small.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); + background-position: 100% 1px; + background-repeat: repeat-y; +} +.jstree-default-small.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-small.jstree-rtl .jstree-open > .jstree-ocl { + background-position: -135px -39px; +} +.jstree-default-small.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -103px -39px; +} +.jstree-default-small.jstree-rtl .jstree-leaf > .jstree-ocl { + background-position: -71px -39px; +} +.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-node, +.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -39px -39px; +} +.jstree-default-small.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: -7px -39px; +} +.jstree-default-small .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; +} +.jstree-default-small > .jstree-container-ul .jstree-loading > .jstree-ocl { + background: url("throbber.gif") center center no-repeat; +} +.jstree-default-small .jstree-file { + background: url("32px.png") -103px -71px no-repeat; +} +.jstree-default-small .jstree-folder { + background: url("32px.png") -263px -7px no-repeat; +} +.jstree-default-small > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; +} +#jstree-dnd.jstree-default-small { + line-height: 18px; + padding: 0 4px; +} +#jstree-dnd.jstree-default-small .jstree-ok, +#jstree-dnd.jstree-default-small .jstree-er { + background-image: url("32px.png"); + background-repeat: no-repeat; + background-color: transparent; +} +#jstree-dnd.jstree-default-small i { + background: transparent; + width: 18px; + height: 18px; + line-height: 18px; +} +#jstree-dnd.jstree-default-small .jstree-ok { + background-position: -7px -71px; +} +#jstree-dnd.jstree-default-small .jstree-er { + background-position: -39px -71px; +} +.jstree-default-small .jstree-ellipsis { + overflow: hidden; +} +.jstree-default-small .jstree-ellipsis .jstree-anchor { + width: calc(100% - 23px); + text-overflow: ellipsis; + overflow: hidden; +} +.jstree-default-small .jstree-ellipsis.jstree-no-icons .jstree-anchor { + width: calc(100% - 5px); +} +.jstree-default-small.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg=="); +} +.jstree-default-small.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-large .jstree-node { + min-height: 32px; + line-height: 32px; + margin-left: 32px; + min-width: 32px; +} +.jstree-default-large .jstree-anchor { + line-height: 32px; + height: 32px; +} +.jstree-default-large .jstree-icon { + width: 32px; + height: 32px; + line-height: 32px; +} +.jstree-default-large .jstree-icon:empty { + width: 32px; + height: 32px; + line-height: 32px; +} +.jstree-default-large.jstree-rtl .jstree-node { + margin-right: 32px; +} +.jstree-default-large .jstree-wholerow { + height: 32px; +} +.jstree-default-large .jstree-node, +.jstree-default-large .jstree-icon { + background-image: url("32px.png"); +} +.jstree-default-large .jstree-node { + background-position: -288px 0px; + background-repeat: repeat-y; +} +.jstree-default-large .jstree-last { + background: transparent; +} +.jstree-default-large .jstree-open > .jstree-ocl { + background-position: -128px 0px; +} +.jstree-default-large .jstree-closed > .jstree-ocl { + background-position: -96px 0px; +} +.jstree-default-large .jstree-leaf > .jstree-ocl { + background-position: -64px 0px; +} +.jstree-default-large .jstree-themeicon { + background-position: -256px 0px; +} +.jstree-default-large > .jstree-no-dots .jstree-node, +.jstree-default-large > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-large > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -32px 0px; +} +.jstree-default-large > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: 0px 0px; +} +.jstree-default-large .jstree-disabled { + background: transparent; +} +.jstree-default-large .jstree-disabled.jstree-hovered { + background: transparent; +} +.jstree-default-large .jstree-disabled.jstree-clicked { + background: #efefef; +} +.jstree-default-large .jstree-checkbox { + background-position: -160px 0px; +} +.jstree-default-large .jstree-checkbox:hover { + background-position: -160px -32px; +} +.jstree-default-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, +.jstree-default-large .jstree-checked > .jstree-checkbox { + background-position: -224px 0px; +} +.jstree-default-large.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, +.jstree-default-large .jstree-checked > .jstree-checkbox:hover { + background-position: -224px -32px; +} +.jstree-default-large .jstree-anchor > .jstree-undetermined { + background-position: -192px 0px; +} +.jstree-default-large .jstree-anchor > .jstree-undetermined:hover { + background-position: -192px -32px; +} +.jstree-default-large .jstree-checkbox-disabled { + opacity: 0.8; + filter: url("data:image/svg+xml;utf8,#jstree-grayscale"); + /* Firefox 10+ */ + filter: gray; + /* IE6-9 */ + -webkit-filter: grayscale(100%); + /* Chrome 19+ & Safari 6+ */ +} +.jstree-default-large > .jstree-striped { + background-size: auto 64px; +} +.jstree-default-large.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg=="); + background-position: 100% 1px; + background-repeat: repeat-y; +} +.jstree-default-large.jstree-rtl .jstree-last { + background: transparent; +} +.jstree-default-large.jstree-rtl .jstree-open > .jstree-ocl { + background-position: -128px -32px; +} +.jstree-default-large.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -96px -32px; +} +.jstree-default-large.jstree-rtl .jstree-leaf > .jstree-ocl { + background-position: -64px -32px; +} +.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-node, +.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-leaf > .jstree-ocl { + background: transparent; +} +.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-open > .jstree-ocl { + background-position: -32px -32px; +} +.jstree-default-large.jstree-rtl > .jstree-no-dots .jstree-closed > .jstree-ocl { + background-position: 0px -32px; +} +.jstree-default-large .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; +} +.jstree-default-large > .jstree-container-ul .jstree-loading > .jstree-ocl { + background: url("throbber.gif") center center no-repeat; +} +.jstree-default-large .jstree-file { + background: url("32px.png") -96px -64px no-repeat; +} +.jstree-default-large .jstree-folder { + background: url("32px.png") -256px 0px no-repeat; +} +.jstree-default-large > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; +} +#jstree-dnd.jstree-default-large { + line-height: 32px; + padding: 0 4px; +} +#jstree-dnd.jstree-default-large .jstree-ok, +#jstree-dnd.jstree-default-large .jstree-er { + background-image: url("32px.png"); + background-repeat: no-repeat; + background-color: transparent; +} +#jstree-dnd.jstree-default-large i { + background: transparent; + width: 32px; + height: 32px; + line-height: 32px; +} +#jstree-dnd.jstree-default-large .jstree-ok { + background-position: 0px -64px; +} +#jstree-dnd.jstree-default-large .jstree-er { + background-position: -32px -64px; +} +.jstree-default-large .jstree-ellipsis { + overflow: hidden; +} +.jstree-default-large .jstree-ellipsis .jstree-anchor { + width: calc(100% - 37px); + text-overflow: ellipsis; + overflow: hidden; +} +.jstree-default-large .jstree-ellipsis.jstree-no-icons .jstree-anchor { + width: calc(100% - 5px); +} +.jstree-default-large.jstree-rtl .jstree-node { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg=="); +} +.jstree-default-large.jstree-rtl .jstree-last { + background: transparent; +} +@media (max-width: 768px) { + #jstree-dnd.jstree-dnd-responsive { + line-height: 40px; + font-weight: bold; + font-size: 1.1em; + text-shadow: 1px 1px white; + } + #jstree-dnd.jstree-dnd-responsive > i { + background: transparent; + width: 40px; + height: 40px; + } + #jstree-dnd.jstree-dnd-responsive > .jstree-ok { + background-image: url("40px.png"); + background-position: 0 -200px; + background-size: 120px 240px; + } + #jstree-dnd.jstree-dnd-responsive > .jstree-er { + background-image: url("40px.png"); + background-position: -40px -200px; + background-size: 120px 240px; + } + #jstree-marker.jstree-dnd-responsive { + border-left-width: 10px; + border-top-width: 10px; + border-bottom-width: 10px; + margin-top: -10px; + } +} +@media (max-width: 768px) { + .jstree-default-responsive { + /* + .jstree-open > .jstree-ocl, + .jstree-closed > .jstree-ocl { border-radius:20px; background-color:white; } + */ + } + .jstree-default-responsive .jstree-icon { + background-image: url("40px.png"); + } + .jstree-default-responsive .jstree-node, + .jstree-default-responsive .jstree-leaf > .jstree-ocl { + background: transparent; + } + .jstree-default-responsive .jstree-node { + min-height: 40px; + line-height: 40px; + margin-left: 40px; + min-width: 40px; + white-space: nowrap; + } + .jstree-default-responsive .jstree-anchor { + line-height: 40px; + height: 40px; + } + .jstree-default-responsive .jstree-icon, + .jstree-default-responsive .jstree-icon:empty { + width: 40px; + height: 40px; + line-height: 40px; + } + .jstree-default-responsive > .jstree-container-ul > .jstree-node { + margin-left: 0; + } + .jstree-default-responsive.jstree-rtl .jstree-node { + margin-left: 0; + margin-right: 40px; + background: transparent; + } + .jstree-default-responsive.jstree-rtl .jstree-container-ul > .jstree-node { + margin-right: 0; + } + .jstree-default-responsive .jstree-ocl, + .jstree-default-responsive .jstree-themeicon, + .jstree-default-responsive .jstree-checkbox { + background-size: 120px 240px; + } + .jstree-default-responsive .jstree-leaf > .jstree-ocl, + .jstree-default-responsive.jstree-rtl .jstree-leaf > .jstree-ocl { + background: transparent; + } + .jstree-default-responsive .jstree-open > .jstree-ocl { + background-position: 0 0px !important; + } + .jstree-default-responsive .jstree-closed > .jstree-ocl { + background-position: 0 -40px !important; + } + .jstree-default-responsive.jstree-rtl .jstree-closed > .jstree-ocl { + background-position: -40px 0px !important; + } + .jstree-default-responsive .jstree-themeicon { + background-position: -40px -40px; + } + .jstree-default-responsive .jstree-checkbox, + .jstree-default-responsive .jstree-checkbox:hover { + background-position: -40px -80px; + } + .jstree-default-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox, + .jstree-default-responsive.jstree-checkbox-selection .jstree-clicked > .jstree-checkbox:hover, + .jstree-default-responsive .jstree-checked > .jstree-checkbox, + .jstree-default-responsive .jstree-checked > .jstree-checkbox:hover { + background-position: 0 -80px; + } + .jstree-default-responsive .jstree-anchor > .jstree-undetermined, + .jstree-default-responsive .jstree-anchor > .jstree-undetermined:hover { + background-position: 0 -120px; + } + .jstree-default-responsive .jstree-anchor { + font-weight: bold; + font-size: 1.1em; + text-shadow: 1px 1px white; + } + .jstree-default-responsive > .jstree-striped { + background: transparent; + } + .jstree-default-responsive .jstree-wholerow { + border-top: 1px solid rgba(255, 255, 255, 0.7); + border-bottom: 1px solid rgba(64, 64, 64, 0.2); + background: #ebebeb; + height: 40px; + } + .jstree-default-responsive .jstree-wholerow-hovered { + background: #e7f4f9; + } + .jstree-default-responsive .jstree-wholerow-clicked { + background: #beebff; + } + .jstree-default-responsive .jstree-children .jstree-last > .jstree-wholerow { + box-shadow: inset 0 -6px 3px -5px #666666; + } + .jstree-default-responsive .jstree-children .jstree-open > .jstree-wholerow { + box-shadow: inset 0 6px 3px -5px #666666; + border-top: 0; + } + .jstree-default-responsive .jstree-children .jstree-open + .jstree-open { + box-shadow: none; + } + .jstree-default-responsive .jstree-node, + .jstree-default-responsive .jstree-icon, + .jstree-default-responsive .jstree-node > .jstree-ocl, + .jstree-default-responsive .jstree-themeicon, + .jstree-default-responsive .jstree-checkbox { + background-image: url("40px.png"); + background-size: 120px 240px; + } + .jstree-default-responsive .jstree-node { + background-position: -80px 0; + background-repeat: repeat-y; + } + .jstree-default-responsive .jstree-last { + background: transparent; + } + .jstree-default-responsive .jstree-leaf > .jstree-ocl { + background-position: -40px -120px; + } + .jstree-default-responsive .jstree-last > .jstree-ocl { + background-position: -40px -160px; + } + .jstree-default-responsive .jstree-themeicon-custom { + background-color: transparent; + background-image: none; + background-position: 0 0; + } + .jstree-default-responsive .jstree-file { + background: url("40px.png") 0 -160px no-repeat; + background-size: 120px 240px; + } + .jstree-default-responsive .jstree-folder { + background: url("40px.png") -40px -40px no-repeat; + background-size: 120px 240px; + } + .jstree-default-responsive > .jstree-container-ul > .jstree-node { + margin-left: 0; + margin-right: 0; + } +} diff --git a/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/throbber.gif b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/throbber.gif new file mode 100644 index 000000000000..1b5b2fde42f8 Binary files /dev/null and b/cvat/apps/dashboard/static/dashboard/js/3rdparty/jstree/themes/default/throbber.gif differ diff --git a/cvat/apps/dashboard/static/dashboard/js/dashboard.js b/cvat/apps/dashboard/static/dashboard/js/dashboard.js new file mode 100644 index 000000000000..28dab1f10822 --- /dev/null +++ b/cvat/apps/dashboard/static/dashboard/js/dashboard.js @@ -0,0 +1,546 @@ +"use strict"; + +/* Dashboard entrypoint */ +window.cvat = window.cvat || {}; +window.cvat.dashboard = window.cvat.dashboard || {}; +window.cvat.dashboard.uiCallbacks = window.cvat.dashboard.uiCallbacks || []; + +window.cvat.dashboard.uiCallbacks.push(function(elements) { + elements.each(function(idx) { + let elem = $(elements[idx]); + let taskID = +elem.attr('id').split('_')[1]; + let taskName = $.trim($( elem.find('label.dashboardTaskNameLabel')[0] ).text()); + let buttonsUI = elem.find('div.dashboardButtonsUI')[0]; + + let dumpButton = $( $(buttonsUI).find('button.dashboardDumpAnnotation')[0] ); + let uploadButton = $( $(buttonsUI).find('button.dashboardUploadAnnotation')[0] ); + let updateButton = $( $(buttonsUI).find('button.dashboardUpdateTask')[0] ); + let deleteButton = $( $(buttonsUI).find('button.dashboardDeleteTask')[0] ); + + let bugTrackerButton = $(buttonsUI).find('.dashboardOpenTrackerButton'); + if (bugTrackerButton.length) { + bugTrackerButton = $(bugTrackerButton[0]); + bugTrackerButton.on('click', function() { + window.open($(buttonsUI).find('a.dashboardBugTrackerLink').attr('href')); + }); + } + + dumpButton.on('click', function() { + window.cvat.dashboard.taskID = taskID; + window.cvat.dashboard.taskName = taskName; + dumpAnnotationRequest(dumpButton, taskID, taskName); + }); + + uploadButton.on('click', function() { + window.cvat.dashboard.taskID = taskID; + window.cvat.dashboard.taskName = taskName; + confirm('The current annotation will be lost. Are you sure?', uploadAnnotationRequest); + }); + + updateButton.on('click', function() { + window.cvat.dashboard.taskID = taskID; + window.cvat.dashboard.taskName = taskName; + $('#dashboardUpdateModal').removeClass('hidden'); + $('#dashboardUpdateModal')[0].loadCurrentLabels(); + }); + + deleteButton.on('click', function() { + window.cvat.dashboard.taskID = taskID; + window.cvat.dashboard.taskName = taskName; + RemoveTaskRequest(); + }); + }); +}); + +document.addEventListener("DOMContentLoaded", buildDashboard); + + +function buildDashboard() { + /* Setup static content */ + setupTaskCreator(); + setupTaskUpdater(); + setupSearch(); + + $(window).on('click', function(e) { + let target = $(e.target); + if ( target.hasClass('modal') ) { + target.addClass('hidden'); + } + }); + + /* Setup task UIs */ + for (let callback of window.cvat.dashboard.uiCallbacks) { + callback( $('.dashboardTaskUI') ); + } + + $('#loadingOverlay').remove(); +} + + +function setupTaskCreator() { + let dashboardCreateTaskButton = $('#dashboardCreateTaskButton'); + let createModal = $('#dashboardCreateModal'); + let nameInput = $('#dashboardNameInput'); + let labelsInput = $('#dashboardLabelsInput'); + let bugTrackerInput = $('#dashboardBugTrackerInput'); + let localSourceRadio = $('#dashboardLocalSource'); + let shareSourceRadio = $('#dashboardShareSource'); + let selectFiles = $('#dashboardSelectFiles'); + let filesLabel = $('#dashboardFilesLabel'); + let localFileSelector = $('#dashboardLocalFileSelector'); + let shareFileSelector = $('#dashboardShareBrowseModal'); + let shareBrowseTree = $('#dashboardShareBrowser'); + let cancelBrowseServer = $('#dashboardCancelBrowseServer'); + let submitBrowseServer = $('#dashboardSubmitBrowseServer'); + let flipImagesBox = $('#dashboardFlipImages'); + let segmentSizeInput = $('#dashboardSegmentSize'); + let customSegmentSize = $('#dashboardCustomSegment'); + let overlapSizeInput = $('#dashboardOverlap'); + let customOverlapSize = $('#dashboardCustomOverlap'); + let imageQualityInput = $('#dashboardImageQuality'); + let customCompressQuality = $('#dashboardCustomQuality'); + + let taskMessage = $('#dashboardCreateTaskMessage'); + let submitCreate = $('#dashboardSubmitTask'); + let cancelCreate = $('#dashboardCancelTask'); + + let name = nameInput.prop('value'); + let labels = labelsInput.prop('value'); + let bugTrackerLink = bugTrackerInput.prop('value'); + let source = 'local'; + let flipImages = false; + let segmentSize = 5000; + let overlapSize = 0; + let compressQuality = 50; + let files = []; + + dashboardCreateTaskButton.on('click', function() { + $('#dashboardCreateModal').removeClass('hidden'); + }); + + nameInput.on('change', (e) => {name = e.target.value;}); + bugTrackerInput.on('change', (e) => {bugTrackerLink = e.target.value;}); + labelsInput.on('change', (e) => {labels = e.target.value;}); + + localSourceRadio.on('click', function() { + if (source == 'local') return; + source = 'local'; + files = []; + updateSelectedFiles(); + }); + + shareSourceRadio.on('click', function() { + if (source == 'share') return; + source = 'share'; + files = []; + updateSelectedFiles(); + }); + + selectFiles.on('click', function() { + if (source == 'local') { + localFileSelector.click(); + } + else { + shareBrowseTree.jstree("refresh"); + shareFileSelector.removeClass('hidden'); + shareBrowseTree.jstree({ + core: { + data: { + url: 'get_share_nodes', + data: (node) => { return {'id' : node.id}; } + } + }, + plugins: ['checkbox', 'sort'], + }); + } + }); + + localFileSelector.on('change', function(e) { + files = e.target.files; + updateSelectedFiles(); + }); + + + cancelBrowseServer.on('click', () => shareFileSelector.addClass('hidden')); + submitBrowseServer.on('click', function() { + files = shareBrowseTree.jstree(true).get_selected(); + cancelBrowseServer.click(); + updateSelectedFiles(); + }); + + flipImagesBox.on('click', (e) => {flipImages = e.target.checked;}); + customSegmentSize.on('change', (e) => segmentSizeInput.prop('disabled', !e.target.checked)); + customOverlapSize.on('change', (e) => overlapSizeInput.prop('disabled', !e.target.checked)); + customCompressQuality.on('change', (e) => imageQualityInput.prop('disabled', !e.target.checked)); + + segmentSizeInput.on('change', function() { + let value = Math.clamp( + +segmentSizeInput.prop('value'), + +segmentSizeInput.prop('min'), + +segmentSizeInput.prop('max') + ); + + segmentSizeInput.prop('value', value); + segmentSize = value; + }); + + overlapSizeInput.on('change', function() { + let value = Math.clamp( + +overlapSizeInput.prop('value'), + +overlapSizeInput.prop('min'), + +overlapSizeInput.prop('max') + ); + + overlapSizeInput.prop('value', value); + overlapSize = value; + }); + + imageQualityInput.on('change', function() { + let value = Math.clamp( + +imageQualityInput.prop('value'), + +imageQualityInput.prop('min'), + +imageQualityInput.prop('max') + ); + + imageQualityInput.prop('value', value); + compressQuality = value; + }); + + submitCreate.on('click', function() { + if (!validateName(name)) { + taskMessage.css('color', 'red'); + taskMessage.text('Invalid task name'); + return; + } + + if (!validateLabels(labels)) { + taskMessage.css('color', 'red'); + taskMessage.text('Invalid task labels'); + return; + } + + if (!validateSegmentSize(segmentSize)) { + taskMessage.css('color', 'red'); + taskMessage.text('Segment size out of range'); + return; + } + + if (!validateOverlapSize(overlapSize, segmentSize)) { + taskMessage.css('color', 'red'); + taskMessage.text('Overlap size must be positive and not more then segment size'); + return; + } + + if (files.length <= 0) { + taskMessage.css('color', 'red'); + taskMessage.text('Need specify files for task'); + return; + } + else if (files.length > maxUploadCount && source == 'local') { + taskMessage.css('color', 'red'); + taskMessage.text('Too many files. Please use share functionality'); + return; + } + else if (source == 'local') { + let commonSize = 0; + for (let file of files) { + commonSize += file.size; + } + if (commonSize > maxUploadSize) { + taskMessage.css('color', 'red'); + taskMessage.text('Too big size. Please use share functionality'); + return; + } + } + + let taskData = new FormData(); + taskData.append('task_name', name); + taskData.append('bug_tracker_link', bugTrackerLink); + taskData.append('labels', labels); + taskData.append('flip_flag', flipImages); + taskData.append('storage', source); + + if (customSegmentSize.prop('checked')) { + taskData.append('segment_size', segmentSize); + } + if (customOverlapSize.prop('checked')) { + taskData.append('overlap_size', overlapSize); + } + if (customCompressQuality.prop('checked')) { + taskData.append('compress_quality', compressQuality); + } + + for (let file of files) { + taskData.append('data', file); + } + + submitCreate.prop('disabled', true); + createTaskRequest(taskData, + () => { + taskMessage.css('color', 'green'); + taskMessage.text('Successful request! Creating..'); + }, + () => window.location.reload(), + (response) => { + taskMessage.css('color', 'red'); + taskMessage.text(response); + }, + () => submitCreate.prop('disabled', false)); + }); + + function updateSelectedFiles() { + switch (files.length) { + case 0: + filesLabel.text('No Files'); + break; + case 1: + filesLabel.text(typeof(files[0]) == 'string' ? files[0] : files[0].name); + break; + default: + filesLabel.text(files.length + ' files'); + } + } + + + function validateName(name) { + let math = name.match('[a-zA-Z0-9()_ ]+'); + return math != null; + } + + function validateLabels(labels) { + let tmp = labels.replace(/\s/g,''); + return tmp.length > 0; + // to do good validator + } + + function validateSegmentSize(segmentSize) { + return (segmentSize >= 100 && segmentSize <= 50000); + } + + function validateOverlapSize(overlapSize, segmentSize) { + return (overlapSize >= 0 && overlapSize <= segmentSize - 1); + } + + cancelCreate.on('click', () => createModal.addClass('hidden')); +} + + +function setupTaskUpdater() { + let updateModal = $('#dashboardUpdateModal'); + let oldLabels = $('#dashboardOldLabels'); + let newLabels = $('#dashboardNewLabels'); + let submitUpdate = $('#dashboardSubmitUpdate'); + let cancelUpdate = $('#dashboardCancelUpdate'); + + updateModal[0].loadCurrentLabels = function() { + $.ajax({ + url: '/get/task/' + window.cvat.dashboard.taskID, + success: function(data) { + let labels = new LabelsInfo(data.spec); + oldLabels.attr('value', labels.normalize()); + }, + error: function(response) { + oldLabels.attr('value', 'Bad request'); + let message = 'Bad task request: ' + response.responseText; + throw Error(message); + } + }); + }; + + cancelUpdate.on('click', function() { + $('#dashboardNewLabels').prop('value', ''); + updateModal.addClass('hidden'); + }); + + submitUpdate.on('click', () => UpdateTaskRequest(newLabels.prop('value'))); +} + + +function setupSearch() { + let searchInput = $("#dashboardSearchInput"); + let searchSubmit = $("#dashboardSearchSubmit"); + + let line = getUrlParameter('search') || ""; + searchInput.val(line); + + searchSubmit.on('click', function() { + let e = $.Event('keypress'); + e.keyCode = 13; + searchInput.trigger(e); + }); + + searchInput.on('keypress', function(e) { + if (e.keyCode != 13) return; + let filter = e.target.value; + if (!filter) window.location.search = ""; + else window.location.search = `search=${filter}`; + }); + + function getUrlParameter(name) { + let regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); + let results = regex.exec(window.location.search); + return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); + } +} + + +/* Server requests */ +function createTaskRequest(oData, onSuccessRequest, onSuccessCreate, onError, onComplete) { + $.ajax({ + url: '/create/task', + type: 'POST', + data: oData, + contentType: false, + processData: false, + success: function(data) { + onSuccessRequest(); + requestCreatingStatus(data); + }, + error: function(data) { + onComplete(); + onError(data.responseText); + } + }); + + function requestCreatingStatus(data) { + let tid = data.tid; + let request_frequency_ms = 1000; + let done = false; + + let requestInterval = setInterval(function() { + $.ajax({ + url: '/check/task/' + tid, + success: receiveStatus, + error: function(data) { + clearInterval(requestInterval); + onComplete(); + onError(data.responseText); + } + }); + }, request_frequency_ms); + + function receiveStatus(data) { + if (done) return; + if (data['state'] == 'created') { + done = true; + clearInterval(requestInterval); + onComplete(); + onSuccessCreate(); + } + else if (data['state'] == 'error') { + done = true; + clearInterval(requestInterval); + onComplete(); + onError(data.stderr); + } + } + } +} + + +function UpdateTaskRequest(labels) { + let oData = new FormData(); + oData.append('labels', labels); + + $.ajax({ + url: '/update/task/' + window.cvat.dashboard.taskID, + type: 'POST', + data: oData, + contentType: false, + processData: false, + success: function() { + $('#dashboardNewLabels').prop('value', ''); + showMessage('Task successfully updated.'); + }, + error: function(data) { + showMessage('Task update error. ' + data.responseText); + }, + complete: () => $('#dashboardUpdateModal').addClass('hidden') + }); +} + + +function RemoveTaskRequest() { + confirm('The action can not be undone. Are you sure?', confirmCallback); + + function confirmCallback() { + $.ajax ({ + url: '/delete/task/' + window.cvat.dashboard.taskID, + success: function() { + $(`#dashboardTask_${window.cvat.dashboard.taskID}`).remove(); + showMessage('Task removed.'); + }, + error: function(response) { + let message = 'Abort. Reason: ' + response.responseText; + showMessage(message); + throw Error(message); + } + }); + } +} + + +function uploadAnnotationRequest() { + let input = $('').attr({ + type: 'file', + accept: 'text/xml' + }).on('change', loadXML).click(); + + function loadXML(e) { + input.remove(); + let overlay = showOverlay("File uploading.."); + let file = e.target.files[0]; + let fileReader = new FileReader(); + fileReader.onload = (e) => parseFile(e, overlay); + fileReader.readAsText(file); + } + + function parseFile(e, overlay) { + let xmlText = e.target.result; + overlay.setMessage('Request task data from server..'); + $.ajax({ + url: '/get/task/' + window.cvat.dashboard.taskID, + success: function(data) { + let labels = new LabelsInfo(data.spec); + let fakeJob = { + start: 0, + stop: data.size + }; + let annotationParser = new AnnotationParser(labels, fakeJob); + let parsed = null; + try { + parsed = annotationParser.parse(xmlText); + } + catch(error) { + let message = "Parsing errors was occured. " + error; + showMessage(message); + overlay.remove(); + return; + } + overlay.setMessage('Annotation saving..'); + + $.ajax({ + url: '/save/annotation/task/' + window.cvat.dashboard.taskID, + type: 'POST', + data: JSON.stringify(parsed), + contentType: 'application/json', + success: function() { + let message = 'Annotation successfully uploaded'; + showMessage(message); + }, + error: function(response) { + let message = 'Annotation uploading errors was occured. ' + response.responseText; + showMessage(message); + }, + complete: () => overlay.remove() + }); + }, + error: function(response) { + overlay.remove(); + let message = 'Bad task request: ' + response.responseText; + showMessage(message); + throw Error(message); + } + }); + } +} diff --git a/cvat/apps/dashboard/static/dashboard/stylesheet.css b/cvat/apps/dashboard/static/dashboard/stylesheet.css new file mode 100644 index 000000000000..1f938ece678b --- /dev/null +++ b/cvat/apps/dashboard/static/dashboard/stylesheet.css @@ -0,0 +1,121 @@ +.dashboardTaskUI { + margin: 5px auto; + width: 1200px; + height: 335px; + background-color: #e7edf5; + border: 1px solid; + border-radius: 5px; +} + +.dashboardTaskIntro { + width: 25%; + height: 75%; + float: left; + margin-left: 20px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; +} + +.dashboardButtonsUI { + margin-top: 1%; + width: 33%; + height: 75%; + float: left; + overflow-y: auto; +} + +.dashboardButtonUI { + display: block; + width: 70%; + height: 2.5em; + margin: auto; + margin-top: 0.1em; + font-size: 1em; +} + +.dashboardJobsUI { + width: 40%; + height: 75%; + float: left; + text-align: center; + overflow-y: scroll; +} + +.dashboardJobList { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + width: 100%; + margin-top: 15px; +} + +.dashboardTitleWrapper { + overflow: hidden; +} + +#dashboardSearchInput { + padding: 10px; + border: 1px solid grey; + float: left; + width: 70%; + background: #f1f1f1; + outline: 0; +} + +#dashboardSearchSubmit { + float: left; + width: 20%; + padding: 10px; + background: #0b7dda; + color: white; + border: 1px solid grey; + border-left: none; + cursor: pointer; + outline: 0; +} + +#dashboardSearchSubmit:hover { + background: #4c92ee; +} + +#dashboardSearchSubmit:active { + background: #0b7fff; +} + +#dashboardCreateTaskButton { + font-size: 2em; +} + +#dashboardCreateContent { + width: 500px; + display: table; + text-align: center; +} + +#dashboardShareBrowser { + width: 100%; + height: 80%; + border: 1px solid black; + border-radius: 5px; + margin-bottom: 10px; + overflow: auto; +} + +#dashboardUpdateContent { + width: 450px; + height: 120px; +} + + +#dashboardOldLabels { + width: 97%; + margin-bottom: 10px; +} + + +#dashboardNewLabels { + width: 97%; + margin-bottom: 10px; +} diff --git a/cvat/apps/dashboard/templates/dashboard/dashboard.html b/cvat/apps/dashboard/templates/dashboard/dashboard.html new file mode 100644 index 000000000000..41bbfcb71fd1 --- /dev/null +++ b/cvat/apps/dashboard/templates/dashboard/dashboard.html @@ -0,0 +1,187 @@ +{% extends 'engine/base.html' %} +{% load static %} +{% load pagination_tags %} + +{% block head_title %} + CVAT Dashboard +{% endblock %} + +{% block head_css %} + {{ block.super }} + + +{% endblock %} + +{% block head_js_3rdparty %} + {{ block.super }} + + {% for js_file in js_3rdparty %} + + {% endfor %} +{% endblock %} + +{% block head_js_cvat %} + {{ block.super }} + + + + + + + + +{% endblock %} + +{% block content %} +
      +
      + + + + + +
      +
      + + +
      +
      +
      + + {% autopaginate data %} +
      + {% for item in data %} + {% include "dashboard/task.html" %} + {% endfor %} +
      +
      {% paginate %}
      +
      + + + + + + +{% endblock %} diff --git a/cvat/apps/dashboard/templates/dashboard/task.html b/cvat/apps/dashboard/templates/dashboard/task.html new file mode 100644 index 000000000000..be5ac0d9783f --- /dev/null +++ b/cvat/apps/dashboard/templates/dashboard/task.html @@ -0,0 +1,31 @@ +
      +
      + +
      +
      + +
      +
      +
      + + + + + {%if item.has_bug_tracker %} + + + {% endif %} +
      +
      +
      + +
      + + {% for segment in item.segments %} + + + + {% endfor %} +
      {{segment.url}}
      +
      +
      diff --git a/cvat/apps/dashboard/tests.py b/cvat/apps/dashboard/tests.py new file mode 100644 index 000000000000..7ce503c2dd97 --- /dev/null +++ b/cvat/apps/dashboard/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cvat/apps/dashboard/urls.py b/cvat/apps/dashboard/urls.py new file mode 100644 index 000000000000..d2757a5d6abb --- /dev/null +++ b/cvat/apps/dashboard/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('get_share_nodes', views.JsTreeView), + path('', views.DashboardView), +] diff --git a/cvat/apps/dashboard/views.py b/cvat/apps/dashboard/views.py new file mode 100644 index 000000000000..493c195ed340 --- /dev/null +++ b/cvat/apps/dashboard/views.py @@ -0,0 +1,112 @@ +from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest +from django.shortcuts import redirect +from django.shortcuts import render +from django.conf import settings +from django.contrib.auth.decorators import permission_required +from cvat.apps.authentication.decorators import login_required + +from cvat.apps.engine.models import Task as TaskModel +from cvat.settings.base import JS_3RDPARTY + +import os + +def ScanNode(directory): + if '..' in directory.split(os.path.sep): + return HttpResponseBadRequest('Permission Denied') + + act_dir = os.path.normpath(settings.SHARE_ROOT + directory) + result = [] + + nodes = os.listdir(act_dir) + files = filter(os.path.isfile, map(lambda f: os.path.join(act_dir, f), nodes)) + dirs = filter(os.path.isdir, map(lambda d: os.path.join(act_dir, d), nodes)) + + for d in dirs: + name = os.path.basename(d) + children = len(os.listdir(d)) > 0 + node = {'id': directory + name + '/', 'text': name, 'children': children} + result.append(node) + + for f in files: + name = os.path.basename(f) + node = {'id': directory + name, 'text': name, "icon" : "jstree-file"} + result.append(node) + + return result + +@login_required +@permission_required('engine.add_task', raise_exception=True) +def JsTreeView(request): + node_id = None + if 'id' in request.GET: + node_id = request.GET['id'] + + if node_id is None or node_id == '#': + node_id = '/' + response = [{"id": node_id, "text": node_id, "children": ScanNode(node_id)}] + else: + response = ScanNode(node_id) + + return JsonResponse(response, safe=False, + json_dumps_params=dict(ensure_ascii=False)) + + +def MainTaskInfo(task, dst_dict): + dst_dict["status"] = task.status + dst_dict["num_of_segments"] = task.segment_set.count() + dst_dict["mode"] = task.mode.capitalize() + dst_dict["name"] = task.name + dst_dict["task_id"] = task.id + dst_dict["created_date"] = task.created_date + dst_dict["updated_date"] = task.updated_date + dst_dict["bug_tracker_link"] = task.bug_tracker + dst_dict["has_bug_tracker"] = len(task.bug_tracker) > 0 + dst_dict["owner"] = 'undefined' + dst_dict["id"] = task.id + dst_dict["segments"] = [] + +def DetailTaskInfo(request, task, dst_dict): + scheme = request.scheme + host = request.get_host() + dst_dict['segments'] = [] + + for segment in task.segment_set.all(): + for job in segment.job_set.all(): + segment_url = "{0}://{1}/?id={2}".format(scheme, host, job.id) + dst_dict["segments"].append({ + 'id': job.id, + 'start': segment.start_frame, + 'stop': segment.stop_frame, + 'url': segment_url + }) + + db_labels = task.label_set.prefetch_related('attributespec_set').all() + attributes = {} + for db_label in db_labels: + attributes[db_label.id] = {} + for db_attrspec in db_label.attributespec_set.all(): + attributes[db_label.id][db_attrspec.id] = db_attrspec.text + + dst_dict['labels'] = attributes + +@login_required +@permission_required('engine.view_task', raise_exception=True) +def DashboardView(request): + filter_name = request.GET['search'] if 'search' in request.GET else None + tasks_query_set = list(TaskModel.objects.prefetch_related('segment_set').order_by('-created_date').all()) + if filter_name is not None: + tasks_query_set = list(filter(lambda x: filter_name.lower() in x.name.lower(), tasks_query_set)) + + data = [] + for task in tasks_query_set: + task_info = {} + MainTaskInfo(task, task_info) + DetailTaskInfo(request, task, task_info) + data.append(task_info) + + return render(request, 'dashboard/dashboard.html', { + 'data': data, + 'max_upload_size': settings.LOCAL_LOAD_MAX_FILES_SIZE, + 'max_upload_count': settings.LOCAL_LOAD_MAX_FILES_COUNT, + 'js_3rdparty': JS_3RDPARTY.get('dashboard', []) + }) diff --git a/cvat/apps/documentation/__init__.py b/cvat/apps/documentation/__init__.py new file mode 100644 index 000000000000..dc9f833335f8 --- /dev/null +++ b/cvat/apps/documentation/__init__.py @@ -0,0 +1,3 @@ +from cvat.settings.base import JS_3RDPARTY + +JS_3RDPARTY['dashboard'] = JS_3RDPARTY.get('dashboard', []) + ['documentation/js/shortcuts.js'] diff --git a/cvat/apps/documentation/admin.py b/cvat/apps/documentation/admin.py new file mode 100644 index 000000000000..8c38f3f3dad5 --- /dev/null +++ b/cvat/apps/documentation/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cvat/apps/documentation/apps.py b/cvat/apps/documentation/apps.py new file mode 100644 index 000000000000..370c161ebcf4 --- /dev/null +++ b/cvat/apps/documentation/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class DocumentationConfig(AppConfig): + name = 'cvat.apps.documentation' diff --git a/cvat/apps/documentation/migrations/__init__.py b/cvat/apps/documentation/migrations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/documentation/models.py b/cvat/apps/documentation/models.py new file mode 100644 index 000000000000..71a836239075 --- /dev/null +++ b/cvat/apps/documentation/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/cvat/apps/documentation/static/documentation/images/gif001.gif b/cvat/apps/documentation/static/documentation/images/gif001.gif new file mode 100644 index 000000000000..3196e8c16df3 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/gif001.gif differ diff --git a/cvat/apps/documentation/static/documentation/images/gif002.gif b/cvat/apps/documentation/static/documentation/images/gif002.gif new file mode 100644 index 000000000000..c9ecbeee5f59 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/gif002.gif differ diff --git a/cvat/apps/documentation/static/documentation/images/gif003.gif b/cvat/apps/documentation/static/documentation/images/gif003.gif new file mode 100644 index 000000000000..9cad1e66fc1a Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/gif003.gif differ diff --git a/cvat/apps/documentation/static/documentation/images/gif004.gif b/cvat/apps/documentation/static/documentation/images/gif004.gif new file mode 100644 index 000000000000..13afacfe7dc7 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/gif004.gif differ diff --git a/cvat/apps/documentation/static/documentation/images/image001.jpg b/cvat/apps/documentation/static/documentation/images/image001.jpg new file mode 100644 index 000000000000..c2b0195aa1a8 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image001.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image002.jpg b/cvat/apps/documentation/static/documentation/images/image002.jpg new file mode 100644 index 000000000000..e3bf1bf4d7c5 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image002.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image003.jpg b/cvat/apps/documentation/static/documentation/images/image003.jpg new file mode 100644 index 000000000000..4a616ece0723 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image003.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image004.jpg b/cvat/apps/documentation/static/documentation/images/image004.jpg new file mode 100644 index 000000000000..08396ef99587 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image004.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image005.jpg b/cvat/apps/documentation/static/documentation/images/image005.jpg new file mode 100644 index 000000000000..a336d1daeec8 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image005.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image006.jpg b/cvat/apps/documentation/static/documentation/images/image006.jpg new file mode 100644 index 000000000000..aef5fbbe1fe7 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image006.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image007.jpg b/cvat/apps/documentation/static/documentation/images/image007.jpg new file mode 100644 index 000000000000..5f08315dd40d Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image007.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image008.jpg b/cvat/apps/documentation/static/documentation/images/image008.jpg new file mode 100644 index 000000000000..d56750ade719 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image008.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image009.jpg b/cvat/apps/documentation/static/documentation/images/image009.jpg new file mode 100644 index 000000000000..939d215b5312 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image009.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image010.jpg b/cvat/apps/documentation/static/documentation/images/image010.jpg new file mode 100644 index 000000000000..dc1880e3f09e Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image010.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image011.jpg b/cvat/apps/documentation/static/documentation/images/image011.jpg new file mode 100644 index 000000000000..258b634dc6e6 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image011.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image012.jpg b/cvat/apps/documentation/static/documentation/images/image012.jpg new file mode 100644 index 000000000000..6255b92ff84b Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image012.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image013.jpg b/cvat/apps/documentation/static/documentation/images/image013.jpg new file mode 100644 index 000000000000..6338f68035c1 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image013.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image014.jpg b/cvat/apps/documentation/static/documentation/images/image014.jpg new file mode 100644 index 000000000000..76692394427e Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image014.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image015.jpg b/cvat/apps/documentation/static/documentation/images/image015.jpg new file mode 100644 index 000000000000..7c7209a8676e Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image015.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image016.jpg b/cvat/apps/documentation/static/documentation/images/image016.jpg new file mode 100644 index 000000000000..7193507a2fdf Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image016.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image017.jpg b/cvat/apps/documentation/static/documentation/images/image017.jpg new file mode 100644 index 000000000000..5380ee88953d Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image017.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image018.jpg b/cvat/apps/documentation/static/documentation/images/image018.jpg new file mode 100644 index 000000000000..6d66f5906771 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image018.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image019.jpg b/cvat/apps/documentation/static/documentation/images/image019.jpg new file mode 100644 index 000000000000..332e954029c1 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image019.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image020.jpg b/cvat/apps/documentation/static/documentation/images/image020.jpg new file mode 100644 index 000000000000..5d45a4aa6c4a Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image020.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image021.jpg b/cvat/apps/documentation/static/documentation/images/image021.jpg new file mode 100644 index 000000000000..8e33df15a727 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image021.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image022.jpg b/cvat/apps/documentation/static/documentation/images/image022.jpg new file mode 100644 index 000000000000..8622ba3aaf39 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image022.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image023.jpg b/cvat/apps/documentation/static/documentation/images/image023.jpg new file mode 100644 index 000000000000..d0cd8286c28e Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image023.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image024.jpg b/cvat/apps/documentation/static/documentation/images/image024.jpg new file mode 100644 index 000000000000..eb349b117b40 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image024.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image025.jpg b/cvat/apps/documentation/static/documentation/images/image025.jpg new file mode 100644 index 000000000000..436b85ecf0c9 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image025.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image026.jpg b/cvat/apps/documentation/static/documentation/images/image026.jpg new file mode 100644 index 000000000000..eb18f905c0cd Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image026.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image027.jpg b/cvat/apps/documentation/static/documentation/images/image027.jpg new file mode 100644 index 000000000000..782f9ba0d111 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image027.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image028.jpg b/cvat/apps/documentation/static/documentation/images/image028.jpg new file mode 100644 index 000000000000..267bc4e67eb3 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image028.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image030.jpg b/cvat/apps/documentation/static/documentation/images/image030.jpg new file mode 100644 index 000000000000..7c2eadb436c4 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image030.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image031.jpg b/cvat/apps/documentation/static/documentation/images/image031.jpg new file mode 100644 index 000000000000..b88942837b9d Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image031.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image032.jpg b/cvat/apps/documentation/static/documentation/images/image032.jpg new file mode 100644 index 000000000000..6da4b28e5117 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image032.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image033.jpg b/cvat/apps/documentation/static/documentation/images/image033.jpg new file mode 100644 index 000000000000..3ac7ef5aed9c Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image033.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image034.jpg b/cvat/apps/documentation/static/documentation/images/image034.jpg new file mode 100644 index 000000000000..08250372e041 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image034.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image035.jpg b/cvat/apps/documentation/static/documentation/images/image035.jpg new file mode 100644 index 000000000000..4ee8614f8831 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image035.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image036.jpg b/cvat/apps/documentation/static/documentation/images/image036.jpg new file mode 100644 index 000000000000..3c75f62bfd7b Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image036.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image037.jpg b/cvat/apps/documentation/static/documentation/images/image037.jpg new file mode 100644 index 000000000000..b412638d44a3 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image037.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image038.jpg b/cvat/apps/documentation/static/documentation/images/image038.jpg new file mode 100644 index 000000000000..8e0cafc48d2c Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image038.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image039.jpg b/cvat/apps/documentation/static/documentation/images/image039.jpg new file mode 100644 index 000000000000..b745ca51cd9b Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image039.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image040.jpg b/cvat/apps/documentation/static/documentation/images/image040.jpg new file mode 100644 index 000000000000..8ab270be4a76 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image040.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image041.jpg b/cvat/apps/documentation/static/documentation/images/image041.jpg new file mode 100644 index 000000000000..1a9b277c5e6d Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image041.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image042.jpg b/cvat/apps/documentation/static/documentation/images/image042.jpg new file mode 100644 index 000000000000..b307ba867368 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image042.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image043.jpg b/cvat/apps/documentation/static/documentation/images/image043.jpg new file mode 100644 index 000000000000..ac69834359aa Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image043.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image044.jpg b/cvat/apps/documentation/static/documentation/images/image044.jpg new file mode 100644 index 000000000000..ab26d4cd3cf5 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image044.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image045.jpg b/cvat/apps/documentation/static/documentation/images/image045.jpg new file mode 100644 index 000000000000..d28fb049afc4 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image045.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image046.jpg b/cvat/apps/documentation/static/documentation/images/image046.jpg new file mode 100644 index 000000000000..518f7633abc3 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image046.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image047.jpg b/cvat/apps/documentation/static/documentation/images/image047.jpg new file mode 100644 index 000000000000..d8ac3c0ad903 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image047.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image048.jpg b/cvat/apps/documentation/static/documentation/images/image048.jpg new file mode 100644 index 000000000000..910a2838684c Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image048.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image049.jpg b/cvat/apps/documentation/static/documentation/images/image049.jpg new file mode 100644 index 000000000000..b109a73cca6f Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image049.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image050.jpg b/cvat/apps/documentation/static/documentation/images/image050.jpg new file mode 100644 index 000000000000..e6f05a349468 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image050.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image051.jpg b/cvat/apps/documentation/static/documentation/images/image051.jpg new file mode 100644 index 000000000000..44768fa7eb0b Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image051.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image052.jpg b/cvat/apps/documentation/static/documentation/images/image052.jpg new file mode 100644 index 000000000000..df7759449c5a Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image052.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image053.jpg b/cvat/apps/documentation/static/documentation/images/image053.jpg new file mode 100644 index 000000000000..cdde5afc3b24 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image053.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image054.jpg b/cvat/apps/documentation/static/documentation/images/image054.jpg new file mode 100644 index 000000000000..7414eea8ef56 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image054.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image055.jpg b/cvat/apps/documentation/static/documentation/images/image055.jpg new file mode 100644 index 000000000000..5a63342e21ad Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image055.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image056.jpg b/cvat/apps/documentation/static/documentation/images/image056.jpg new file mode 100644 index 000000000000..c10807059d36 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image056.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image057.jpg b/cvat/apps/documentation/static/documentation/images/image057.jpg new file mode 100644 index 000000000000..81485c54ea9c Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image057.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image058.jpg b/cvat/apps/documentation/static/documentation/images/image058.jpg new file mode 100644 index 000000000000..13c3ef098ac7 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image058.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image059.jpg b/cvat/apps/documentation/static/documentation/images/image059.jpg new file mode 100644 index 000000000000..0aa7314bee8f Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image059.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image060.jpg b/cvat/apps/documentation/static/documentation/images/image060.jpg new file mode 100644 index 000000000000..936dde081832 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image060.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image061.jpg b/cvat/apps/documentation/static/documentation/images/image061.jpg new file mode 100644 index 000000000000..a1448d81f873 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image061.jpg differ diff --git a/cvat/apps/documentation/static/documentation/images/image062.jpg b/cvat/apps/documentation/static/documentation/images/image062.jpg new file mode 100644 index 000000000000..cbe16f398009 Binary files /dev/null and b/cvat/apps/documentation/static/documentation/images/image062.jpg differ diff --git a/cvat/apps/documentation/static/documentation/js/3rdparty/showdown-toc.js b/cvat/apps/documentation/static/documentation/js/3rdparty/showdown-toc.js new file mode 100644 index 000000000000..7d917391dd9c --- /dev/null +++ b/cvat/apps/documentation/static/documentation/js/3rdparty/showdown-toc.js @@ -0,0 +1,138 @@ +// Extension loading compatible with AMD and CommonJs +(function(extension) { + 'use strict'; + + if (typeof showdown === 'object') { + // global (browser or nodejs global) + showdown.extension('toc', extension()); + } else if (typeof define === 'function' && define.amd) { + // AMD + define('toc', extension()); + } else if (typeof exports === 'object') { + // Node, CommonJS-like + module.exports = extension(); + } else { + // showdown was not found so we throw + throw Error('Could not find showdown library'); + } + +}(function() { + + function getHeaderEntries(sourceHtml) { + if (typeof window === 'undefined') { + return getHeaderEntriesInNodeJs(sourceHtml); + } else { + return getHeaderEntriesInBrowser(sourceHtml); + } + } + + function getHeaderEntriesInNodeJs(sourceHtml) { + var cheerio = require('cheerio'); + var $ = cheerio.load(sourceHtml); + var headers = $('h1, h2, h3, h4, h5, h6'); + + var headerList = []; + for (var i = 0; i < headers.length; i++) { + var el = headers[i]; + headerList.push(new TocEntry(el.name, $(el).text(), $(el).attr('id'))); + } + + return headerList; + } + + function getHeaderEntriesInBrowser(sourceHtml) { + // Generate dummy element + var source = document.createElement('div'); + source.innerHTML = sourceHtml; + + // Find headers + var headers = source.querySelectorAll('h1, h2, h3, h4, h5, h6'); + var headerList = []; + for (var i = 0; i < headers.length; i++) { + var el = headers[i]; + headerList.push(new TocEntry(el.tagName, el.textContent, el.id)); + } + + return headerList; + } + + function TocEntry(tagName, text, anchor) { + this.tagName = tagName; + this.text = text; + this.anchor = anchor; + this.children = []; + } + + TocEntry.prototype.childrenToString = function() { + if (this.children.length === 0) { + return ""; + } + var result = "
        \n"; + for (var i = 0; i < this.children.length; i++) { + result += this.children[i].toString(); + } + result += "
      \n"; + return result; + }; + + TocEntry.prototype.toString = function() { + var result = "
    • "; + if (this.text) { + result += "" + this.text + ""; + } + result += this.childrenToString(); + result += "
    • \n"; + return result; + }; + + function sortHeader(tocEntries, level) { + level = level || 1; + var tagName = "H" + level, + result = [], + currentTocEntry; + + function push(tocEntry) { + if (tocEntry !== undefined) { + if (tocEntry.children.length > 0) { + tocEntry.children = sortHeader(tocEntry.children, level + 1); + } + result.push(tocEntry); + } + } + + for (var i = 0; i < tocEntries.length; i++) { + var tocEntry = tocEntries[i]; + if (tocEntry.tagName.toUpperCase() !== tagName) { + if (currentTocEntry === undefined) { + currentTocEntry = new TocEntry(); + } + currentTocEntry.children.push(tocEntry); + } else { + push(currentTocEntry); + currentTocEntry = tocEntry; + } + } + + push(currentTocEntry); + return result; + } + + return { + type: 'output', + filter: function(sourceHtml) { + var headerList = getHeaderEntries(sourceHtml); + + // No header found + if (headerList.length === 0) { + return sourceHtml; + } + + // Sort header + headerList = sortHeader(headerList); + + // Build result and replace all [toc] + var result = '
      \n
        \n' + headerList.join("") + '
      \n
      \n'; + return sourceHtml.replace(/\[toc\]/gi, result); + } + }; +})); diff --git a/cvat/apps/documentation/static/documentation/js/3rdparty/showdown.js b/cvat/apps/documentation/static/documentation/js/3rdparty/showdown.js new file mode 100644 index 000000000000..9bd48152e49c --- /dev/null +++ b/cvat/apps/documentation/static/documentation/js/3rdparty/showdown.js @@ -0,0 +1,4504 @@ +;/*! showdown v 1.8.6 - 22-12-2017 */ +(function(){ +/** + * Created by Tivie on 13-07-2015. + */ + +function getDefaultOpts (simple) { + 'use strict'; + + var defaultOptions = { + omitExtraWLInCodeBlocks: { + defaultValue: false, + describe: 'Omit the default extra whiteline added to code blocks', + type: 'boolean' + }, + noHeaderId: { + defaultValue: false, + describe: 'Turn on/off generated header id', + type: 'boolean' + }, + prefixHeaderId: { + defaultValue: false, + describe: 'Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic \'section-\' prefix', + type: 'string' + }, + rawPrefixHeaderId: { + defaultValue: false, + describe: 'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)', + type: 'boolean' + }, + ghCompatibleHeaderId: { + defaultValue: false, + describe: 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)', + type: 'boolean' + }, + rawHeaderId: { + defaultValue: false, + describe: 'Remove only spaces, \' and " from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids', + type: 'boolean' + }, + headerLevelStart: { + defaultValue: false, + describe: 'The header blocks level start', + type: 'integer' + }, + parseImgDimensions: { + defaultValue: false, + describe: 'Turn on/off image dimension parsing', + type: 'boolean' + }, + simplifiedAutoLink: { + defaultValue: false, + describe: 'Turn on/off GFM autolink style', + type: 'boolean' + }, + excludeTrailingPunctuationFromURLs: { + defaultValue: false, + describe: 'Excludes trailing punctuation from links generated with autoLinking', + type: 'boolean' + }, + literalMidWordUnderscores: { + defaultValue: false, + describe: 'Parse midword underscores as literal underscores', + type: 'boolean' + }, + literalMidWordAsterisks: { + defaultValue: false, + describe: 'Parse midword asterisks as literal asterisks', + type: 'boolean' + }, + strikethrough: { + defaultValue: false, + describe: 'Turn on/off strikethrough support', + type: 'boolean' + }, + tables: { + defaultValue: false, + describe: 'Turn on/off tables support', + type: 'boolean' + }, + tablesHeaderId: { + defaultValue: false, + describe: 'Add an id to table headers', + type: 'boolean' + }, + ghCodeBlocks: { + defaultValue: true, + describe: 'Turn on/off GFM fenced code blocks support', + type: 'boolean' + }, + tasklists: { + defaultValue: false, + describe: 'Turn on/off GFM tasklist support', + type: 'boolean' + }, + smoothLivePreview: { + defaultValue: false, + describe: 'Prevents weird effects in live previews due to incomplete input', + type: 'boolean' + }, + smartIndentationFix: { + defaultValue: false, + description: 'Tries to smartly fix indentation in es6 strings', + type: 'boolean' + }, + disableForced4SpacesIndentedSublists: { + defaultValue: false, + description: 'Disables the requirement of indenting nested sublists by 4 spaces', + type: 'boolean' + }, + simpleLineBreaks: { + defaultValue: false, + description: 'Parses simple line breaks as
      (GFM Style)', + type: 'boolean' + }, + requireSpaceBeforeHeadingText: { + defaultValue: false, + description: 'Makes adding a space between `#` and the header text mandatory (GFM Style)', + type: 'boolean' + }, + ghMentions: { + defaultValue: false, + description: 'Enables github @mentions', + type: 'boolean' + }, + ghMentionsLink: { + defaultValue: 'https://github.com/{u}', + description: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.', + type: 'string' + }, + encodeEmails: { + defaultValue: true, + description: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities', + type: 'boolean' + }, + openLinksInNewWindow: { + defaultValue: false, + description: 'Open all links in new windows', + type: 'boolean' + }, + backslashEscapesHTMLTags: { + defaultValue: false, + description: 'Support for HTML Tag escaping. ex: \
      foo\
      ', + type: 'boolean' + }, + emoji: { + defaultValue: false, + description: 'Enable emoji support. Ex: `this is a :smile: emoji`', + type: 'boolean' + }, + underline: { + defaultValue: false, + description: 'Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `` and ``', + type: 'boolean' + }, + completeHTMLDocument: { + defaultValue: false, + description: 'Outputs a complete html document, including ``, `` and `` tags', + type: 'boolean' + }, + metadata: { + defaultValue: false, + description: 'Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).', + type: 'boolean' + }, + splitAdjacentBlockquotes: { + defaultValue: false, + description: 'Split adjacent blockquote blocks', + type: 'boolean' + } + }; + if (simple === false) { + return JSON.parse(JSON.stringify(defaultOptions)); + } + var ret = {}; + for (var opt in defaultOptions) { + if (defaultOptions.hasOwnProperty(opt)) { + ret[opt] = defaultOptions[opt].defaultValue; + } + } + return ret; +} + +function allOptionsOn () { + 'use strict'; + var options = getDefaultOpts(true), + ret = {}; + for (var opt in options) { + if (options.hasOwnProperty(opt)) { + ret[opt] = true; + } + } + return ret; +} + +/** + * Created by Tivie on 06-01-2015. + */ + +// Private properties +var showdown = {}, + parsers = {}, + extensions = {}, + globalOptions = getDefaultOpts(true), + setFlavor = 'vanilla', + flavor = { + github: { + omitExtraWLInCodeBlocks: true, + simplifiedAutoLink: true, + excludeTrailingPunctuationFromURLs: true, + literalMidWordUnderscores: true, + strikethrough: true, + tables: true, + tablesHeaderId: true, + ghCodeBlocks: true, + tasklists: true, + disableForced4SpacesIndentedSublists: true, + simpleLineBreaks: true, + requireSpaceBeforeHeadingText: true, + ghCompatibleHeaderId: true, + ghMentions: true, + backslashEscapesHTMLTags: true, + emoji: true, + splitAdjacentBlockquotes: true + }, + original: { + noHeaderId: true, + ghCodeBlocks: false + }, + ghost: { + omitExtraWLInCodeBlocks: true, + parseImgDimensions: true, + simplifiedAutoLink: true, + excludeTrailingPunctuationFromURLs: true, + literalMidWordUnderscores: true, + strikethrough: true, + tables: true, + tablesHeaderId: true, + ghCodeBlocks: true, + tasklists: true, + smoothLivePreview: true, + simpleLineBreaks: true, + requireSpaceBeforeHeadingText: true, + ghMentions: false, + encodeEmails: true + }, + vanilla: getDefaultOpts(true), + allOn: allOptionsOn() + }; + +/** + * helper namespace + * @type {{}} + */ +showdown.helper = {}; + +/** + * TODO LEGACY SUPPORT CODE + * @type {{}} + */ +showdown.extensions = {}; + +/** + * Set a global option + * @static + * @param {string} key + * @param {*} value + * @returns {showdown} + */ +showdown.setOption = function (key, value) { + 'use strict'; + globalOptions[key] = value; + return this; +}; + +/** + * Get a global option + * @static + * @param {string} key + * @returns {*} + */ +showdown.getOption = function (key) { + 'use strict'; + return globalOptions[key]; +}; + +/** + * Get the global options + * @static + * @returns {{}} + */ +showdown.getOptions = function () { + 'use strict'; + return globalOptions; +}; + +/** + * Reset global options to the default values + * @static + */ +showdown.resetOptions = function () { + 'use strict'; + globalOptions = getDefaultOpts(true); +}; + +/** + * Set the flavor showdown should use as default + * @param {string} name + */ +showdown.setFlavor = function (name) { + 'use strict'; + if (!flavor.hasOwnProperty(name)) { + throw Error(name + ' flavor was not found'); + } + showdown.resetOptions(); + var preset = flavor[name]; + setFlavor = name; + for (var option in preset) { + if (preset.hasOwnProperty(option)) { + globalOptions[option] = preset[option]; + } + } +}; + +/** + * Get the currently set flavor + * @returns {string} + */ +showdown.getFlavor = function () { + 'use strict'; + return setFlavor; +}; + +/** + * Get the options of a specified flavor. Returns undefined if the flavor was not found + * @param {string} name Name of the flavor + * @returns {{}|undefined} + */ +showdown.getFlavorOptions = function (name) { + 'use strict'; + if (flavor.hasOwnProperty(name)) { + return flavor[name]; + } +}; + +/** + * Get the default options + * @static + * @param {boolean} [simple=true] + * @returns {{}} + */ +showdown.getDefaultOptions = function (simple) { + 'use strict'; + return getDefaultOpts(simple); +}; + +/** + * Get or set a subParser + * + * subParser(name) - Get a registered subParser + * subParser(name, func) - Register a subParser + * @static + * @param {string} name + * @param {function} [func] + * @returns {*} + */ +showdown.subParser = function (name, func) { + 'use strict'; + if (showdown.helper.isString(name)) { + if (typeof func !== 'undefined') { + parsers[name] = func; + } else { + if (parsers.hasOwnProperty(name)) { + return parsers[name]; + } else { + throw Error('SubParser named ' + name + ' not registered!'); + } + } + } +}; + +/** + * Gets or registers an extension + * @static + * @param {string} name + * @param {object|function=} ext + * @returns {*} + */ +showdown.extension = function (name, ext) { + 'use strict'; + + if (!showdown.helper.isString(name)) { + throw Error('Extension \'name\' must be a string'); + } + + name = showdown.helper.stdExtName(name); + + // Getter + if (showdown.helper.isUndefined(ext)) { + if (!extensions.hasOwnProperty(name)) { + throw Error('Extension named ' + name + ' is not registered!'); + } + return extensions[name]; + + // Setter + } else { + // Expand extension if it's wrapped in a function + if (typeof ext === 'function') { + ext = ext(); + } + + // Ensure extension is an array + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + + var validExtension = validate(ext, name); + + if (validExtension.valid) { + extensions[name] = ext; + } else { + throw Error(validExtension.error); + } + } +}; + +/** + * Gets all extensions registered + * @returns {{}} + */ +showdown.getAllExtensions = function () { + 'use strict'; + return extensions; +}; + +/** + * Remove an extension + * @param {string} name + */ +showdown.removeExtension = function (name) { + 'use strict'; + delete extensions[name]; +}; + +/** + * Removes all extensions + */ +showdown.resetExtensions = function () { + 'use strict'; + extensions = {}; +}; + +/** + * Validate extension + * @param {array} extension + * @param {string} name + * @returns {{valid: boolean, error: string}} + */ +function validate (extension, name) { + 'use strict'; + + var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension', + ret = { + valid: true, + error: '' + }; + + if (!showdown.helper.isArray(extension)) { + extension = [extension]; + } + + for (var i = 0; i < extension.length; ++i) { + var baseMsg = errMsg + ' sub-extension ' + i + ': ', + ext = extension[i]; + if (typeof ext !== 'object') { + ret.valid = false; + ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given'; + return ret; + } + + if (!showdown.helper.isString(ext.type)) { + ret.valid = false; + ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given'; + return ret; + } + + var type = ext.type = ext.type.toLowerCase(); + + // normalize extension type + if (type === 'language') { + type = ext.type = 'lang'; + } + + if (type === 'html') { + type = ext.type = 'output'; + } + + if (type !== 'lang' && type !== 'output' && type !== 'listener') { + ret.valid = false; + ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"'; + return ret; + } + + if (type === 'listener') { + if (showdown.helper.isUndefined(ext.listeners)) { + ret.valid = false; + ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"'; + return ret; + } + } else { + if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) { + ret.valid = false; + ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method'; + return ret; + } + } + + if (ext.listeners) { + if (typeof ext.listeners !== 'object') { + ret.valid = false; + ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given'; + return ret; + } + for (var ln in ext.listeners) { + if (ext.listeners.hasOwnProperty(ln)) { + if (typeof ext.listeners[ln] !== 'function') { + ret.valid = false; + ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln + + ' must be a function but ' + typeof ext.listeners[ln] + ' given'; + return ret; + } + } + } + } + + if (ext.filter) { + if (typeof ext.filter !== 'function') { + ret.valid = false; + ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given'; + return ret; + } + } else if (ext.regex) { + if (showdown.helper.isString(ext.regex)) { + ext.regex = new RegExp(ext.regex, 'g'); + } + if (!(ext.regex instanceof RegExp)) { + ret.valid = false; + ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given'; + return ret; + } + if (showdown.helper.isUndefined(ext.replace)) { + ret.valid = false; + ret.error = baseMsg + '"regex" extensions must implement a replace string or function'; + return ret; + } + } + } + return ret; +} + +/** + * Validate extension + * @param {object} ext + * @returns {boolean} + */ +showdown.validateExtension = function (ext) { + 'use strict'; + + var validateExtension = validate(ext, null); + if (!validateExtension.valid) { + console.warn(validateExtension.error); + return false; + } + return true; +}; + +/** + * showdownjs helper functions + */ + +if (!showdown.hasOwnProperty('helper')) { + showdown.helper = {}; +} + +/** + * Check if var is string + * @static + * @param {string} a + * @returns {boolean} + */ +showdown.helper.isString = function (a) { + 'use strict'; + return (typeof a === 'string' || a instanceof String); +}; + +/** + * Check if var is a function + * @static + * @param {*} a + * @returns {boolean} + */ +showdown.helper.isFunction = function (a) { + 'use strict'; + var getType = {}; + return a && getType.toString.call(a) === '[object Function]'; +}; + +/** + * isArray helper function + * @static + * @param {*} a + * @returns {boolean} + */ +showdown.helper.isArray = function (a) { + 'use strict'; + return Array.isArray(a); +}; + +/** + * Check if value is undefined + * @static + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + */ +showdown.helper.isUndefined = function (value) { + 'use strict'; + return typeof value === 'undefined'; +}; + +/** + * ForEach helper function + * Iterates over Arrays and Objects (own properties only) + * @static + * @param {*} obj + * @param {function} callback Accepts 3 params: 1. value, 2. key, 3. the original array/object + */ +showdown.helper.forEach = function (obj, callback) { + 'use strict'; + // check if obj is defined + if (showdown.helper.isUndefined(obj)) { + throw new Error('obj param is required'); + } + + if (showdown.helper.isUndefined(callback)) { + throw new Error('callback param is required'); + } + + if (!showdown.helper.isFunction(callback)) { + throw new Error('callback param must be a function/closure'); + } + + if (typeof obj.forEach === 'function') { + obj.forEach(callback); + } else if (showdown.helper.isArray(obj)) { + for (var i = 0; i < obj.length; i++) { + callback(obj[i], i, obj); + } + } else if (typeof (obj) === 'object') { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + callback(obj[prop], prop, obj); + } + } + } else { + throw new Error('obj does not seem to be an array or an iterable object'); + } +}; + +/** + * Standardidize extension name + * @static + * @param {string} s extension name + * @returns {string} + */ +showdown.helper.stdExtName = function (s) { + 'use strict'; + return s.replace(/[_?*+\/\\.^-]/g, '').replace(/\s/g, '').toLowerCase(); +}; + +function escapeCharactersCallback (wholeMatch, m1) { + 'use strict'; + var charCodeToEscape = m1.charCodeAt(0); + return '¨E' + charCodeToEscape + 'E'; +} + +/** + * Callback used to escape characters when passing through String.replace + * @static + * @param {string} wholeMatch + * @param {string} m1 + * @returns {string} + */ +showdown.helper.escapeCharactersCallback = escapeCharactersCallback; + +/** + * Escape characters in a string + * @static + * @param {string} text + * @param {string} charsToEscape + * @param {boolean} afterBackslash + * @returns {XML|string|void|*} + */ +showdown.helper.escapeCharacters = function (text, charsToEscape, afterBackslash) { + 'use strict'; + // First we have to escape the escape characters so that + // we can build a character class out of them + var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])'; + + if (afterBackslash) { + regexString = '\\\\' + regexString; + } + + var regex = new RegExp(regexString, 'g'); + text = text.replace(regex, escapeCharactersCallback); + + return text; +}; + +var rgxFindMatchPos = function (str, left, right, flags) { + 'use strict'; + var f = flags || '', + g = f.indexOf('g') > -1, + x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')), + l = new RegExp(left, f.replace(/g/g, '')), + pos = [], + t, s, m, start, end; + + do { + t = 0; + while ((m = x.exec(str))) { + if (l.test(m[0])) { + if (!(t++)) { + s = x.lastIndex; + start = s - m[0].length; + } + } else if (t) { + if (!--t) { + end = m.index + m[0].length; + var obj = { + left: {start: start, end: s}, + match: {start: s, end: m.index}, + right: {start: m.index, end: end}, + wholeMatch: {start: start, end: end} + }; + pos.push(obj); + if (!g) { + return pos; + } + } + } + } + } while (t && (x.lastIndex = s)); + + return pos; +}; + +/** + * matchRecursiveRegExp + * + * (c) 2007 Steven Levithan + * MIT License + * + * Accepts a string to search, a left and right format delimiter + * as regex patterns, and optional regex flags. Returns an array + * of matches, allowing nested instances of left/right delimiters. + * Use the "g" flag to return all matches, otherwise only the + * first is returned. Be careful to ensure that the left and + * right format delimiters produce mutually exclusive matches. + * Backreferences are not supported within the right delimiter + * due to how it is internally combined with the left delimiter. + * When matching strings whose format delimiters are unbalanced + * to the left or right, the output is intentionally as a + * conventional regex library with recursion support would + * produce, e.g. "<" and ">" both produce ["x"] when using + * "<" and ">" as the delimiters (both strings contain a single, + * balanced instance of ""). + * + * examples: + * matchRecursiveRegExp("test", "\\(", "\\)") + * returns: [] + * matchRecursiveRegExp(">>t<>", "<", ">", "g") + * returns: ["t<>", ""] + * matchRecursiveRegExp("
      test
      ", "]*>", "
      ", "gi") + * returns: ["test"] + */ +showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) { + 'use strict'; + + var matchPos = rgxFindMatchPos (str, left, right, flags), + results = []; + + for (var i = 0; i < matchPos.length; ++i) { + results.push([ + str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), + str.slice(matchPos[i].match.start, matchPos[i].match.end), + str.slice(matchPos[i].left.start, matchPos[i].left.end), + str.slice(matchPos[i].right.start, matchPos[i].right.end) + ]); + } + return results; +}; + +/** + * + * @param {string} str + * @param {string|function} replacement + * @param {string} left + * @param {string} right + * @param {string} flags + * @returns {string} + */ +showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) { + 'use strict'; + + if (!showdown.helper.isFunction(replacement)) { + var repStr = replacement; + replacement = function () { + return repStr; + }; + } + + var matchPos = rgxFindMatchPos(str, left, right, flags), + finalStr = str, + lng = matchPos.length; + + if (lng > 0) { + var bits = []; + if (matchPos[0].wholeMatch.start !== 0) { + bits.push(str.slice(0, matchPos[0].wholeMatch.start)); + } + for (var i = 0; i < lng; ++i) { + bits.push( + replacement( + str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end), + str.slice(matchPos[i].match.start, matchPos[i].match.end), + str.slice(matchPos[i].left.start, matchPos[i].left.end), + str.slice(matchPos[i].right.start, matchPos[i].right.end) + ) + ); + if (i < lng - 1) { + bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start)); + } + } + if (matchPos[lng - 1].wholeMatch.end < str.length) { + bits.push(str.slice(matchPos[lng - 1].wholeMatch.end)); + } + finalStr = bits.join(''); + } + return finalStr; +}; + +/** + * Returns the index within the passed String object of the first occurrence of the specified regex, + * starting the search at fromIndex. Returns -1 if the value is not found. + * + * @param {string} str string to search + * @param {RegExp} regex Regular expression to search + * @param {int} [fromIndex = 0] Index to start the search + * @returns {Number} + * @throws InvalidArgumentError + */ +showdown.helper.regexIndexOf = function (str, regex, fromIndex) { + 'use strict'; + if (!showdown.helper.isString(str)) { + throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string'; + } + if (regex instanceof RegExp === false) { + throw 'InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp'; + } + var indexOf = str.substring(fromIndex || 0).search(regex); + return (indexOf >= 0) ? (indexOf + (fromIndex || 0)) : indexOf; +}; + +/** + * Splits the passed string object at the defined index, and returns an array composed of the two substrings + * @param {string} str string to split + * @param {int} index index to split string at + * @returns {[string,string]} + * @throws InvalidArgumentError + */ +showdown.helper.splitAtIndex = function (str, index) { + 'use strict'; + if (!showdown.helper.isString(str)) { + throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string'; + } + return [str.substring(0, index), str.substring(index)]; +}; + +/** + * Obfuscate an e-mail address through the use of Character Entities, + * transforming ASCII characters into their equivalent decimal or hex entities. + * + * Since it has a random component, subsequent calls to this function produce different results + * + * @param {string} mail + * @returns {string} + */ +showdown.helper.encodeEmailAddress = function (mail) { + 'use strict'; + var encode = [ + function (ch) { + return '&#' + ch.charCodeAt(0) + ';'; + }, + function (ch) { + return '&#x' + ch.charCodeAt(0).toString(16) + ';'; + }, + function (ch) { + return ch; + } + ]; + + mail = mail.replace(/./g, function (ch) { + if (ch === '@') { + // this *must* be encoded. I insist. + ch = encode[Math.floor(Math.random() * 2)](ch); + } else { + var r = Math.random(); + // roughly 10% raw, 45% hex, 45% dec + ch = ( + r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch) + ); + } + return ch; + }); + + return mail; +}; + +/** + * POLYFILLS + */ +// use this instead of builtin is undefined for IE8 compatibility +if (typeof(console) === 'undefined') { + console = { + warn: function (msg) { + 'use strict'; + alert(msg); + }, + log: function (msg) { + 'use strict'; + alert(msg); + }, + error: function (msg) { + 'use strict'; + throw msg; + } + }; +} + +/** + * Common regexes. + * We declare some common regexes to improve performance + */ +showdown.helper.regexes = { + asteriskDashAndColon: /([*_:~])/g +}; + +/** + * EMOJIS LIST + */ +showdown.helper.emojis = { + '+1':'\ud83d\udc4d', + '-1':'\ud83d\udc4e', + '100':'\ud83d\udcaf', + '1234':'\ud83d\udd22', + '1st_place_medal':'\ud83e\udd47', + '2nd_place_medal':'\ud83e\udd48', + '3rd_place_medal':'\ud83e\udd49', + '8ball':'\ud83c\udfb1', + 'a':'\ud83c\udd70\ufe0f', + 'ab':'\ud83c\udd8e', + 'abc':'\ud83d\udd24', + 'abcd':'\ud83d\udd21', + 'accept':'\ud83c\ude51', + 'aerial_tramway':'\ud83d\udea1', + 'airplane':'\u2708\ufe0f', + 'alarm_clock':'\u23f0', + 'alembic':'\u2697\ufe0f', + 'alien':'\ud83d\udc7d', + 'ambulance':'\ud83d\ude91', + 'amphora':'\ud83c\udffa', + 'anchor':'\u2693\ufe0f', + 'angel':'\ud83d\udc7c', + 'anger':'\ud83d\udca2', + 'angry':'\ud83d\ude20', + 'anguished':'\ud83d\ude27', + 'ant':'\ud83d\udc1c', + 'apple':'\ud83c\udf4e', + 'aquarius':'\u2652\ufe0f', + 'aries':'\u2648\ufe0f', + 'arrow_backward':'\u25c0\ufe0f', + 'arrow_double_down':'\u23ec', + 'arrow_double_up':'\u23eb', + 'arrow_down':'\u2b07\ufe0f', + 'arrow_down_small':'\ud83d\udd3d', + 'arrow_forward':'\u25b6\ufe0f', + 'arrow_heading_down':'\u2935\ufe0f', + 'arrow_heading_up':'\u2934\ufe0f', + 'arrow_left':'\u2b05\ufe0f', + 'arrow_lower_left':'\u2199\ufe0f', + 'arrow_lower_right':'\u2198\ufe0f', + 'arrow_right':'\u27a1\ufe0f', + 'arrow_right_hook':'\u21aa\ufe0f', + 'arrow_up':'\u2b06\ufe0f', + 'arrow_up_down':'\u2195\ufe0f', + 'arrow_up_small':'\ud83d\udd3c', + 'arrow_upper_left':'\u2196\ufe0f', + 'arrow_upper_right':'\u2197\ufe0f', + 'arrows_clockwise':'\ud83d\udd03', + 'arrows_counterclockwise':'\ud83d\udd04', + 'art':'\ud83c\udfa8', + 'articulated_lorry':'\ud83d\ude9b', + 'artificial_satellite':'\ud83d\udef0', + 'astonished':'\ud83d\ude32', + 'athletic_shoe':'\ud83d\udc5f', + 'atm':'\ud83c\udfe7', + 'atom_symbol':'\u269b\ufe0f', + 'avocado':'\ud83e\udd51', + 'b':'\ud83c\udd71\ufe0f', + 'baby':'\ud83d\udc76', + 'baby_bottle':'\ud83c\udf7c', + 'baby_chick':'\ud83d\udc24', + 'baby_symbol':'\ud83d\udebc', + 'back':'\ud83d\udd19', + 'bacon':'\ud83e\udd53', + 'badminton':'\ud83c\udff8', + 'baggage_claim':'\ud83d\udec4', + 'baguette_bread':'\ud83e\udd56', + 'balance_scale':'\u2696\ufe0f', + 'balloon':'\ud83c\udf88', + 'ballot_box':'\ud83d\uddf3', + 'ballot_box_with_check':'\u2611\ufe0f', + 'bamboo':'\ud83c\udf8d', + 'banana':'\ud83c\udf4c', + 'bangbang':'\u203c\ufe0f', + 'bank':'\ud83c\udfe6', + 'bar_chart':'\ud83d\udcca', + 'barber':'\ud83d\udc88', + 'baseball':'\u26be\ufe0f', + 'basketball':'\ud83c\udfc0', + 'basketball_man':'\u26f9\ufe0f', + 'basketball_woman':'\u26f9\ufe0f‍\u2640\ufe0f', + 'bat':'\ud83e\udd87', + 'bath':'\ud83d\udec0', + 'bathtub':'\ud83d\udec1', + 'battery':'\ud83d\udd0b', + 'beach_umbrella':'\ud83c\udfd6', + 'bear':'\ud83d\udc3b', + 'bed':'\ud83d\udecf', + 'bee':'\ud83d\udc1d', + 'beer':'\ud83c\udf7a', + 'beers':'\ud83c\udf7b', + 'beetle':'\ud83d\udc1e', + 'beginner':'\ud83d\udd30', + 'bell':'\ud83d\udd14', + 'bellhop_bell':'\ud83d\udece', + 'bento':'\ud83c\udf71', + 'biking_man':'\ud83d\udeb4', + 'bike':'\ud83d\udeb2', + 'biking_woman':'\ud83d\udeb4‍\u2640\ufe0f', + 'bikini':'\ud83d\udc59', + 'biohazard':'\u2623\ufe0f', + 'bird':'\ud83d\udc26', + 'birthday':'\ud83c\udf82', + 'black_circle':'\u26ab\ufe0f', + 'black_flag':'\ud83c\udff4', + 'black_heart':'\ud83d\udda4', + 'black_joker':'\ud83c\udccf', + 'black_large_square':'\u2b1b\ufe0f', + 'black_medium_small_square':'\u25fe\ufe0f', + 'black_medium_square':'\u25fc\ufe0f', + 'black_nib':'\u2712\ufe0f', + 'black_small_square':'\u25aa\ufe0f', + 'black_square_button':'\ud83d\udd32', + 'blonde_man':'\ud83d\udc71', + 'blonde_woman':'\ud83d\udc71‍\u2640\ufe0f', + 'blossom':'\ud83c\udf3c', + 'blowfish':'\ud83d\udc21', + 'blue_book':'\ud83d\udcd8', + 'blue_car':'\ud83d\ude99', + 'blue_heart':'\ud83d\udc99', + 'blush':'\ud83d\ude0a', + 'boar':'\ud83d\udc17', + 'boat':'\u26f5\ufe0f', + 'bomb':'\ud83d\udca3', + 'book':'\ud83d\udcd6', + 'bookmark':'\ud83d\udd16', + 'bookmark_tabs':'\ud83d\udcd1', + 'books':'\ud83d\udcda', + 'boom':'\ud83d\udca5', + 'boot':'\ud83d\udc62', + 'bouquet':'\ud83d\udc90', + 'bowing_man':'\ud83d\ude47', + 'bow_and_arrow':'\ud83c\udff9', + 'bowing_woman':'\ud83d\ude47‍\u2640\ufe0f', + 'bowling':'\ud83c\udfb3', + 'boxing_glove':'\ud83e\udd4a', + 'boy':'\ud83d\udc66', + 'bread':'\ud83c\udf5e', + 'bride_with_veil':'\ud83d\udc70', + 'bridge_at_night':'\ud83c\udf09', + 'briefcase':'\ud83d\udcbc', + 'broken_heart':'\ud83d\udc94', + 'bug':'\ud83d\udc1b', + 'building_construction':'\ud83c\udfd7', + 'bulb':'\ud83d\udca1', + 'bullettrain_front':'\ud83d\ude85', + 'bullettrain_side':'\ud83d\ude84', + 'burrito':'\ud83c\udf2f', + 'bus':'\ud83d\ude8c', + 'business_suit_levitating':'\ud83d\udd74', + 'busstop':'\ud83d\ude8f', + 'bust_in_silhouette':'\ud83d\udc64', + 'busts_in_silhouette':'\ud83d\udc65', + 'butterfly':'\ud83e\udd8b', + 'cactus':'\ud83c\udf35', + 'cake':'\ud83c\udf70', + 'calendar':'\ud83d\udcc6', + 'call_me_hand':'\ud83e\udd19', + 'calling':'\ud83d\udcf2', + 'camel':'\ud83d\udc2b', + 'camera':'\ud83d\udcf7', + 'camera_flash':'\ud83d\udcf8', + 'camping':'\ud83c\udfd5', + 'cancer':'\u264b\ufe0f', + 'candle':'\ud83d\udd6f', + 'candy':'\ud83c\udf6c', + 'canoe':'\ud83d\udef6', + 'capital_abcd':'\ud83d\udd20', + 'capricorn':'\u2651\ufe0f', + 'car':'\ud83d\ude97', + 'card_file_box':'\ud83d\uddc3', + 'card_index':'\ud83d\udcc7', + 'card_index_dividers':'\ud83d\uddc2', + 'carousel_horse':'\ud83c\udfa0', + 'carrot':'\ud83e\udd55', + 'cat':'\ud83d\udc31', + 'cat2':'\ud83d\udc08', + 'cd':'\ud83d\udcbf', + 'chains':'\u26d3', + 'champagne':'\ud83c\udf7e', + 'chart':'\ud83d\udcb9', + 'chart_with_downwards_trend':'\ud83d\udcc9', + 'chart_with_upwards_trend':'\ud83d\udcc8', + 'checkered_flag':'\ud83c\udfc1', + 'cheese':'\ud83e\uddc0', + 'cherries':'\ud83c\udf52', + 'cherry_blossom':'\ud83c\udf38', + 'chestnut':'\ud83c\udf30', + 'chicken':'\ud83d\udc14', + 'children_crossing':'\ud83d\udeb8', + 'chipmunk':'\ud83d\udc3f', + 'chocolate_bar':'\ud83c\udf6b', + 'christmas_tree':'\ud83c\udf84', + 'church':'\u26ea\ufe0f', + 'cinema':'\ud83c\udfa6', + 'circus_tent':'\ud83c\udfaa', + 'city_sunrise':'\ud83c\udf07', + 'city_sunset':'\ud83c\udf06', + 'cityscape':'\ud83c\udfd9', + 'cl':'\ud83c\udd91', + 'clamp':'\ud83d\udddc', + 'clap':'\ud83d\udc4f', + 'clapper':'\ud83c\udfac', + 'classical_building':'\ud83c\udfdb', + 'clinking_glasses':'\ud83e\udd42', + 'clipboard':'\ud83d\udccb', + 'clock1':'\ud83d\udd50', + 'clock10':'\ud83d\udd59', + 'clock1030':'\ud83d\udd65', + 'clock11':'\ud83d\udd5a', + 'clock1130':'\ud83d\udd66', + 'clock12':'\ud83d\udd5b', + 'clock1230':'\ud83d\udd67', + 'clock130':'\ud83d\udd5c', + 'clock2':'\ud83d\udd51', + 'clock230':'\ud83d\udd5d', + 'clock3':'\ud83d\udd52', + 'clock330':'\ud83d\udd5e', + 'clock4':'\ud83d\udd53', + 'clock430':'\ud83d\udd5f', + 'clock5':'\ud83d\udd54', + 'clock530':'\ud83d\udd60', + 'clock6':'\ud83d\udd55', + 'clock630':'\ud83d\udd61', + 'clock7':'\ud83d\udd56', + 'clock730':'\ud83d\udd62', + 'clock8':'\ud83d\udd57', + 'clock830':'\ud83d\udd63', + 'clock9':'\ud83d\udd58', + 'clock930':'\ud83d\udd64', + 'closed_book':'\ud83d\udcd5', + 'closed_lock_with_key':'\ud83d\udd10', + 'closed_umbrella':'\ud83c\udf02', + 'cloud':'\u2601\ufe0f', + 'cloud_with_lightning':'\ud83c\udf29', + 'cloud_with_lightning_and_rain':'\u26c8', + 'cloud_with_rain':'\ud83c\udf27', + 'cloud_with_snow':'\ud83c\udf28', + 'clown_face':'\ud83e\udd21', + 'clubs':'\u2663\ufe0f', + 'cocktail':'\ud83c\udf78', + 'coffee':'\u2615\ufe0f', + 'coffin':'\u26b0\ufe0f', + 'cold_sweat':'\ud83d\ude30', + 'comet':'\u2604\ufe0f', + 'computer':'\ud83d\udcbb', + 'computer_mouse':'\ud83d\uddb1', + 'confetti_ball':'\ud83c\udf8a', + 'confounded':'\ud83d\ude16', + 'confused':'\ud83d\ude15', + 'congratulations':'\u3297\ufe0f', + 'construction':'\ud83d\udea7', + 'construction_worker_man':'\ud83d\udc77', + 'construction_worker_woman':'\ud83d\udc77‍\u2640\ufe0f', + 'control_knobs':'\ud83c\udf9b', + 'convenience_store':'\ud83c\udfea', + 'cookie':'\ud83c\udf6a', + 'cool':'\ud83c\udd92', + 'policeman':'\ud83d\udc6e', + 'copyright':'\u00a9\ufe0f', + 'corn':'\ud83c\udf3d', + 'couch_and_lamp':'\ud83d\udecb', + 'couple':'\ud83d\udc6b', + 'couple_with_heart_woman_man':'\ud83d\udc91', + 'couple_with_heart_man_man':'\ud83d\udc68‍\u2764\ufe0f‍\ud83d\udc68', + 'couple_with_heart_woman_woman':'\ud83d\udc69‍\u2764\ufe0f‍\ud83d\udc69', + 'couplekiss_man_man':'\ud83d\udc68‍\u2764\ufe0f‍\ud83d\udc8b‍\ud83d\udc68', + 'couplekiss_man_woman':'\ud83d\udc8f', + 'couplekiss_woman_woman':'\ud83d\udc69‍\u2764\ufe0f‍\ud83d\udc8b‍\ud83d\udc69', + 'cow':'\ud83d\udc2e', + 'cow2':'\ud83d\udc04', + 'cowboy_hat_face':'\ud83e\udd20', + 'crab':'\ud83e\udd80', + 'crayon':'\ud83d\udd8d', + 'credit_card':'\ud83d\udcb3', + 'crescent_moon':'\ud83c\udf19', + 'cricket':'\ud83c\udfcf', + 'crocodile':'\ud83d\udc0a', + 'croissant':'\ud83e\udd50', + 'crossed_fingers':'\ud83e\udd1e', + 'crossed_flags':'\ud83c\udf8c', + 'crossed_swords':'\u2694\ufe0f', + 'crown':'\ud83d\udc51', + 'cry':'\ud83d\ude22', + 'crying_cat_face':'\ud83d\ude3f', + 'crystal_ball':'\ud83d\udd2e', + 'cucumber':'\ud83e\udd52', + 'cupid':'\ud83d\udc98', + 'curly_loop':'\u27b0', + 'currency_exchange':'\ud83d\udcb1', + 'curry':'\ud83c\udf5b', + 'custard':'\ud83c\udf6e', + 'customs':'\ud83d\udec3', + 'cyclone':'\ud83c\udf00', + 'dagger':'\ud83d\udde1', + 'dancer':'\ud83d\udc83', + 'dancing_women':'\ud83d\udc6f', + 'dancing_men':'\ud83d\udc6f‍\u2642\ufe0f', + 'dango':'\ud83c\udf61', + 'dark_sunglasses':'\ud83d\udd76', + 'dart':'\ud83c\udfaf', + 'dash':'\ud83d\udca8', + 'date':'\ud83d\udcc5', + 'deciduous_tree':'\ud83c\udf33', + 'deer':'\ud83e\udd8c', + 'department_store':'\ud83c\udfec', + 'derelict_house':'\ud83c\udfda', + 'desert':'\ud83c\udfdc', + 'desert_island':'\ud83c\udfdd', + 'desktop_computer':'\ud83d\udda5', + 'male_detective':'\ud83d\udd75\ufe0f', + 'diamond_shape_with_a_dot_inside':'\ud83d\udca0', + 'diamonds':'\u2666\ufe0f', + 'disappointed':'\ud83d\ude1e', + 'disappointed_relieved':'\ud83d\ude25', + 'dizzy':'\ud83d\udcab', + 'dizzy_face':'\ud83d\ude35', + 'do_not_litter':'\ud83d\udeaf', + 'dog':'\ud83d\udc36', + 'dog2':'\ud83d\udc15', + 'dollar':'\ud83d\udcb5', + 'dolls':'\ud83c\udf8e', + 'dolphin':'\ud83d\udc2c', + 'door':'\ud83d\udeaa', + 'doughnut':'\ud83c\udf69', + 'dove':'\ud83d\udd4a', + 'dragon':'\ud83d\udc09', + 'dragon_face':'\ud83d\udc32', + 'dress':'\ud83d\udc57', + 'dromedary_camel':'\ud83d\udc2a', + 'drooling_face':'\ud83e\udd24', + 'droplet':'\ud83d\udca7', + 'drum':'\ud83e\udd41', + 'duck':'\ud83e\udd86', + 'dvd':'\ud83d\udcc0', + 'e-mail':'\ud83d\udce7', + 'eagle':'\ud83e\udd85', + 'ear':'\ud83d\udc42', + 'ear_of_rice':'\ud83c\udf3e', + 'earth_africa':'\ud83c\udf0d', + 'earth_americas':'\ud83c\udf0e', + 'earth_asia':'\ud83c\udf0f', + 'egg':'\ud83e\udd5a', + 'eggplant':'\ud83c\udf46', + 'eight_pointed_black_star':'\u2734\ufe0f', + 'eight_spoked_asterisk':'\u2733\ufe0f', + 'electric_plug':'\ud83d\udd0c', + 'elephant':'\ud83d\udc18', + 'email':'\u2709\ufe0f', + 'end':'\ud83d\udd1a', + 'envelope_with_arrow':'\ud83d\udce9', + 'euro':'\ud83d\udcb6', + 'european_castle':'\ud83c\udff0', + 'european_post_office':'\ud83c\udfe4', + 'evergreen_tree':'\ud83c\udf32', + 'exclamation':'\u2757\ufe0f', + 'expressionless':'\ud83d\ude11', + 'eye':'\ud83d\udc41', + 'eye_speech_bubble':'\ud83d\udc41‍\ud83d\udde8', + 'eyeglasses':'\ud83d\udc53', + 'eyes':'\ud83d\udc40', + 'face_with_head_bandage':'\ud83e\udd15', + 'face_with_thermometer':'\ud83e\udd12', + 'fist_oncoming':'\ud83d\udc4a', + 'factory':'\ud83c\udfed', + 'fallen_leaf':'\ud83c\udf42', + 'family_man_woman_boy':'\ud83d\udc6a', + 'family_man_boy':'\ud83d\udc68‍\ud83d\udc66', + 'family_man_boy_boy':'\ud83d\udc68‍\ud83d\udc66‍\ud83d\udc66', + 'family_man_girl':'\ud83d\udc68‍\ud83d\udc67', + 'family_man_girl_boy':'\ud83d\udc68‍\ud83d\udc67‍\ud83d\udc66', + 'family_man_girl_girl':'\ud83d\udc68‍\ud83d\udc67‍\ud83d\udc67', + 'family_man_man_boy':'\ud83d\udc68‍\ud83d\udc68‍\ud83d\udc66', + 'family_man_man_boy_boy':'\ud83d\udc68‍\ud83d\udc68‍\ud83d\udc66‍\ud83d\udc66', + 'family_man_man_girl':'\ud83d\udc68‍\ud83d\udc68‍\ud83d\udc67', + 'family_man_man_girl_boy':'\ud83d\udc68‍\ud83d\udc68‍\ud83d\udc67‍\ud83d\udc66', + 'family_man_man_girl_girl':'\ud83d\udc68‍\ud83d\udc68‍\ud83d\udc67‍\ud83d\udc67', + 'family_man_woman_boy_boy':'\ud83d\udc68‍\ud83d\udc69‍\ud83d\udc66‍\ud83d\udc66', + 'family_man_woman_girl':'\ud83d\udc68‍\ud83d\udc69‍\ud83d\udc67', + 'family_man_woman_girl_boy':'\ud83d\udc68‍\ud83d\udc69‍\ud83d\udc67‍\ud83d\udc66', + 'family_man_woman_girl_girl':'\ud83d\udc68‍\ud83d\udc69‍\ud83d\udc67‍\ud83d\udc67', + 'family_woman_boy':'\ud83d\udc69‍\ud83d\udc66', + 'family_woman_boy_boy':'\ud83d\udc69‍\ud83d\udc66‍\ud83d\udc66', + 'family_woman_girl':'\ud83d\udc69‍\ud83d\udc67', + 'family_woman_girl_boy':'\ud83d\udc69‍\ud83d\udc67‍\ud83d\udc66', + 'family_woman_girl_girl':'\ud83d\udc69‍\ud83d\udc67‍\ud83d\udc67', + 'family_woman_woman_boy':'\ud83d\udc69‍\ud83d\udc69‍\ud83d\udc66', + 'family_woman_woman_boy_boy':'\ud83d\udc69‍\ud83d\udc69‍\ud83d\udc66‍\ud83d\udc66', + 'family_woman_woman_girl':'\ud83d\udc69‍\ud83d\udc69‍\ud83d\udc67', + 'family_woman_woman_girl_boy':'\ud83d\udc69‍\ud83d\udc69‍\ud83d\udc67‍\ud83d\udc66', + 'family_woman_woman_girl_girl':'\ud83d\udc69‍\ud83d\udc69‍\ud83d\udc67‍\ud83d\udc67', + 'fast_forward':'\u23e9', + 'fax':'\ud83d\udce0', + 'fearful':'\ud83d\ude28', + 'feet':'\ud83d\udc3e', + 'female_detective':'\ud83d\udd75\ufe0f‍\u2640\ufe0f', + 'ferris_wheel':'\ud83c\udfa1', + 'ferry':'\u26f4', + 'field_hockey':'\ud83c\udfd1', + 'file_cabinet':'\ud83d\uddc4', + 'file_folder':'\ud83d\udcc1', + 'film_projector':'\ud83d\udcfd', + 'film_strip':'\ud83c\udf9e', + 'fire':'\ud83d\udd25', + 'fire_engine':'\ud83d\ude92', + 'fireworks':'\ud83c\udf86', + 'first_quarter_moon':'\ud83c\udf13', + 'first_quarter_moon_with_face':'\ud83c\udf1b', + 'fish':'\ud83d\udc1f', + 'fish_cake':'\ud83c\udf65', + 'fishing_pole_and_fish':'\ud83c\udfa3', + 'fist_raised':'\u270a', + 'fist_left':'\ud83e\udd1b', + 'fist_right':'\ud83e\udd1c', + 'flags':'\ud83c\udf8f', + 'flashlight':'\ud83d\udd26', + 'fleur_de_lis':'\u269c\ufe0f', + 'flight_arrival':'\ud83d\udeec', + 'flight_departure':'\ud83d\udeeb', + 'floppy_disk':'\ud83d\udcbe', + 'flower_playing_cards':'\ud83c\udfb4', + 'flushed':'\ud83d\ude33', + 'fog':'\ud83c\udf2b', + 'foggy':'\ud83c\udf01', + 'football':'\ud83c\udfc8', + 'footprints':'\ud83d\udc63', + 'fork_and_knife':'\ud83c\udf74', + 'fountain':'\u26f2\ufe0f', + 'fountain_pen':'\ud83d\udd8b', + 'four_leaf_clover':'\ud83c\udf40', + 'fox_face':'\ud83e\udd8a', + 'framed_picture':'\ud83d\uddbc', + 'free':'\ud83c\udd93', + 'fried_egg':'\ud83c\udf73', + 'fried_shrimp':'\ud83c\udf64', + 'fries':'\ud83c\udf5f', + 'frog':'\ud83d\udc38', + 'frowning':'\ud83d\ude26', + 'frowning_face':'\u2639\ufe0f', + 'frowning_man':'\ud83d\ude4d‍\u2642\ufe0f', + 'frowning_woman':'\ud83d\ude4d', + 'middle_finger':'\ud83d\udd95', + 'fuelpump':'\u26fd\ufe0f', + 'full_moon':'\ud83c\udf15', + 'full_moon_with_face':'\ud83c\udf1d', + 'funeral_urn':'\u26b1\ufe0f', + 'game_die':'\ud83c\udfb2', + 'gear':'\u2699\ufe0f', + 'gem':'\ud83d\udc8e', + 'gemini':'\u264a\ufe0f', + 'ghost':'\ud83d\udc7b', + 'gift':'\ud83c\udf81', + 'gift_heart':'\ud83d\udc9d', + 'girl':'\ud83d\udc67', + 'globe_with_meridians':'\ud83c\udf10', + 'goal_net':'\ud83e\udd45', + 'goat':'\ud83d\udc10', + 'golf':'\u26f3\ufe0f', + 'golfing_man':'\ud83c\udfcc\ufe0f', + 'golfing_woman':'\ud83c\udfcc\ufe0f‍\u2640\ufe0f', + 'gorilla':'\ud83e\udd8d', + 'grapes':'\ud83c\udf47', + 'green_apple':'\ud83c\udf4f', + 'green_book':'\ud83d\udcd7', + 'green_heart':'\ud83d\udc9a', + 'green_salad':'\ud83e\udd57', + 'grey_exclamation':'\u2755', + 'grey_question':'\u2754', + 'grimacing':'\ud83d\ude2c', + 'grin':'\ud83d\ude01', + 'grinning':'\ud83d\ude00', + 'guardsman':'\ud83d\udc82', + 'guardswoman':'\ud83d\udc82‍\u2640\ufe0f', + 'guitar':'\ud83c\udfb8', + 'gun':'\ud83d\udd2b', + 'haircut_woman':'\ud83d\udc87', + 'haircut_man':'\ud83d\udc87‍\u2642\ufe0f', + 'hamburger':'\ud83c\udf54', + 'hammer':'\ud83d\udd28', + 'hammer_and_pick':'\u2692', + 'hammer_and_wrench':'\ud83d\udee0', + 'hamster':'\ud83d\udc39', + 'hand':'\u270b', + 'handbag':'\ud83d\udc5c', + 'handshake':'\ud83e\udd1d', + 'hankey':'\ud83d\udca9', + 'hatched_chick':'\ud83d\udc25', + 'hatching_chick':'\ud83d\udc23', + 'headphones':'\ud83c\udfa7', + 'hear_no_evil':'\ud83d\ude49', + 'heart':'\u2764\ufe0f', + 'heart_decoration':'\ud83d\udc9f', + 'heart_eyes':'\ud83d\ude0d', + 'heart_eyes_cat':'\ud83d\ude3b', + 'heartbeat':'\ud83d\udc93', + 'heartpulse':'\ud83d\udc97', + 'hearts':'\u2665\ufe0f', + 'heavy_check_mark':'\u2714\ufe0f', + 'heavy_division_sign':'\u2797', + 'heavy_dollar_sign':'\ud83d\udcb2', + 'heavy_heart_exclamation':'\u2763\ufe0f', + 'heavy_minus_sign':'\u2796', + 'heavy_multiplication_x':'\u2716\ufe0f', + 'heavy_plus_sign':'\u2795', + 'helicopter':'\ud83d\ude81', + 'herb':'\ud83c\udf3f', + 'hibiscus':'\ud83c\udf3a', + 'high_brightness':'\ud83d\udd06', + 'high_heel':'\ud83d\udc60', + 'hocho':'\ud83d\udd2a', + 'hole':'\ud83d\udd73', + 'honey_pot':'\ud83c\udf6f', + 'horse':'\ud83d\udc34', + 'horse_racing':'\ud83c\udfc7', + 'hospital':'\ud83c\udfe5', + 'hot_pepper':'\ud83c\udf36', + 'hotdog':'\ud83c\udf2d', + 'hotel':'\ud83c\udfe8', + 'hotsprings':'\u2668\ufe0f', + 'hourglass':'\u231b\ufe0f', + 'hourglass_flowing_sand':'\u23f3', + 'house':'\ud83c\udfe0', + 'house_with_garden':'\ud83c\udfe1', + 'houses':'\ud83c\udfd8', + 'hugs':'\ud83e\udd17', + 'hushed':'\ud83d\ude2f', + 'ice_cream':'\ud83c\udf68', + 'ice_hockey':'\ud83c\udfd2', + 'ice_skate':'\u26f8', + 'icecream':'\ud83c\udf66', + 'id':'\ud83c\udd94', + 'ideograph_advantage':'\ud83c\ude50', + 'imp':'\ud83d\udc7f', + 'inbox_tray':'\ud83d\udce5', + 'incoming_envelope':'\ud83d\udce8', + 'tipping_hand_woman':'\ud83d\udc81', + 'information_source':'\u2139\ufe0f', + 'innocent':'\ud83d\ude07', + 'interrobang':'\u2049\ufe0f', + 'iphone':'\ud83d\udcf1', + 'izakaya_lantern':'\ud83c\udfee', + 'jack_o_lantern':'\ud83c\udf83', + 'japan':'\ud83d\uddfe', + 'japanese_castle':'\ud83c\udfef', + 'japanese_goblin':'\ud83d\udc7a', + 'japanese_ogre':'\ud83d\udc79', + 'jeans':'\ud83d\udc56', + 'joy':'\ud83d\ude02', + 'joy_cat':'\ud83d\ude39', + 'joystick':'\ud83d\udd79', + 'kaaba':'\ud83d\udd4b', + 'key':'\ud83d\udd11', + 'keyboard':'\u2328\ufe0f', + 'keycap_ten':'\ud83d\udd1f', + 'kick_scooter':'\ud83d\udef4', + 'kimono':'\ud83d\udc58', + 'kiss':'\ud83d\udc8b', + 'kissing':'\ud83d\ude17', + 'kissing_cat':'\ud83d\ude3d', + 'kissing_closed_eyes':'\ud83d\ude1a', + 'kissing_heart':'\ud83d\ude18', + 'kissing_smiling_eyes':'\ud83d\ude19', + 'kiwi_fruit':'\ud83e\udd5d', + 'koala':'\ud83d\udc28', + 'koko':'\ud83c\ude01', + 'label':'\ud83c\udff7', + 'large_blue_circle':'\ud83d\udd35', + 'large_blue_diamond':'\ud83d\udd37', + 'large_orange_diamond':'\ud83d\udd36', + 'last_quarter_moon':'\ud83c\udf17', + 'last_quarter_moon_with_face':'\ud83c\udf1c', + 'latin_cross':'\u271d\ufe0f', + 'laughing':'\ud83d\ude06', + 'leaves':'\ud83c\udf43', + 'ledger':'\ud83d\udcd2', + 'left_luggage':'\ud83d\udec5', + 'left_right_arrow':'\u2194\ufe0f', + 'leftwards_arrow_with_hook':'\u21a9\ufe0f', + 'lemon':'\ud83c\udf4b', + 'leo':'\u264c\ufe0f', + 'leopard':'\ud83d\udc06', + 'level_slider':'\ud83c\udf9a', + 'libra':'\u264e\ufe0f', + 'light_rail':'\ud83d\ude88', + 'link':'\ud83d\udd17', + 'lion':'\ud83e\udd81', + 'lips':'\ud83d\udc44', + 'lipstick':'\ud83d\udc84', + 'lizard':'\ud83e\udd8e', + 'lock':'\ud83d\udd12', + 'lock_with_ink_pen':'\ud83d\udd0f', + 'lollipop':'\ud83c\udf6d', + 'loop':'\u27bf', + 'loud_sound':'\ud83d\udd0a', + 'loudspeaker':'\ud83d\udce2', + 'love_hotel':'\ud83c\udfe9', + 'love_letter':'\ud83d\udc8c', + 'low_brightness':'\ud83d\udd05', + 'lying_face':'\ud83e\udd25', + 'm':'\u24c2\ufe0f', + 'mag':'\ud83d\udd0d', + 'mag_right':'\ud83d\udd0e', + 'mahjong':'\ud83c\udc04\ufe0f', + 'mailbox':'\ud83d\udceb', + 'mailbox_closed':'\ud83d\udcea', + 'mailbox_with_mail':'\ud83d\udcec', + 'mailbox_with_no_mail':'\ud83d\udced', + 'man':'\ud83d\udc68', + 'man_artist':'\ud83d\udc68‍\ud83c\udfa8', + 'man_astronaut':'\ud83d\udc68‍\ud83d\ude80', + 'man_cartwheeling':'\ud83e\udd38‍\u2642\ufe0f', + 'man_cook':'\ud83d\udc68‍\ud83c\udf73', + 'man_dancing':'\ud83d\udd7a', + 'man_facepalming':'\ud83e\udd26‍\u2642\ufe0f', + 'man_factory_worker':'\ud83d\udc68‍\ud83c\udfed', + 'man_farmer':'\ud83d\udc68‍\ud83c\udf3e', + 'man_firefighter':'\ud83d\udc68‍\ud83d\ude92', + 'man_health_worker':'\ud83d\udc68‍\u2695\ufe0f', + 'man_in_tuxedo':'\ud83e\udd35', + 'man_judge':'\ud83d\udc68‍\u2696\ufe0f', + 'man_juggling':'\ud83e\udd39‍\u2642\ufe0f', + 'man_mechanic':'\ud83d\udc68‍\ud83d\udd27', + 'man_office_worker':'\ud83d\udc68‍\ud83d\udcbc', + 'man_pilot':'\ud83d\udc68‍\u2708\ufe0f', + 'man_playing_handball':'\ud83e\udd3e‍\u2642\ufe0f', + 'man_playing_water_polo':'\ud83e\udd3d‍\u2642\ufe0f', + 'man_scientist':'\ud83d\udc68‍\ud83d\udd2c', + 'man_shrugging':'\ud83e\udd37‍\u2642\ufe0f', + 'man_singer':'\ud83d\udc68‍\ud83c\udfa4', + 'man_student':'\ud83d\udc68‍\ud83c\udf93', + 'man_teacher':'\ud83d\udc68‍\ud83c\udfeb', + 'man_technologist':'\ud83d\udc68‍\ud83d\udcbb', + 'man_with_gua_pi_mao':'\ud83d\udc72', + 'man_with_turban':'\ud83d\udc73', + 'tangerine':'\ud83c\udf4a', + 'mans_shoe':'\ud83d\udc5e', + 'mantelpiece_clock':'\ud83d\udd70', + 'maple_leaf':'\ud83c\udf41', + 'martial_arts_uniform':'\ud83e\udd4b', + 'mask':'\ud83d\ude37', + 'massage_woman':'\ud83d\udc86', + 'massage_man':'\ud83d\udc86‍\u2642\ufe0f', + 'meat_on_bone':'\ud83c\udf56', + 'medal_military':'\ud83c\udf96', + 'medal_sports':'\ud83c\udfc5', + 'mega':'\ud83d\udce3', + 'melon':'\ud83c\udf48', + 'memo':'\ud83d\udcdd', + 'men_wrestling':'\ud83e\udd3c‍\u2642\ufe0f', + 'menorah':'\ud83d\udd4e', + 'mens':'\ud83d\udeb9', + 'metal':'\ud83e\udd18', + 'metro':'\ud83d\ude87', + 'microphone':'\ud83c\udfa4', + 'microscope':'\ud83d\udd2c', + 'milk_glass':'\ud83e\udd5b', + 'milky_way':'\ud83c\udf0c', + 'minibus':'\ud83d\ude90', + 'minidisc':'\ud83d\udcbd', + 'mobile_phone_off':'\ud83d\udcf4', + 'money_mouth_face':'\ud83e\udd11', + 'money_with_wings':'\ud83d\udcb8', + 'moneybag':'\ud83d\udcb0', + 'monkey':'\ud83d\udc12', + 'monkey_face':'\ud83d\udc35', + 'monorail':'\ud83d\ude9d', + 'moon':'\ud83c\udf14', + 'mortar_board':'\ud83c\udf93', + 'mosque':'\ud83d\udd4c', + 'motor_boat':'\ud83d\udee5', + 'motor_scooter':'\ud83d\udef5', + 'motorcycle':'\ud83c\udfcd', + 'motorway':'\ud83d\udee3', + 'mount_fuji':'\ud83d\uddfb', + 'mountain':'\u26f0', + 'mountain_biking_man':'\ud83d\udeb5', + 'mountain_biking_woman':'\ud83d\udeb5‍\u2640\ufe0f', + 'mountain_cableway':'\ud83d\udea0', + 'mountain_railway':'\ud83d\ude9e', + 'mountain_snow':'\ud83c\udfd4', + 'mouse':'\ud83d\udc2d', + 'mouse2':'\ud83d\udc01', + 'movie_camera':'\ud83c\udfa5', + 'moyai':'\ud83d\uddff', + 'mrs_claus':'\ud83e\udd36', + 'muscle':'\ud83d\udcaa', + 'mushroom':'\ud83c\udf44', + 'musical_keyboard':'\ud83c\udfb9', + 'musical_note':'\ud83c\udfb5', + 'musical_score':'\ud83c\udfbc', + 'mute':'\ud83d\udd07', + 'nail_care':'\ud83d\udc85', + 'name_badge':'\ud83d\udcdb', + 'national_park':'\ud83c\udfde', + 'nauseated_face':'\ud83e\udd22', + 'necktie':'\ud83d\udc54', + 'negative_squared_cross_mark':'\u274e', + 'nerd_face':'\ud83e\udd13', + 'neutral_face':'\ud83d\ude10', + 'new':'\ud83c\udd95', + 'new_moon':'\ud83c\udf11', + 'new_moon_with_face':'\ud83c\udf1a', + 'newspaper':'\ud83d\udcf0', + 'newspaper_roll':'\ud83d\uddde', + 'next_track_button':'\u23ed', + 'ng':'\ud83c\udd96', + 'no_good_man':'\ud83d\ude45‍\u2642\ufe0f', + 'no_good_woman':'\ud83d\ude45', + 'night_with_stars':'\ud83c\udf03', + 'no_bell':'\ud83d\udd15', + 'no_bicycles':'\ud83d\udeb3', + 'no_entry':'\u26d4\ufe0f', + 'no_entry_sign':'\ud83d\udeab', + 'no_mobile_phones':'\ud83d\udcf5', + 'no_mouth':'\ud83d\ude36', + 'no_pedestrians':'\ud83d\udeb7', + 'no_smoking':'\ud83d\udead', + 'non-potable_water':'\ud83d\udeb1', + 'nose':'\ud83d\udc43', + 'notebook':'\ud83d\udcd3', + 'notebook_with_decorative_cover':'\ud83d\udcd4', + 'notes':'\ud83c\udfb6', + 'nut_and_bolt':'\ud83d\udd29', + 'o':'\u2b55\ufe0f', + 'o2':'\ud83c\udd7e\ufe0f', + 'ocean':'\ud83c\udf0a', + 'octopus':'\ud83d\udc19', + 'oden':'\ud83c\udf62', + 'office':'\ud83c\udfe2', + 'oil_drum':'\ud83d\udee2', + 'ok':'\ud83c\udd97', + 'ok_hand':'\ud83d\udc4c', + 'ok_man':'\ud83d\ude46‍\u2642\ufe0f', + 'ok_woman':'\ud83d\ude46', + 'old_key':'\ud83d\udddd', + 'older_man':'\ud83d\udc74', + 'older_woman':'\ud83d\udc75', + 'om':'\ud83d\udd49', + 'on':'\ud83d\udd1b', + 'oncoming_automobile':'\ud83d\ude98', + 'oncoming_bus':'\ud83d\ude8d', + 'oncoming_police_car':'\ud83d\ude94', + 'oncoming_taxi':'\ud83d\ude96', + 'open_file_folder':'\ud83d\udcc2', + 'open_hands':'\ud83d\udc50', + 'open_mouth':'\ud83d\ude2e', + 'open_umbrella':'\u2602\ufe0f', + 'ophiuchus':'\u26ce', + 'orange_book':'\ud83d\udcd9', + 'orthodox_cross':'\u2626\ufe0f', + 'outbox_tray':'\ud83d\udce4', + 'owl':'\ud83e\udd89', + 'ox':'\ud83d\udc02', + 'package':'\ud83d\udce6', + 'page_facing_up':'\ud83d\udcc4', + 'page_with_curl':'\ud83d\udcc3', + 'pager':'\ud83d\udcdf', + 'paintbrush':'\ud83d\udd8c', + 'palm_tree':'\ud83c\udf34', + 'pancakes':'\ud83e\udd5e', + 'panda_face':'\ud83d\udc3c', + 'paperclip':'\ud83d\udcce', + 'paperclips':'\ud83d\udd87', + 'parasol_on_ground':'\u26f1', + 'parking':'\ud83c\udd7f\ufe0f', + 'part_alternation_mark':'\u303d\ufe0f', + 'partly_sunny':'\u26c5\ufe0f', + 'passenger_ship':'\ud83d\udef3', + 'passport_control':'\ud83d\udec2', + 'pause_button':'\u23f8', + 'peace_symbol':'\u262e\ufe0f', + 'peach':'\ud83c\udf51', + 'peanuts':'\ud83e\udd5c', + 'pear':'\ud83c\udf50', + 'pen':'\ud83d\udd8a', + 'pencil2':'\u270f\ufe0f', + 'penguin':'\ud83d\udc27', + 'pensive':'\ud83d\ude14', + 'performing_arts':'\ud83c\udfad', + 'persevere':'\ud83d\ude23', + 'person_fencing':'\ud83e\udd3a', + 'pouting_woman':'\ud83d\ude4e', + 'phone':'\u260e\ufe0f', + 'pick':'\u26cf', + 'pig':'\ud83d\udc37', + 'pig2':'\ud83d\udc16', + 'pig_nose':'\ud83d\udc3d', + 'pill':'\ud83d\udc8a', + 'pineapple':'\ud83c\udf4d', + 'ping_pong':'\ud83c\udfd3', + 'pisces':'\u2653\ufe0f', + 'pizza':'\ud83c\udf55', + 'place_of_worship':'\ud83d\uded0', + 'plate_with_cutlery':'\ud83c\udf7d', + 'play_or_pause_button':'\u23ef', + 'point_down':'\ud83d\udc47', + 'point_left':'\ud83d\udc48', + 'point_right':'\ud83d\udc49', + 'point_up':'\u261d\ufe0f', + 'point_up_2':'\ud83d\udc46', + 'police_car':'\ud83d\ude93', + 'policewoman':'\ud83d\udc6e‍\u2640\ufe0f', + 'poodle':'\ud83d\udc29', + 'popcorn':'\ud83c\udf7f', + 'post_office':'\ud83c\udfe3', + 'postal_horn':'\ud83d\udcef', + 'postbox':'\ud83d\udcee', + 'potable_water':'\ud83d\udeb0', + 'potato':'\ud83e\udd54', + 'pouch':'\ud83d\udc5d', + 'poultry_leg':'\ud83c\udf57', + 'pound':'\ud83d\udcb7', + 'rage':'\ud83d\ude21', + 'pouting_cat':'\ud83d\ude3e', + 'pouting_man':'\ud83d\ude4e‍\u2642\ufe0f', + 'pray':'\ud83d\ude4f', + 'prayer_beads':'\ud83d\udcff', + 'pregnant_woman':'\ud83e\udd30', + 'previous_track_button':'\u23ee', + 'prince':'\ud83e\udd34', + 'princess':'\ud83d\udc78', + 'printer':'\ud83d\udda8', + 'purple_heart':'\ud83d\udc9c', + 'purse':'\ud83d\udc5b', + 'pushpin':'\ud83d\udccc', + 'put_litter_in_its_place':'\ud83d\udeae', + 'question':'\u2753', + 'rabbit':'\ud83d\udc30', + 'rabbit2':'\ud83d\udc07', + 'racehorse':'\ud83d\udc0e', + 'racing_car':'\ud83c\udfce', + 'radio':'\ud83d\udcfb', + 'radio_button':'\ud83d\udd18', + 'radioactive':'\u2622\ufe0f', + 'railway_car':'\ud83d\ude83', + 'railway_track':'\ud83d\udee4', + 'rainbow':'\ud83c\udf08', + 'rainbow_flag':'\ud83c\udff3\ufe0f‍\ud83c\udf08', + 'raised_back_of_hand':'\ud83e\udd1a', + 'raised_hand_with_fingers_splayed':'\ud83d\udd90', + 'raised_hands':'\ud83d\ude4c', + 'raising_hand_woman':'\ud83d\ude4b', + 'raising_hand_man':'\ud83d\ude4b‍\u2642\ufe0f', + 'ram':'\ud83d\udc0f', + 'ramen':'\ud83c\udf5c', + 'rat':'\ud83d\udc00', + 'record_button':'\u23fa', + 'recycle':'\u267b\ufe0f', + 'red_circle':'\ud83d\udd34', + 'registered':'\u00ae\ufe0f', + 'relaxed':'\u263a\ufe0f', + 'relieved':'\ud83d\ude0c', + 'reminder_ribbon':'\ud83c\udf97', + 'repeat':'\ud83d\udd01', + 'repeat_one':'\ud83d\udd02', + 'rescue_worker_helmet':'\u26d1', + 'restroom':'\ud83d\udebb', + 'revolving_hearts':'\ud83d\udc9e', + 'rewind':'\u23ea', + 'rhinoceros':'\ud83e\udd8f', + 'ribbon':'\ud83c\udf80', + 'rice':'\ud83c\udf5a', + 'rice_ball':'\ud83c\udf59', + 'rice_cracker':'\ud83c\udf58', + 'rice_scene':'\ud83c\udf91', + 'right_anger_bubble':'\ud83d\uddef', + 'ring':'\ud83d\udc8d', + 'robot':'\ud83e\udd16', + 'rocket':'\ud83d\ude80', + 'rofl':'\ud83e\udd23', + 'roll_eyes':'\ud83d\ude44', + 'roller_coaster':'\ud83c\udfa2', + 'rooster':'\ud83d\udc13', + 'rose':'\ud83c\udf39', + 'rosette':'\ud83c\udff5', + 'rotating_light':'\ud83d\udea8', + 'round_pushpin':'\ud83d\udccd', + 'rowing_man':'\ud83d\udea3', + 'rowing_woman':'\ud83d\udea3‍\u2640\ufe0f', + 'rugby_football':'\ud83c\udfc9', + 'running_man':'\ud83c\udfc3', + 'running_shirt_with_sash':'\ud83c\udfbd', + 'running_woman':'\ud83c\udfc3‍\u2640\ufe0f', + 'sa':'\ud83c\ude02\ufe0f', + 'sagittarius':'\u2650\ufe0f', + 'sake':'\ud83c\udf76', + 'sandal':'\ud83d\udc61', + 'santa':'\ud83c\udf85', + 'satellite':'\ud83d\udce1', + 'saxophone':'\ud83c\udfb7', + 'school':'\ud83c\udfeb', + 'school_satchel':'\ud83c\udf92', + 'scissors':'\u2702\ufe0f', + 'scorpion':'\ud83e\udd82', + 'scorpius':'\u264f\ufe0f', + 'scream':'\ud83d\ude31', + 'scream_cat':'\ud83d\ude40', + 'scroll':'\ud83d\udcdc', + 'seat':'\ud83d\udcba', + 'secret':'\u3299\ufe0f', + 'see_no_evil':'\ud83d\ude48', + 'seedling':'\ud83c\udf31', + 'selfie':'\ud83e\udd33', + 'shallow_pan_of_food':'\ud83e\udd58', + 'shamrock':'\u2618\ufe0f', + 'shark':'\ud83e\udd88', + 'shaved_ice':'\ud83c\udf67', + 'sheep':'\ud83d\udc11', + 'shell':'\ud83d\udc1a', + 'shield':'\ud83d\udee1', + 'shinto_shrine':'\u26e9', + 'ship':'\ud83d\udea2', + 'shirt':'\ud83d\udc55', + 'shopping':'\ud83d\udecd', + 'shopping_cart':'\ud83d\uded2', + 'shower':'\ud83d\udebf', + 'shrimp':'\ud83e\udd90', + 'signal_strength':'\ud83d\udcf6', + 'six_pointed_star':'\ud83d\udd2f', + 'ski':'\ud83c\udfbf', + 'skier':'\u26f7', + 'skull':'\ud83d\udc80', + 'skull_and_crossbones':'\u2620\ufe0f', + 'sleeping':'\ud83d\ude34', + 'sleeping_bed':'\ud83d\udecc', + 'sleepy':'\ud83d\ude2a', + 'slightly_frowning_face':'\ud83d\ude41', + 'slightly_smiling_face':'\ud83d\ude42', + 'slot_machine':'\ud83c\udfb0', + 'small_airplane':'\ud83d\udee9', + 'small_blue_diamond':'\ud83d\udd39', + 'small_orange_diamond':'\ud83d\udd38', + 'small_red_triangle':'\ud83d\udd3a', + 'small_red_triangle_down':'\ud83d\udd3b', + 'smile':'\ud83d\ude04', + 'smile_cat':'\ud83d\ude38', + 'smiley':'\ud83d\ude03', + 'smiley_cat':'\ud83d\ude3a', + 'smiling_imp':'\ud83d\ude08', + 'smirk':'\ud83d\ude0f', + 'smirk_cat':'\ud83d\ude3c', + 'smoking':'\ud83d\udeac', + 'snail':'\ud83d\udc0c', + 'snake':'\ud83d\udc0d', + 'sneezing_face':'\ud83e\udd27', + 'snowboarder':'\ud83c\udfc2', + 'snowflake':'\u2744\ufe0f', + 'snowman':'\u26c4\ufe0f', + 'snowman_with_snow':'\u2603\ufe0f', + 'sob':'\ud83d\ude2d', + 'soccer':'\u26bd\ufe0f', + 'soon':'\ud83d\udd1c', + 'sos':'\ud83c\udd98', + 'sound':'\ud83d\udd09', + 'space_invader':'\ud83d\udc7e', + 'spades':'\u2660\ufe0f', + 'spaghetti':'\ud83c\udf5d', + 'sparkle':'\u2747\ufe0f', + 'sparkler':'\ud83c\udf87', + 'sparkles':'\u2728', + 'sparkling_heart':'\ud83d\udc96', + 'speak_no_evil':'\ud83d\ude4a', + 'speaker':'\ud83d\udd08', + 'speaking_head':'\ud83d\udde3', + 'speech_balloon':'\ud83d\udcac', + 'speedboat':'\ud83d\udea4', + 'spider':'\ud83d\udd77', + 'spider_web':'\ud83d\udd78', + 'spiral_calendar':'\ud83d\uddd3', + 'spiral_notepad':'\ud83d\uddd2', + 'spoon':'\ud83e\udd44', + 'squid':'\ud83e\udd91', + 'stadium':'\ud83c\udfdf', + 'star':'\u2b50\ufe0f', + 'star2':'\ud83c\udf1f', + 'star_and_crescent':'\u262a\ufe0f', + 'star_of_david':'\u2721\ufe0f', + 'stars':'\ud83c\udf20', + 'station':'\ud83d\ude89', + 'statue_of_liberty':'\ud83d\uddfd', + 'steam_locomotive':'\ud83d\ude82', + 'stew':'\ud83c\udf72', + 'stop_button':'\u23f9', + 'stop_sign':'\ud83d\uded1', + 'stopwatch':'\u23f1', + 'straight_ruler':'\ud83d\udccf', + 'strawberry':'\ud83c\udf53', + 'stuck_out_tongue':'\ud83d\ude1b', + 'stuck_out_tongue_closed_eyes':'\ud83d\ude1d', + 'stuck_out_tongue_winking_eye':'\ud83d\ude1c', + 'studio_microphone':'\ud83c\udf99', + 'stuffed_flatbread':'\ud83e\udd59', + 'sun_behind_large_cloud':'\ud83c\udf25', + 'sun_behind_rain_cloud':'\ud83c\udf26', + 'sun_behind_small_cloud':'\ud83c\udf24', + 'sun_with_face':'\ud83c\udf1e', + 'sunflower':'\ud83c\udf3b', + 'sunglasses':'\ud83d\ude0e', + 'sunny':'\u2600\ufe0f', + 'sunrise':'\ud83c\udf05', + 'sunrise_over_mountains':'\ud83c\udf04', + 'surfing_man':'\ud83c\udfc4', + 'surfing_woman':'\ud83c\udfc4‍\u2640\ufe0f', + 'sushi':'\ud83c\udf63', + 'suspension_railway':'\ud83d\ude9f', + 'sweat':'\ud83d\ude13', + 'sweat_drops':'\ud83d\udca6', + 'sweat_smile':'\ud83d\ude05', + 'sweet_potato':'\ud83c\udf60', + 'swimming_man':'\ud83c\udfca', + 'swimming_woman':'\ud83c\udfca‍\u2640\ufe0f', + 'symbols':'\ud83d\udd23', + 'synagogue':'\ud83d\udd4d', + 'syringe':'\ud83d\udc89', + 'taco':'\ud83c\udf2e', + 'tada':'\ud83c\udf89', + 'tanabata_tree':'\ud83c\udf8b', + 'taurus':'\u2649\ufe0f', + 'taxi':'\ud83d\ude95', + 'tea':'\ud83c\udf75', + 'telephone_receiver':'\ud83d\udcde', + 'telescope':'\ud83d\udd2d', + 'tennis':'\ud83c\udfbe', + 'tent':'\u26fa\ufe0f', + 'thermometer':'\ud83c\udf21', + 'thinking':'\ud83e\udd14', + 'thought_balloon':'\ud83d\udcad', + 'ticket':'\ud83c\udfab', + 'tickets':'\ud83c\udf9f', + 'tiger':'\ud83d\udc2f', + 'tiger2':'\ud83d\udc05', + 'timer_clock':'\u23f2', + 'tipping_hand_man':'\ud83d\udc81‍\u2642\ufe0f', + 'tired_face':'\ud83d\ude2b', + 'tm':'\u2122\ufe0f', + 'toilet':'\ud83d\udebd', + 'tokyo_tower':'\ud83d\uddfc', + 'tomato':'\ud83c\udf45', + 'tongue':'\ud83d\udc45', + 'top':'\ud83d\udd1d', + 'tophat':'\ud83c\udfa9', + 'tornado':'\ud83c\udf2a', + 'trackball':'\ud83d\uddb2', + 'tractor':'\ud83d\ude9c', + 'traffic_light':'\ud83d\udea5', + 'train':'\ud83d\ude8b', + 'train2':'\ud83d\ude86', + 'tram':'\ud83d\ude8a', + 'triangular_flag_on_post':'\ud83d\udea9', + 'triangular_ruler':'\ud83d\udcd0', + 'trident':'\ud83d\udd31', + 'triumph':'\ud83d\ude24', + 'trolleybus':'\ud83d\ude8e', + 'trophy':'\ud83c\udfc6', + 'tropical_drink':'\ud83c\udf79', + 'tropical_fish':'\ud83d\udc20', + 'truck':'\ud83d\ude9a', + 'trumpet':'\ud83c\udfba', + 'tulip':'\ud83c\udf37', + 'tumbler_glass':'\ud83e\udd43', + 'turkey':'\ud83e\udd83', + 'turtle':'\ud83d\udc22', + 'tv':'\ud83d\udcfa', + 'twisted_rightwards_arrows':'\ud83d\udd00', + 'two_hearts':'\ud83d\udc95', + 'two_men_holding_hands':'\ud83d\udc6c', + 'two_women_holding_hands':'\ud83d\udc6d', + 'u5272':'\ud83c\ude39', + 'u5408':'\ud83c\ude34', + 'u55b6':'\ud83c\ude3a', + 'u6307':'\ud83c\ude2f\ufe0f', + 'u6708':'\ud83c\ude37\ufe0f', + 'u6709':'\ud83c\ude36', + 'u6e80':'\ud83c\ude35', + 'u7121':'\ud83c\ude1a\ufe0f', + 'u7533':'\ud83c\ude38', + 'u7981':'\ud83c\ude32', + 'u7a7a':'\ud83c\ude33', + 'umbrella':'\u2614\ufe0f', + 'unamused':'\ud83d\ude12', + 'underage':'\ud83d\udd1e', + 'unicorn':'\ud83e\udd84', + 'unlock':'\ud83d\udd13', + 'up':'\ud83c\udd99', + 'upside_down_face':'\ud83d\ude43', + 'v':'\u270c\ufe0f', + 'vertical_traffic_light':'\ud83d\udea6', + 'vhs':'\ud83d\udcfc', + 'vibration_mode':'\ud83d\udcf3', + 'video_camera':'\ud83d\udcf9', + 'video_game':'\ud83c\udfae', + 'violin':'\ud83c\udfbb', + 'virgo':'\u264d\ufe0f', + 'volcano':'\ud83c\udf0b', + 'volleyball':'\ud83c\udfd0', + 'vs':'\ud83c\udd9a', + 'vulcan_salute':'\ud83d\udd96', + 'walking_man':'\ud83d\udeb6', + 'walking_woman':'\ud83d\udeb6‍\u2640\ufe0f', + 'waning_crescent_moon':'\ud83c\udf18', + 'waning_gibbous_moon':'\ud83c\udf16', + 'warning':'\u26a0\ufe0f', + 'wastebasket':'\ud83d\uddd1', + 'watch':'\u231a\ufe0f', + 'water_buffalo':'\ud83d\udc03', + 'watermelon':'\ud83c\udf49', + 'wave':'\ud83d\udc4b', + 'wavy_dash':'\u3030\ufe0f', + 'waxing_crescent_moon':'\ud83c\udf12', + 'wc':'\ud83d\udebe', + 'weary':'\ud83d\ude29', + 'wedding':'\ud83d\udc92', + 'weight_lifting_man':'\ud83c\udfcb\ufe0f', + 'weight_lifting_woman':'\ud83c\udfcb\ufe0f‍\u2640\ufe0f', + 'whale':'\ud83d\udc33', + 'whale2':'\ud83d\udc0b', + 'wheel_of_dharma':'\u2638\ufe0f', + 'wheelchair':'\u267f\ufe0f', + 'white_check_mark':'\u2705', + 'white_circle':'\u26aa\ufe0f', + 'white_flag':'\ud83c\udff3\ufe0f', + 'white_flower':'\ud83d\udcae', + 'white_large_square':'\u2b1c\ufe0f', + 'white_medium_small_square':'\u25fd\ufe0f', + 'white_medium_square':'\u25fb\ufe0f', + 'white_small_square':'\u25ab\ufe0f', + 'white_square_button':'\ud83d\udd33', + 'wilted_flower':'\ud83e\udd40', + 'wind_chime':'\ud83c\udf90', + 'wind_face':'\ud83c\udf2c', + 'wine_glass':'\ud83c\udf77', + 'wink':'\ud83d\ude09', + 'wolf':'\ud83d\udc3a', + 'woman':'\ud83d\udc69', + 'woman_artist':'\ud83d\udc69‍\ud83c\udfa8', + 'woman_astronaut':'\ud83d\udc69‍\ud83d\ude80', + 'woman_cartwheeling':'\ud83e\udd38‍\u2640\ufe0f', + 'woman_cook':'\ud83d\udc69‍\ud83c\udf73', + 'woman_facepalming':'\ud83e\udd26‍\u2640\ufe0f', + 'woman_factory_worker':'\ud83d\udc69‍\ud83c\udfed', + 'woman_farmer':'\ud83d\udc69‍\ud83c\udf3e', + 'woman_firefighter':'\ud83d\udc69‍\ud83d\ude92', + 'woman_health_worker':'\ud83d\udc69‍\u2695\ufe0f', + 'woman_judge':'\ud83d\udc69‍\u2696\ufe0f', + 'woman_juggling':'\ud83e\udd39‍\u2640\ufe0f', + 'woman_mechanic':'\ud83d\udc69‍\ud83d\udd27', + 'woman_office_worker':'\ud83d\udc69‍\ud83d\udcbc', + 'woman_pilot':'\ud83d\udc69‍\u2708\ufe0f', + 'woman_playing_handball':'\ud83e\udd3e‍\u2640\ufe0f', + 'woman_playing_water_polo':'\ud83e\udd3d‍\u2640\ufe0f', + 'woman_scientist':'\ud83d\udc69‍\ud83d\udd2c', + 'woman_shrugging':'\ud83e\udd37‍\u2640\ufe0f', + 'woman_singer':'\ud83d\udc69‍\ud83c\udfa4', + 'woman_student':'\ud83d\udc69‍\ud83c\udf93', + 'woman_teacher':'\ud83d\udc69‍\ud83c\udfeb', + 'woman_technologist':'\ud83d\udc69‍\ud83d\udcbb', + 'woman_with_turban':'\ud83d\udc73‍\u2640\ufe0f', + 'womans_clothes':'\ud83d\udc5a', + 'womans_hat':'\ud83d\udc52', + 'women_wrestling':'\ud83e\udd3c‍\u2640\ufe0f', + 'womens':'\ud83d\udeba', + 'world_map':'\ud83d\uddfa', + 'worried':'\ud83d\ude1f', + 'wrench':'\ud83d\udd27', + 'writing_hand':'\u270d\ufe0f', + 'x':'\u274c', + 'yellow_heart':'\ud83d\udc9b', + 'yen':'\ud83d\udcb4', + 'yin_yang':'\u262f\ufe0f', + 'yum':'\ud83d\ude0b', + 'zap':'\u26a1\ufe0f', + 'zipper_mouth_face':'\ud83e\udd10', + 'zzz':'\ud83d\udca4', + + /* special emojis :P */ + 'octocat': '', + 'showdown': '' +}; + +/** + * Created by Estevao on 31-05-2015. + */ + +/** + * Showdown Converter class + * @class + * @param {object} [converterOptions] + * @returns {Converter} + */ +showdown.Converter = function (converterOptions) { + 'use strict'; + + var + /** + * Options used by this converter + * @private + * @type {{}} + */ + options = {}, + + /** + * Language extensions used by this converter + * @private + * @type {Array} + */ + langExtensions = [], + + /** + * Output modifiers extensions used by this converter + * @private + * @type {Array} + */ + outputModifiers = [], + + /** + * Event listeners + * @private + * @type {{}} + */ + listeners = {}, + + /** + * The flavor set in this converter + */ + setConvFlavor = setFlavor, + + /** + * Metadata of the document + * @type {{parsed: {}, raw: string, format: string}} + */ + metadata = { + parsed: {}, + raw: '', + format: '' + }; + + _constructor(); + + /** + * Converter constructor + * @private + */ + function _constructor () { + converterOptions = converterOptions || {}; + + for (var gOpt in globalOptions) { + if (globalOptions.hasOwnProperty(gOpt)) { + options[gOpt] = globalOptions[gOpt]; + } + } + + // Merge options + if (typeof converterOptions === 'object') { + for (var opt in converterOptions) { + if (converterOptions.hasOwnProperty(opt)) { + options[opt] = converterOptions[opt]; + } + } + } else { + throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions + + ' was passed instead.'); + } + + if (options.extensions) { + showdown.helper.forEach(options.extensions, _parseExtension); + } + } + + /** + * Parse extension + * @param {*} ext + * @param {string} [name=''] + * @private + */ + function _parseExtension (ext, name) { + + name = name || null; + // If it's a string, the extension was previously loaded + if (showdown.helper.isString(ext)) { + ext = showdown.helper.stdExtName(ext); + name = ext; + + // LEGACY_SUPPORT CODE + if (showdown.extensions[ext]) { + console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' + + 'Please inform the developer that the extension should be updated!'); + legacyExtensionLoading(showdown.extensions[ext], ext); + return; + // END LEGACY SUPPORT CODE + + } else if (!showdown.helper.isUndefined(extensions[ext])) { + ext = extensions[ext]; + + } else { + throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.'); + } + } + + if (typeof ext === 'function') { + ext = ext(); + } + + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + + var validExt = validate(ext, name); + if (!validExt.valid) { + throw Error(validExt.error); + } + + for (var i = 0; i < ext.length; ++i) { + switch (ext[i].type) { + + case 'lang': + langExtensions.push(ext[i]); + break; + + case 'output': + outputModifiers.push(ext[i]); + break; + } + if (ext[i].hasOwnProperty('listeners')) { + for (var ln in ext[i].listeners) { + if (ext[i].listeners.hasOwnProperty(ln)) { + listen(ln, ext[i].listeners[ln]); + } + } + } + } + + } + + /** + * LEGACY_SUPPORT + * @param {*} ext + * @param {string} name + */ + function legacyExtensionLoading (ext, name) { + if (typeof ext === 'function') { + ext = ext(new showdown.Converter()); + } + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + var valid = validate(ext, name); + + if (!valid.valid) { + throw Error(valid.error); + } + + for (var i = 0; i < ext.length; ++i) { + switch (ext[i].type) { + case 'lang': + langExtensions.push(ext[i]); + break; + case 'output': + outputModifiers.push(ext[i]); + break; + default:// should never reach here + throw Error('Extension loader error: Type unrecognized!!!'); + } + } + } + + /** + * Listen to an event + * @param {string} name + * @param {function} callback + */ + function listen (name, callback) { + if (!showdown.helper.isString(name)) { + throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given'); + } + + if (typeof callback !== 'function') { + throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given'); + } + + if (!listeners.hasOwnProperty(name)) { + listeners[name] = []; + } + listeners[name].push(callback); + } + + function rTrimInputText (text) { + var rsp = text.match(/^\s*/)[0].length, + rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm'); + return text.replace(rgx, ''); + } + + /** + * Dispatch an event + * @private + * @param {string} evtName Event name + * @param {string} text Text + * @param {{}} options Converter Options + * @param {{}} globals + * @returns {string} + */ + this._dispatch = function dispatch (evtName, text, options, globals) { + if (listeners.hasOwnProperty(evtName)) { + for (var ei = 0; ei < listeners[evtName].length; ++ei) { + var nText = listeners[evtName][ei](evtName, text, this, options, globals); + if (nText && typeof nText !== 'undefined') { + text = nText; + } + } + } + return text; + }; + + /** + * Listen to an event + * @param {string} name + * @param {function} callback + * @returns {showdown.Converter} + */ + this.listen = function (name, callback) { + listen(name, callback); + return this; + }; + + /** + * Converts a markdown string into HTML + * @param {string} text + * @returns {*} + */ + this.makeHtml = function (text) { + //check if text is not falsy + if (!text) { + return text; + } + + var globals = { + gHtmlBlocks: [], + gHtmlMdBlocks: [], + gHtmlSpans: [], + gUrls: {}, + gTitles: {}, + gDimensions: {}, + gListLevel: 0, + hashLinkCounts: {}, + langExtensions: langExtensions, + outputModifiers: outputModifiers, + converter: this, + ghCodeBlocks: [], + metadata: { + parsed: {}, + raw: '', + format: '' + } + }; + + // This lets us use ¨ trema as an escape char to avoid md5 hashes + // The choice of character is arbitrary; anything that isn't + // magic in Markdown will work. + text = text.replace(/¨/g, '¨T'); + + // Replace $ with ¨D + // RegExp interprets $ as a special character + // when it's in a replacement string + text = text.replace(/\$/g, '¨D'); + + // Standardize line endings + text = text.replace(/\r\n/g, '\n'); // DOS to Unix + text = text.replace(/\r/g, '\n'); // Mac to Unix + + // Stardardize line spaces (nbsp causes trouble in older browsers and some regex flavors) + text = text.replace(/\u00A0/g, ' '); + + if (options.smartIndentationFix) { + text = rTrimInputText(text); + } + + // Make sure text begins and ends with a couple of newlines: + text = '\n\n' + text + '\n\n'; + + // detab + text = showdown.subParser('detab')(text, options, globals); + + /** + * Strip any lines consisting only of spaces and tabs. + * This makes subsequent regexs easier to write, because we can + * match consecutive blank lines with /\n+/ instead of something + * contorted like /[ \t]*\n+/ + */ + text = text.replace(/^[ \t]+$/mg, ''); + + //run languageExtensions + showdown.helper.forEach(langExtensions, function (ext) { + text = showdown.subParser('runExtension')(ext, text, options, globals); + }); + + // run the sub parsers + text = showdown.subParser('metadata')(text, options, globals); + text = showdown.subParser('hashPreCodeTags')(text, options, globals); + text = showdown.subParser('githubCodeBlocks')(text, options, globals); + text = showdown.subParser('hashHTMLBlocks')(text, options, globals); + text = showdown.subParser('hashCodeTags')(text, options, globals); + text = showdown.subParser('stripLinkDefinitions')(text, options, globals); + text = showdown.subParser('blockGamut')(text, options, globals); + text = showdown.subParser('unhashHTMLSpans')(text, options, globals); + text = showdown.subParser('unescapeSpecialChars')(text, options, globals); + + // attacklab: Restore dollar signs + text = text.replace(/¨D/g, '$$'); + + // attacklab: Restore tremas + text = text.replace(/¨T/g, '¨'); + + // render a complete html document instead of a partial if the option is enabled + text = showdown.subParser('completeHTMLDocument')(text, options, globals); + + // Run output modifiers + showdown.helper.forEach(outputModifiers, function (ext) { + text = showdown.subParser('runExtension')(ext, text, options, globals); + }); + + // update metadata + metadata = globals.metadata; + return text; + }; + + /** + * Set an option of this Converter instance + * @param {string} key + * @param {*} value + */ + this.setOption = function (key, value) { + options[key] = value; + }; + + /** + * Get the option of this Converter instance + * @param {string} key + * @returns {*} + */ + this.getOption = function (key) { + return options[key]; + }; + + /** + * Get the options of this Converter instance + * @returns {{}} + */ + this.getOptions = function () { + return options; + }; + + /** + * Add extension to THIS converter + * @param {{}} extension + * @param {string} [name=null] + */ + this.addExtension = function (extension, name) { + name = name || null; + _parseExtension(extension, name); + }; + + /** + * Use a global registered extension with THIS converter + * @param {string} extensionName Name of the previously registered extension + */ + this.useExtension = function (extensionName) { + _parseExtension(extensionName); + }; + + /** + * Set the flavor THIS converter should use + * @param {string} name + */ + this.setFlavor = function (name) { + if (!flavor.hasOwnProperty(name)) { + throw Error(name + ' flavor was not found'); + } + var preset = flavor[name]; + setConvFlavor = name; + for (var option in preset) { + if (preset.hasOwnProperty(option)) { + options[option] = preset[option]; + } + } + }; + + /** + * Get the currently set flavor of this converter + * @returns {string} + */ + this.getFlavor = function () { + return setConvFlavor; + }; + + /** + * Remove an extension from THIS converter. + * Note: This is a costly operation. It's better to initialize a new converter + * and specify the extensions you wish to use + * @param {Array} extension + */ + this.removeExtension = function (extension) { + if (!showdown.helper.isArray(extension)) { + extension = [extension]; + } + for (var a = 0; a < extension.length; ++a) { + var ext = extension[a]; + for (var i = 0; i < langExtensions.length; ++i) { + if (langExtensions[i] === ext) { + langExtensions[i].splice(i, 1); + } + } + for (var ii = 0; ii < outputModifiers.length; ++i) { + if (outputModifiers[ii] === ext) { + outputModifiers[ii].splice(i, 1); + } + } + } + }; + + /** + * Get all extension of THIS converter + * @returns {{language: Array, output: Array}} + */ + this.getAllExtensions = function () { + return { + language: langExtensions, + output: outputModifiers + }; + }; + + /** + * Get the metadata of the previously parsed document + * @param raw + * @returns {string|{}} + */ + this.getMetadata = function (raw) { + if (raw) { + return metadata.raw; + } else { + return metadata.parsed; + } + }; + + /** + * Get the metadata format of the previously parsed document + * @returns {string} + */ + this.getMetadataFormat = function () { + return metadata.format; + }; + + /** + * Private: set a single key, value metadata pair + * @param {string} key + * @param {string} value + */ + this._setMetadataPair = function (key, value) { + metadata.parsed[key] = value; + }; + + /** + * Private: set metadata format + * @param {string} format + */ + this._setMetadataFormat = function (format) { + metadata.format = format; + }; + + /** + * Private: set metadata raw text + * @param {string} raw + */ + this._setMetadataRaw = function (raw) { + metadata.raw = raw; + }; +}; + +/** + * Turn Markdown link shortcuts into XHTML tags. + */ +showdown.subParser('anchors', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('anchors.before', text, options, globals); + + var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) { + if (showdown.helper.isUndefined(title)) { + title = ''; + } + linkId = linkId.toLowerCase(); + + // Special case for explicit empty url + if (wholeMatch.search(/\(? ?(['"].*['"])?\)$/m) > -1) { + url = ''; + } else if (!url) { + if (!linkId) { + // lower-case and turn embedded newlines into spaces + linkId = linkText.toLowerCase().replace(/ ?\n/g, ' '); + } + url = '#' + linkId; + + if (!showdown.helper.isUndefined(globals.gUrls[linkId])) { + url = globals.gUrls[linkId]; + if (!showdown.helper.isUndefined(globals.gTitles[linkId])) { + title = globals.gTitles[linkId]; + } + } else { + return wholeMatch; + } + } + + //url = showdown.helper.escapeCharacters(url, '*_', false); // replaced line to improve performance + url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback); + + var result = ''; + + return result; + }; + + // First, handle reference-style links: [link text] [id] + text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag); + + // Next, inline-style links: [link text](url "optional title") + // cases with crazy urls like ./image/cat1).png + text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g, + writeAnchorTag); + + // normal cases + text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]??(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g, + writeAnchorTag); + + // handle reference-style shortcuts: [link text] + // These must come last in case you've also got [link test][1] + // or [link test](/foo) + text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag); + + // Lastly handle GithubMentions if option is enabled + if (options.ghMentions) { + text = text.replace(/(^|\s)(\\)?(@([a-z\d\-]+))(?=[.!?;,[\]()]|\s|$)/gmi, function (wm, st, escape, mentions, username) { + if (escape === '\\') { + return st + mentions; + } + + //check if options.ghMentionsLink is a string + if (!showdown.helper.isString(options.ghMentionsLink)) { + throw new Error('ghMentionsLink option must be a string'); + } + var lnk = options.ghMentionsLink.replace(/\{u}/g, username), + target = ''; + if (options.openLinksInNewWindow) { + target = ' target="¨E95Eblank"'; + } + return st + '' + mentions + ''; + }); + } + + text = globals.converter._dispatch('anchors.after', text, options, globals); + return text; +}); + +// url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-] + +var simpleURLRegex = /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi, + simpleURLRegex2 = /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi, + delimUrlRegex = /()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi, + simpleMailRegex = /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gmi, + delimMailRegex = /<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, + + replaceLink = function (options) { + 'use strict'; + return function (wm, leadingMagicChars, link, m2, m3, trailingPunctuation, trailingMagicChars) { + link = link.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback); + var lnkTxt = link, + append = '', + target = '', + lmc = leadingMagicChars || '', + tmc = trailingMagicChars || ''; + if (/^www\./i.test(link)) { + link = link.replace(/^www\./i, 'http://www.'); + } + if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) { + append = trailingPunctuation; + } + if (options.openLinksInNewWindow) { + target = ' target="¨E95Eblank"'; + } + return lmc + '' + lnkTxt + '' + append + tmc; + }; + }, + + replaceMail = function (options, globals) { + 'use strict'; + return function (wholeMatch, b, mail) { + var href = 'mailto:'; + b = b || ''; + mail = showdown.subParser('unescapeSpecialChars')(mail, options, globals); + if (options.encodeEmails) { + href = showdown.helper.encodeEmailAddress(href + mail); + mail = showdown.helper.encodeEmailAddress(mail); + } else { + href = href + mail; + } + return b + '' + mail + ''; + }; + }; + +showdown.subParser('autoLinks', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('autoLinks.before', text, options, globals); + + text = text.replace(delimUrlRegex, replaceLink(options)); + text = text.replace(delimMailRegex, replaceMail(options, globals)); + + text = globals.converter._dispatch('autoLinks.after', text, options, globals); + + return text; +}); + +showdown.subParser('simplifiedAutoLinks', function (text, options, globals) { + 'use strict'; + + if (!options.simplifiedAutoLink) { + return text; + } + + text = globals.converter._dispatch('simplifiedAutoLinks.before', text, options, globals); + + if (options.excludeTrailingPunctuationFromURLs) { + text = text.replace(simpleURLRegex2, replaceLink(options)); + } else { + text = text.replace(simpleURLRegex, replaceLink(options)); + } + text = text.replace(simpleMailRegex, replaceMail(options, globals)); + + text = globals.converter._dispatch('simplifiedAutoLinks.after', text, options, globals); + + return text; +}); + +/** + * These are all the transformations that form block-level + * tags like paragraphs, headers, and list items. + */ +showdown.subParser('blockGamut', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('blockGamut.before', text, options, globals); + + // we parse blockquotes first so that we can have headings and hrs + // inside blockquotes + text = showdown.subParser('blockQuotes')(text, options, globals); + text = showdown.subParser('headers')(text, options, globals); + + // Do Horizontal Rules: + text = showdown.subParser('horizontalRule')(text, options, globals); + + text = showdown.subParser('lists')(text, options, globals); + text = showdown.subParser('codeBlocks')(text, options, globals); + text = showdown.subParser('tables')(text, options, globals); + + // We already ran _HashHTMLBlocks() before, in Markdown(), but that + // was to escape raw HTML in the original Markdown source. This time, + // we're escaping the markup we've just created, so that we don't wrap + //

      tags around block-level tags. + text = showdown.subParser('hashHTMLBlocks')(text, options, globals); + text = showdown.subParser('paragraphs')(text, options, globals); + + text = globals.converter._dispatch('blockGamut.after', text, options, globals); + + return text; +}); + +showdown.subParser('blockQuotes', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('blockQuotes.before', text, options, globals); + + // add a couple extra lines after the text and endtext mark + text = text + '\n\n'; + + var rgx = /(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm; + + if (options.splitAdjacentBlockquotes) { + rgx = /^ {0,3}>[\s\S]*?(?:\n\n)/gm; + } + + text = text.replace(rgx, function (bq) { + // attacklab: hack around Konqueror 3.5.4 bug: + // "----------bug".replace(/^-/g,"") == "bug" + bq = bq.replace(/^[ \t]*>[ \t]?/gm, ''); // trim one level of quoting + + // attacklab: clean up hack + bq = bq.replace(/¨0/g, ''); + + bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines + bq = showdown.subParser('githubCodeBlocks')(bq, options, globals); + bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse + + bq = bq.replace(/(^|\n)/g, '$1 '); + // These leading spaces screw with

       content, so we need to fix that:
      +    bq = bq.replace(/(\s*
      [^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
      +      var pre = m1;
      +      // attacklab: hack around Konqueror 3.5.4 bug:
      +      pre = pre.replace(/^  /mg, '¨0');
      +      pre = pre.replace(/¨0/g, '');
      +      return pre;
      +    });
      +
      +    return showdown.subParser('hashBlock')('
      \n' + bq + '\n
      ', options, globals); + }); + + text = globals.converter._dispatch('blockQuotes.after', text, options, globals); + return text; +}); + +/** + * Process Markdown `
      ` blocks.
      + */
      +showdown.subParser('codeBlocks', function (text, options, globals) {
      +  'use strict';
      +
      +  text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
      +
      +  // sentinel workarounds for lack of \A and \Z, safari\khtml bug
      +  text += '¨0';
      +
      +  var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g;
      +  text = text.replace(pattern, function (wholeMatch, m1, m2) {
      +    var codeblock = m1,
      +        nextChar = m2,
      +        end = '\n';
      +
      +    codeblock = showdown.subParser('outdent')(codeblock, options, globals);
      +    codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
      +    codeblock = showdown.subParser('detab')(codeblock, options, globals);
      +    codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
      +    codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
      +
      +    if (options.omitExtraWLInCodeBlocks) {
      +      end = '';
      +    }
      +
      +    codeblock = '
      ' + codeblock + end + '
      '; + + return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar; + }); + + // strip sentinel + text = text.replace(/¨0/, ''); + + text = globals.converter._dispatch('codeBlocks.after', text, options, globals); + return text; +}); + +/** + * + * * Backtick quotes are used for spans. + * + * * You can use multiple backticks as the delimiters if you want to + * include literal backticks in the code span. So, this input: + * + * Just type ``foo `bar` baz`` at the prompt. + * + * Will translate to: + * + *

      Just type foo `bar` baz at the prompt.

      + * + * There's no arbitrary limit to the number of backticks you + * can use as delimters. If you need three consecutive backticks + * in your code, use four for delimiters, etc. + * + * * You can use spaces to get literal backticks at the edges: + * + * ... type `` `bar` `` ... + * + * Turns to: + * + * ... type `bar` ... + */ +showdown.subParser('codeSpans', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('codeSpans.before', text, options, globals); + + if (typeof(text) === 'undefined') { + text = ''; + } + text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, + function (wholeMatch, m1, m2, m3) { + var c = m3; + c = c.replace(/^([ \t]*)/g, ''); // leading whitespace + c = c.replace(/[ \t]*$/g, ''); // trailing whitespace + c = showdown.subParser('encodeCode')(c, options, globals); + c = m1 + '' + c + ''; + c = showdown.subParser('hashHTMLSpans')(c, options, globals); + return c; + } + ); + + text = globals.converter._dispatch('codeSpans.after', text, options, globals); + return text; +}); + +/** + * Turn Markdown link shortcuts into XHTML tags. + */ +showdown.subParser('completeHTMLDocument', function (text, options, globals) { + 'use strict'; + + if (!options.completeHTMLDocument) { + return text; + } + + text = globals.converter._dispatch('completeHTMLDocument.before', text, options, globals); + + var doctype = 'html', + doctypeParsed = '\n', + title = '', + charset = '\n', + lang = '', + metadata = ''; + + if (typeof globals.metadata.parsed.doctype !== 'undefined') { + doctypeParsed = '\n'; + doctype = globals.metadata.parsed.doctype.toString().toLowerCase(); + if (doctype === 'html' || doctype === 'html5') { + charset = ''; + } + } + + for (var meta in globals.metadata.parsed) { + if (globals.metadata.parsed.hasOwnProperty(meta)) { + switch (meta.toLowerCase()) { + case 'doctype': + break; + + case 'title': + title = '' + globals.metadata.parsed.title + '\n'; + break; + + case 'charset': + if (doctype === 'html' || doctype === 'html5') { + charset = '\n'; + } else { + charset = '\n'; + } + break; + + case 'language': + case 'lang': + lang = ' lang="' + globals.metadata.parsed[meta] + '"'; + metadata += '\n'; + break; + + default: + metadata += '\n'; + } + } + } + + text = doctypeParsed + '\n\n' + title + charset + metadata + '\n\n' + text.trim() + '\n\n'; + + text = globals.converter._dispatch('completeHTMLDocument.after', text, options, globals); + return text; +}); + +/** + * Convert all tabs to spaces + */ +showdown.subParser('detab', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('detab.before', text, options, globals); + + // expand first n-1 tabs + text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width + + // replace the nth with two sentinels + text = text.replace(/\t/g, '¨A¨B'); + + // use the sentinel to anchor our regex so it doesn't explode + text = text.replace(/¨B(.+?)¨A/g, function (wholeMatch, m1) { + var leadingText = m1, + numSpaces = 4 - leadingText.length % 4; // g_tab_width + + // there *must* be a better way to do this: + for (var i = 0; i < numSpaces; i++) { + leadingText += ' '; + } + + return leadingText; + }); + + // clean up sentinels + text = text.replace(/¨A/g, ' '); // g_tab_width + text = text.replace(/¨B/g, ''); + + text = globals.converter._dispatch('detab.after', text, options, globals); + return text; +}); + +showdown.subParser('ellipsis', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('ellipsis.before', text, options, globals); + + text = text.replace(/\.\.\./g, '…'); + + text = globals.converter._dispatch('ellipsis.after', text, options, globals); + + return text; +}); + +/** + * These are all the transformations that occur *within* block-level + * tags like paragraphs, headers, and list items. + */ +showdown.subParser('emoji', function (text, options, globals) { + 'use strict'; + + if (!options.emoji) { + return text; + } + + text = globals.converter._dispatch('emoji.before', text, options, globals); + + var emojiRgx = /:([\S]+?):/g; + + text = text.replace(emojiRgx, function (wm, emojiCode) { + if (showdown.helper.emojis.hasOwnProperty(emojiCode)) { + return showdown.helper.emojis[emojiCode]; + } + return wm; + }); + + text = globals.converter._dispatch('emoji.after', text, options, globals); + + return text; +}); + +/** + * Smart processing for ampersands and angle brackets that need to be encoded. + */ +showdown.subParser('encodeAmpsAndAngles', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('encodeAmpsAndAngles.before', text, options, globals); + + // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: + // http://bumppo.net/projects/amputator/ + text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&'); + + // Encode naked <'s + text = text.replace(/<(?![a-z\/?$!])/gi, '<'); + + // Encode < + text = text.replace(/ + text = text.replace(/>/g, '>'); + + text = globals.converter._dispatch('encodeAmpsAndAngles.after', text, options, globals); + return text; +}); + +/** + * Returns the string, with after processing the following backslash escape sequences. + * + * attacklab: The polite way to do this is with the new escapeCharacters() function: + * + * text = escapeCharacters(text,"\\",true); + * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); + * + * ...but we're sidestepping its use of the (slow) RegExp constructor + * as an optimization for Firefox. This function gets called a LOT. + */ +showdown.subParser('encodeBackslashEscapes', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('encodeBackslashEscapes.before', text, options, globals); + + text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback); + text = text.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g, showdown.helper.escapeCharactersCallback); + + text = globals.converter._dispatch('encodeBackslashEscapes.after', text, options, globals); + return text; +}); + +/** + * Encode/escape certain characters inside Markdown code runs. + * The point is that in code, these characters are literals, + * and lose their special Markdown meanings. + */ +showdown.subParser('encodeCode', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('encodeCode.before', text, options, globals); + + // Encode all ampersands; HTML entities are not + // entities within a Markdown code span. + text = text + .replace(/&/g, '&') + // Do the angle bracket song and dance: + .replace(//g, '>') + // Now, escape characters that are magic in Markdown: + .replace(/([*_{}\[\]\\=~-])/g, showdown.helper.escapeCharactersCallback); + + text = globals.converter._dispatch('encodeCode.after', text, options, globals); + return text; +}); + +/** + * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they + * don't conflict with their use in Markdown for code, italics and strong. + */ +showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.before', text, options, globals); + + // Build a regex to find HTML tags. + var tags = /<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi, + comments = /-]|-[^>])(?:[^-]|-[^-])*)--)>/gi; + + text = text.replace(tags, function (wholeMatch) { + return wholeMatch + .replace(/(.)<\/?code>(?=.)/g, '$1`') + .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback); + }); + + text = text.replace(comments, function (wholeMatch) { + return wholeMatch + .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback); + }); + + text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.after', text, options, globals); + return text; +}); + +/** + * Handle github codeblocks prior to running HashHTML so that + * HTML contained within the codeblock gets escaped properly + * Example: + * ```ruby + * def hello_world(x) + * puts "Hello, #{x}" + * end + * ``` + */ +showdown.subParser('githubCodeBlocks', function (text, options, globals) { + 'use strict'; + + // early exit if option is not enabled + if (!options.ghCodeBlocks) { + return text; + } + + text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals); + + text += '¨0'; + + text = text.replace(/(?:^|\n)(```+|~~~+)([^\s`~]*)\n([\s\S]*?)\n\1/g, function (wholeMatch, delim, language, codeblock) { + var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n'; + + // First parse the github code block + codeblock = showdown.subParser('encodeCode')(codeblock, options, globals); + codeblock = showdown.subParser('detab')(codeblock, options, globals); + codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines + codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace + + codeblock = '
      ' + codeblock + end + '
      '; + + codeblock = showdown.subParser('hashBlock')(codeblock, options, globals); + + // Since GHCodeblocks can be false positives, we need to + // store the primitive text and the parsed text in a global var, + // and then return a token + return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n'; + }); + + // attacklab: strip sentinel + text = text.replace(/¨0/, ''); + + return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals); +}); + +showdown.subParser('hashBlock', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashBlock.before', text, options, globals); + text = text.replace(/(^\n+|\n+$)/g, ''); + text = '\n\n¨K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n'; + text = globals.converter._dispatch('hashBlock.after', text, options, globals); + return text; +}); + +/** + * Hash and escape elements that should not be parsed as markdown + */ +showdown.subParser('hashCodeTags', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashCodeTags.before', text, options, globals); + + var repFunc = function (wholeMatch, match, left, right) { + var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right; + return '¨C' + (globals.gHtmlSpans.push(codeblock) - 1) + 'C'; + }; + + // Hash naked + text = showdown.helper.replaceRecursiveRegExp(text, repFunc, ']*>', '', 'gim'); + + text = globals.converter._dispatch('hashCodeTags.after', text, options, globals); + return text; +}); + +showdown.subParser('hashElement', function (text, options, globals) { + 'use strict'; + + return function (wholeMatch, m1) { + var blockText = m1; + + // Undo double lines + blockText = blockText.replace(/\n\n/g, '\n'); + blockText = blockText.replace(/^\n/, ''); + + // strip trailing blank lines + blockText = blockText.replace(/\n+$/g, ''); + + // Replace the element text with a marker ("¨KxK" where x is its key) + blockText = '\n\n¨K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n'; + + return blockText; + }; +}); + +showdown.subParser('hashHTMLBlocks', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashHTMLBlocks.before', text, options, globals); + + var blockTags = [ + 'pre', + 'div', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'blockquote', + 'table', + 'dl', + 'ol', + 'ul', + 'script', + 'noscript', + 'form', + 'fieldset', + 'iframe', + 'math', + 'style', + 'section', + 'header', + 'footer', + 'nav', + 'article', + 'aside', + 'address', + 'audio', + 'canvas', + 'figure', + 'hgroup', + 'output', + 'video', + 'p' + ], + repFunc = function (wholeMatch, match, left, right) { + var txt = wholeMatch; + // check if this html element is marked as markdown + // if so, it's contents should be parsed as markdown + if (left.search(/\bmarkdown\b/) !== -1) { + txt = left + globals.converter.makeHtml(match) + right; + } + return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n'; + }; + + if (options.backslashEscapesHTMLTags) { + // encode backslash escaped HTML tags + text = text.replace(/\\<(\/?[^>]+?)>/g, function (wm, inside) { + return '<' + inside + '>'; + }); + } + + // hash HTML Blocks + for (var i = 0; i < blockTags.length; ++i) { + + var opTagPos, + rgx1 = new RegExp('^ {0,3}(<' + blockTags[i] + '\\b[^>]*>)', 'im'), + patLeft = '<' + blockTags[i] + '\\b[^>]*>', + patRight = ''; + // 1. Look for the first position of the first opening HTML tag in the text + while ((opTagPos = showdown.helper.regexIndexOf(text, rgx1)) !== -1) { + + // if the HTML tag is \ escaped, we need to escape it and break + + + //2. Split the text in that position + var subTexts = showdown.helper.splitAtIndex(text, opTagPos), + //3. Match recursively + newSubText1 = showdown.helper.replaceRecursiveRegExp(subTexts[1], repFunc, patLeft, patRight, 'im'); + + // prevent an infinite loop + if (newSubText1 === subTexts[1]) { + break; + } + text = subTexts[0].concat(newSubText1); + } + } + // HR SPECIAL CASE + text = text.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, + showdown.subParser('hashElement')(text, options, globals)); + + // Special case for standalone HTML comments + text = showdown.helper.replaceRecursiveRegExp(text, function (txt) { + return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n'; + }, '^ {0,3}', 'gm'); + + // PHP and ASP-style processor instructions ( and <%...%>) + text = text.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, + showdown.subParser('hashElement')(text, options, globals)); + + text = globals.converter._dispatch('hashHTMLBlocks.after', text, options, globals); + return text; +}); + +/** + * Hash span elements that should not be parsed as markdown + */ +showdown.subParser('hashHTMLSpans', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('hashHTMLSpans.before', text, options, globals); + + function hashHTMLSpan (html) { + return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C'; + } + + // Hash Self Closing tags + text = text.replace(/<[^>]+?\/>/gi, function (wm) { + return hashHTMLSpan(wm); + }); + + // Hash tags without properties + text = text.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g, function (wm) { + return hashHTMLSpan(wm); + }); + + // Hash tags with properties + text = text.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g, function (wm) { + return hashHTMLSpan(wm); + }); + + // Hash self closing tags without /> + text = text.replace(/<[^>]+?>/gi, function (wm) { + return hashHTMLSpan(wm); + }); + + /*showdown.helper.matchRecursiveRegExp(text, ']*>', '', 'gi');*/ + + text = globals.converter._dispatch('hashHTMLSpans.after', text, options, globals); + return text; +}); + +/** + * Unhash HTML spans + */ +showdown.subParser('unhashHTMLSpans', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('unhashHTMLSpans.before', text, options, globals); + + for (var i = 0; i < globals.gHtmlSpans.length; ++i) { + var repText = globals.gHtmlSpans[i], + // limiter to prevent infinite loop (assume 10 as limit for recurse) + limit = 0; + + while (/¨C(\d+)C/.test(repText)) { + var num = RegExp.$1; + repText = repText.replace('¨C' + num + 'C', globals.gHtmlSpans[num]); + if (limit === 10) { + console.error('maximum nesting of 10 spans reached!!!'); + break; + } + ++limit; + } + text = text.replace('¨C' + i + 'C', repText); + } + + text = globals.converter._dispatch('unhashHTMLSpans.after', text, options, globals); + return text; +}); + +/** + * Hash and escape
       elements that should not be parsed as markdown
      + */
      +showdown.subParser('hashPreCodeTags', function (text, options, globals) {
      +  'use strict';
      +  text = globals.converter._dispatch('hashPreCodeTags.before', text, options, globals);
      +
      +  var repFunc = function (wholeMatch, match, left, right) {
      +    // encode html entities
      +    var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;
      +    return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
      +  };
      +
      +  // Hash 
      
      +  text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^ {0,3}]*>\\s*]*>', '^ {0,3}\\s*
      ', 'gim'); + + text = globals.converter._dispatch('hashPreCodeTags.after', text, options, globals); + return text; +}); + +showdown.subParser('headers', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('headers.before', text, options, globals); + + var headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart), + + // Set text-style headers: + // Header 1 + // ======== + // + // Header 2 + // -------- + // + setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm, + setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm; + + text = text.replace(setextRegexH1, function (wholeMatch, m1) { + + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', + hLevel = headerLevelStart, + hashBlock = '' + spanGamut + ''; + return showdown.subParser('hashBlock')(hashBlock, options, globals); + }); + + text = text.replace(setextRegexH2, function (matchFound, m1) { + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', + hLevel = headerLevelStart + 1, + hashBlock = '' + spanGamut + ''; + return showdown.subParser('hashBlock')(hashBlock, options, globals); + }); + + // atx-style headers: + // # Header 1 + // ## Header 2 + // ## Header 2 with closing hashes ## + // ... + // ###### Header 6 + // + var atxStyle = (options.requireSpaceBeforeHeadingText) ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm; + + text = text.replace(atxStyle, function (wholeMatch, m1, m2) { + var hText = m2; + if (options.customizedHeaderId) { + hText = m2.replace(/\s?\{([^{]+?)}\s*$/, ''); + } + + var span = showdown.subParser('spanGamut')(hText, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"', + hLevel = headerLevelStart - 1 + m1.length, + header = '' + span + ''; + + return showdown.subParser('hashBlock')(header, options, globals); + }); + + function headerId (m) { + var title, + prefix; + + // It is separate from other options to allow combining prefix and customized + if (options.customizedHeaderId) { + var match = m.match(/\{([^{]+?)}\s*$/); + if (match && match[1]) { + m = match[1]; + } + } + + title = m; + + // Prefix id to prevent causing inadvertent pre-existing style matches. + if (showdown.helper.isString(options.prefixHeaderId)) { + prefix = options.prefixHeaderId; + } else if (options.prefixHeaderId === true) { + prefix = 'section-'; + } else { + prefix = ''; + } + + if (!options.rawPrefixHeaderId) { + title = prefix + title; + } + + if (options.ghCompatibleHeaderId) { + title = title + .replace(/ /g, '-') + // replace previously escaped chars (&, ¨ and $) + .replace(/&/g, '') + .replace(/¨T/g, '') + .replace(/¨D/g, '') + // replace rest of the chars (&~$ are repeated as they might have been escaped) + // borrowed from github's redcarpet (some they should produce similar results) + .replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, '') + .toLowerCase(); + } else if (options.rawHeaderId) { + title = title + .replace(/ /g, '-') + // replace previously escaped chars (&, ¨ and $) + .replace(/&/g, '&') + .replace(/¨T/g, '¨') + .replace(/¨D/g, '$') + // replace " and ' + .replace(/["']/g, '-') + .toLowerCase(); + } else { + title = title + .replace(/[^\w]/g, '') + .toLowerCase(); + } + + if (options.rawPrefixHeaderId) { + title = prefix + title; + } + + if (globals.hashLinkCounts[title]) { + title = title + '-' + (globals.hashLinkCounts[title]++); + } else { + globals.hashLinkCounts[title] = 1; + } + return title; + } + + text = globals.converter._dispatch('headers.after', text, options, globals); + return text; +}); + +/** + * Turn Markdown link shortcuts into XHTML
      tags. + */ +showdown.subParser('horizontalRule', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('horizontalRule.before', text, options, globals); + + var key = showdown.subParser('hashBlock')('
      ', options, globals); + text = text.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm, key); + text = text.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm, key); + text = text.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm, key); + + text = globals.converter._dispatch('horizontalRule.after', text, options, globals); + return text; +}); + +/** + * Turn Markdown image shortcuts into tags. + */ +showdown.subParser('images', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('images.before', text, options, globals); + + var inlineRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g, + crazyRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g, + base64RegExp = /!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g, + referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g, + refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g; + + function writeImageTagBase64 (wholeMatch, altText, linkId, url, width, height, m5, title) { + url = url.replace(/\s/g, ''); + return writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title); + } + + function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) { + + var gUrls = globals.gUrls, + gTitles = globals.gTitles, + gDims = globals.gDimensions; + + linkId = linkId.toLowerCase(); + + if (!title) { + title = ''; + } + // Special case for explicit empty url + if (wholeMatch.search(/\(? ?(['"].*['"])?\)$/m) > -1) { + url = ''; + + } else if (url === '' || url === null) { + if (linkId === '' || linkId === null) { + // lower-case and turn embedded newlines into spaces + linkId = altText.toLowerCase().replace(/ ?\n/g, ' '); + } + url = '#' + linkId; + + if (!showdown.helper.isUndefined(gUrls[linkId])) { + url = gUrls[linkId]; + if (!showdown.helper.isUndefined(gTitles[linkId])) { + title = gTitles[linkId]; + } + if (!showdown.helper.isUndefined(gDims[linkId])) { + width = gDims[linkId].width; + height = gDims[linkId].height; + } + } else { + return wholeMatch; + } + } + + altText = altText + .replace(/"/g, '"') + //altText = showdown.helper.escapeCharacters(altText, '*_', false); + .replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback); + //url = showdown.helper.escapeCharacters(url, '*_', false); + url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback); + var result = '' + altText + 'x "optional title") + + // base64 encoded images + text = text.replace(base64RegExp, writeImageTagBase64); + + // cases with crazy urls like ./image/cat1).png + text = text.replace(crazyRegExp, writeImageTag); + + // normal cases + text = text.replace(inlineRegExp, writeImageTag); + + // handle reference-style shortcuts: ![img text] + text = text.replace(refShortcutRegExp, writeImageTag); + + text = globals.converter._dispatch('images.after', text, options, globals); + return text; +}); + +showdown.subParser('italicsAndBold', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('italicsAndBold.before', text, options, globals); + + // it's faster to have 3 separate regexes for each case than have just one + // because of backtracing, in some cases, it could lead to an exponential effect + // called "catastrophic backtrace". Ominous! + + function parseInside (txt, left, right) { + /* + if (options.simplifiedAutoLink) { + txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals); + } + */ + return left + txt + right; + } + + // Parse underscores + if (options.literalMidWordUnderscores) { + text = text.replace(/\b___(\S[\s\S]*)___\b/g, function (wm, txt) { + return parseInside (txt, '', ''); + }); + text = text.replace(/\b__(\S[\s\S]*)__\b/g, function (wm, txt) { + return parseInside (txt, '', ''); + }); + text = text.replace(/\b_(\S[\s\S]*?)_\b/g, function (wm, txt) { + return parseInside (txt, '', ''); + }); + } else { + text = text.replace(/___(\S[\s\S]*?)___/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/__(\S[\s\S]*?)__/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/_([^\s_][\s\S]*?)_/g, function (wm, m) { + // !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it) + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + } + + // Now parse asterisks + if (options.literalMidWordAsterisks) { + text = text.replace(/([^*]|^)\B\*\*\*(\S[\s\S]+?)\*\*\*\B(?!\*)/g, function (wm, lead, txt) { + return parseInside (txt, lead + '', ''); + }); + text = text.replace(/([^*]|^)\B\*\*(\S[\s\S]+?)\*\*\B(?!\*)/g, function (wm, lead, txt) { + return parseInside (txt, lead + '', ''); + }); + text = text.replace(/([^*]|^)\B\*(\S[\s\S]+?)\*\B(?!\*)/g, function (wm, lead, txt) { + return parseInside (txt, lead + '', ''); + }); + } else { + text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) { + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) { + // !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it) + return (/\S$/.test(m)) ? parseInside (m, '', '') : wm; + }); + } + + + text = globals.converter._dispatch('italicsAndBold.after', text, options, globals); + return text; +}); + +/** + * Form HTML ordered (numbered) and unordered (bulleted) lists. + */ +showdown.subParser('lists', function (text, options, globals) { + 'use strict'; + + /** + * Process the contents of a single ordered or unordered list, splitting it + * into individual list items. + * @param {string} listStr + * @param {boolean} trimTrailing + * @returns {string} + */ + function processListItems (listStr, trimTrailing) { + // The $g_list_level global keeps track of when we're inside a list. + // Each time we enter a list, we increment it; when we leave a list, + // we decrement. If it's zero, we're not in a list anymore. + // + // We do this because when we're not inside a list, we want to treat + // something like this: + // + // I recommend upgrading to version + // 8. Oops, now this line is treated + // as a sub-list. + // + // As a single paragraph, despite the fact that the second line starts + // with a digit-period-space sequence. + // + // Whereas when we're inside a list (or sub-list), that line will be + // treated as the start of a sub-list. What a kludge, huh? This is + // an aspect of Markdown's syntax that's hard to parse perfectly + // without resorting to mind-reading. Perhaps the solution is to + // change the syntax rules such that sub-lists must start with a + // starting cardinal number; e.g. "1." or "a.". + globals.gListLevel++; + + // trim trailing blank lines: + listStr = listStr.replace(/\n{2,}$/, '\n'); + + // attacklab: add sentinel to emulate \z + listStr += '¨0'; + + var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm, + isParagraphed = (/\n[ \t]*\n(?!¨0)/.test(listStr)); + + // Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation, + // which is a syntax breaking change + // activating this option reverts to old behavior + if (options.disableForced4SpacesIndentedSublists) { + rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm; + } + + listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) { + checked = (checked && checked.trim() !== ''); + + var item = showdown.subParser('outdent')(m4, options, globals), + bulletStyle = ''; + + // Support for github tasklists + if (taskbtn && options.tasklists) { + bulletStyle = ' class="task-list-item" style="list-style-type: none;"'; + item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () { + var otp = '
    • a
    • + // instead of: + //
      • - - a
      + // So, to prevent it, we will put a marker (¨A)in the beginning of the line + // Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser + item = item.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g, function (wm2) { + return '¨A' + wm2; + }); + + // m1 - Leading line or + // Has a double return (multi paragraph) or + // Has sublist + if (m1 || (item.search(/\n{2,}/) > -1)) { + item = showdown.subParser('githubCodeBlocks')(item, options, globals); + item = showdown.subParser('blockGamut')(item, options, globals); + } else { + // Recursion for sub-lists: + item = showdown.subParser('lists')(item, options, globals); + item = item.replace(/\n$/, ''); // chomp(item) + item = showdown.subParser('hashHTMLBlocks')(item, options, globals); + + // Colapse double linebreaks + item = item.replace(/\n\n+/g, '\n\n'); + if (isParagraphed) { + item = showdown.subParser('paragraphs')(item, options, globals); + } else { + item = showdown.subParser('spanGamut')(item, options, globals); + } + } + + // now we need to remove the marker (¨A) + item = item.replace('¨A', ''); + // we can finally wrap the line in list item tags + item = '' + item + '\n'; + + return item; + }); + + // attacklab: strip sentinel + listStr = listStr.replace(/¨0/g, ''); + + globals.gListLevel--; + + if (trimTrailing) { + listStr = listStr.replace(/\s+$/, ''); + } + + return listStr; + } + + function styleStartNumber (list, listType) { + // check if ol and starts by a number different than 1 + if (listType === 'ol') { + var res = list.match(/^ *(\d+)\./); + if (res && res[1] !== '1') { + return ' start="' + res[1] + '"'; + } + } + return ''; + } + + /** + * Check and parse consecutive lists (better fix for issue #142) + * @param {string} list + * @param {string} listType + * @param {boolean} trimTrailing + * @returns {string} + */ + function parseConsecutiveLists (list, listType, trimTrailing) { + // check if we caught 2 or more consecutive lists by mistake + // we use the counterRgx, meaning if listType is UL we look for OL and vice versa + var olRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?\d+\.[ \t]/gm : /^ {0,3}\d+\.[ \t]/gm, + ulRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?[*+-][ \t]/gm : /^ {0,3}[*+-][ \t]/gm, + counterRxg = (listType === 'ul') ? olRgx : ulRgx, + result = ''; + + if (list.search(counterRxg) !== -1) { + (function parseCL (txt) { + var pos = txt.search(counterRxg), + style = styleStartNumber(list, listType); + if (pos !== -1) { + // slice + result += '\n\n<' + listType + style + '>\n' + processListItems(txt.slice(0, pos), !!trimTrailing) + '\n'; + + // invert counterType and listType + listType = (listType === 'ul') ? 'ol' : 'ul'; + counterRxg = (listType === 'ul') ? olRgx : ulRgx; + + //recurse + parseCL(txt.slice(pos)); + } else { + result += '\n\n<' + listType + style + '>\n' + processListItems(txt, !!trimTrailing) + '\n'; + } + })(list); + } else { + var style = styleStartNumber(list, listType); + result = '\n\n<' + listType + style + '>\n' + processListItems(list, !!trimTrailing) + '\n'; + } + + return result; + } + + /** Start of list parsing **/ + text = globals.converter._dispatch('lists.before', text, options, globals); + // add sentinel to hack around khtml/safari bug: + // http://bugs.webkit.org/show_bug.cgi?id=11231 + text += '¨0'; + + if (globals.gListLevel) { + text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm, + function (wholeMatch, list, m2) { + var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; + return parseConsecutiveLists(list, listType, true); + } + ); + } else { + text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm, + function (wholeMatch, m1, list, m3) { + var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; + return parseConsecutiveLists(list, listType, false); + } + ); + } + + // strip sentinel + text = text.replace(/¨0/, ''); + text = globals.converter._dispatch('lists.after', text, options, globals); + return text; +}); + +/** + * Parse metadata at the top of the document + */ +showdown.subParser('metadata', function (text, options, globals) { + 'use strict'; + + if (!options.metadata) { + return text; + } + + text = globals.converter._dispatch('metadata.before', text, options, globals); + + function parseMetadataContents (content) { + // raw is raw so it's not changed in any way + globals.metadata.raw = content; + + // escape chars forbidden in html attributes + // double quotes + content = content + // ampersand first + .replace(/&/g, '&') + // double quotes + .replace(/"/g, '"'); + + content = content.replace(/\n {4}/g, ' '); + content.replace(/^([\S ]+): +([\s\S]+?)$/gm, function (wm, key, value) { + globals.metadata.parsed[key] = value; + return ''; + }); + } + + text = text.replace(/^\s*«««+(\S*?)\n([\s\S]+?)\n»»»+\n/, function (wholematch, format, content) { + parseMetadataContents(content); + return '¨M'; + }); + + text = text.replace(/^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/, function (wholematch, format, content) { + if (format) { + globals.metadata.format = format; + } + parseMetadataContents(content); + return '¨M'; + }); + + text = text.replace(/¨M/g, ''); + + text = globals.converter._dispatch('metadata.after', text, options, globals); + return text; +}); + +/** + * Remove one level of line-leading tabs or spaces + */ +showdown.subParser('outdent', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('outdent.before', text, options, globals); + + // attacklab: hack around Konqueror 3.5.4 bug: + // "----------bug".replace(/^-/g,"") == "bug" + text = text.replace(/^(\t|[ ]{1,4})/gm, '¨0'); // attacklab: g_tab_width + + // attacklab: clean up hack + text = text.replace(/¨0/g, ''); + + text = globals.converter._dispatch('outdent.after', text, options, globals); + return text; +}); + +/** + * + */ +showdown.subParser('paragraphs', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('paragraphs.before', text, options, globals); + // Strip leading and trailing lines: + text = text.replace(/^\n+/g, ''); + text = text.replace(/\n+$/g, ''); + + var grafs = text.split(/\n{2,}/g), + grafsOut = [], + end = grafs.length; // Wrap

      tags + + for (var i = 0; i < end; i++) { + var str = grafs[i]; + // if this is an HTML marker, copy it + if (str.search(/¨(K|G)(\d+)\1/g) >= 0) { + grafsOut.push(str); + + // test for presence of characters to prevent empty lines being parsed + // as paragraphs (resulting in undesired extra empty paragraphs) + } else if (str.search(/\S/) >= 0) { + str = showdown.subParser('spanGamut')(str, options, globals); + str = str.replace(/^([ \t]*)/g, '

      '); + str += '

      '; + grafsOut.push(str); + } + } + + /** Unhashify HTML blocks */ + end = grafsOut.length; + for (i = 0; i < end; i++) { + var blockText = '', + grafsOutIt = grafsOut[i], + codeFlag = false; + // if this is a marker for an html block... + // use RegExp.test instead of string.search because of QML bug + while (/¨(K|G)(\d+)\1/.test(grafsOutIt)) { + var delim = RegExp.$1, + num = RegExp.$2; + + if (delim === 'K') { + blockText = globals.gHtmlBlocks[num]; + } else { + // we need to check if ghBlock is a false positive + if (codeFlag) { + // use encoded version of all text + blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text, options, globals); + } else { + blockText = globals.ghCodeBlocks[num].codeblock; + } + } + blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs + + grafsOutIt = grafsOutIt.replace(/(\n\n)?¨(K|G)\d+\2(\n\n)?/, blockText); + // Check if grafsOutIt is a pre->code + if (/^]*>\s*]*>/.test(grafsOutIt)) { + codeFlag = true; + } + } + grafsOut[i] = grafsOutIt; + } + text = grafsOut.join('\n'); + // Strip leading and trailing lines: + text = text.replace(/^\n+/g, ''); + text = text.replace(/\n+$/g, ''); + return globals.converter._dispatch('paragraphs.after', text, options, globals); +}); + +/** + * Run extension + */ +showdown.subParser('runExtension', function (ext, text, options, globals) { + 'use strict'; + + if (ext.filter) { + text = ext.filter(text, globals.converter, options); + + } else if (ext.regex) { + // TODO remove this when old extension loading mechanism is deprecated + var re = ext.regex; + if (!(re instanceof RegExp)) { + re = new RegExp(re, 'g'); + } + text = text.replace(re, ext.replace); + } + + return text; +}); + +/** + * These are all the transformations that occur *within* block-level + * tags like paragraphs, headers, and list items. + */ +showdown.subParser('spanGamut', function (text, options, globals) { + 'use strict'; + + text = globals.converter._dispatch('spanGamut.before', text, options, globals); + text = showdown.subParser('codeSpans')(text, options, globals); + text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals); + text = showdown.subParser('encodeBackslashEscapes')(text, options, globals); + + // Process anchor and image tags. Images must come first, + // because ![foo][f] looks like an anchor. + text = showdown.subParser('images')(text, options, globals); + text = showdown.subParser('anchors')(text, options, globals); + + // Make links out of things like `` + // Must come after anchors, because you can use < and > + // delimiters in inline links like [this](). + text = showdown.subParser('autoLinks')(text, options, globals); + text = showdown.subParser('simplifiedAutoLinks')(text, options, globals); + text = showdown.subParser('emoji')(text, options, globals); + text = showdown.subParser('underline')(text, options, globals); + text = showdown.subParser('italicsAndBold')(text, options, globals); + text = showdown.subParser('strikethrough')(text, options, globals); + text = showdown.subParser('ellipsis')(text, options, globals); + + // we need to hash HTML tags inside spans + text = showdown.subParser('hashHTMLSpans')(text, options, globals); + + // now we encode amps and angles + text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals); + + // Do hard breaks + if (options.simpleLineBreaks) { + // GFM style hard breaks + // only add line breaks if the text does not contain a block (special case for lists) + if (!/\n\n¨K/.test(text)) { + text = text.replace(/\n+/g, '
      \n'); + } + } else { + // Vanilla hard breaks + text = text.replace(/ +\n/g, '
      \n'); + } + + text = globals.converter._dispatch('spanGamut.after', text, options, globals); + return text; +}); + +showdown.subParser('strikethrough', function (text, options, globals) { + 'use strict'; + + function parseInside (txt) { + if (options.simplifiedAutoLink) { + txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals); + } + return '' + txt + ''; + } + + if (options.strikethrough) { + text = globals.converter._dispatch('strikethrough.before', text, options, globals); + text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) { return parseInside(txt); }); + text = globals.converter._dispatch('strikethrough.after', text, options, globals); + } + + return text; +}); + +/** + * Strips link definitions from text, stores the URLs and titles in + * hash references. + * Link defs are in the form: ^[id]: url "optional title" + */ +showdown.subParser('stripLinkDefinitions', function (text, options, globals) { + 'use strict'; + + var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm, + base64Regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm; + + // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug + text += '¨0'; + + var replaceFunc = function (wholeMatch, linkId, url, width, height, blankLines, title) { + linkId = linkId.toLowerCase(); + if (url.match(/^data:.+?\/.+?;base64,/)) { + // remove newlines + globals.gUrls[linkId] = url.replace(/\s/g, ''); + } else { + globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url, options, globals); // Link IDs are case-insensitive + } + + if (blankLines) { + // Oops, found blank lines, so it's not a title. + // Put back the parenthetical statement we stole. + return blankLines + title; + + } else { + if (title) { + globals.gTitles[linkId] = title.replace(/"|'/g, '"'); + } + if (options.parseImgDimensions && width && height) { + globals.gDimensions[linkId] = { + width: width, + height: height + }; + } + } + // Completely remove the definition from the text + return ''; + }; + + // first we try to find base64 link references + text = text.replace(base64Regex, replaceFunc); + + text = text.replace(regex, replaceFunc); + + // attacklab: strip sentinel + text = text.replace(/¨0/, ''); + + return text; +}); + +showdown.subParser('tables', function (text, options, globals) { + 'use strict'; + + if (!options.tables) { + return text; + } + + var tableRgx = /^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|¨0)/gm, + //singeColTblRgx = /^ {0,3}\|.+\|\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n(?: {0,3}\|.+\|\n)+(?:\n\n|¨0)/gm; + singeColTblRgx = /^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm; + + function parseStyles (sLine) { + if (/^:[ \t]*--*$/.test(sLine)) { + return ' style="text-align:left;"'; + } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) { + return ' style="text-align:right;"'; + } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) { + return ' style="text-align:center;"'; + } else { + return ''; + } + } + + function parseHeaders (header, style) { + var id = ''; + header = header.trim(); + // support both tablesHeaderId and tableHeaderId due to error in documentation so we don't break backwards compatibility + if (options.tablesHeaderId || options.tableHeaderId) { + id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"'; + } + header = showdown.subParser('spanGamut')(header, options, globals); + + return '' + header + '\n'; + } + + function parseCells (cell, style) { + var subText = showdown.subParser('spanGamut')(cell, options, globals); + return '' + subText + '\n'; + } + + function buildTable (headers, cells) { + var tb = '\n\n\n', + tblLgn = headers.length; + + for (var i = 0; i < tblLgn; ++i) { + tb += headers[i]; + } + tb += '\n\n\n'; + + for (i = 0; i < cells.length; ++i) { + tb += '\n'; + for (var ii = 0; ii < tblLgn; ++ii) { + tb += cells[i][ii]; + } + tb += '\n'; + } + tb += '\n
      \n'; + return tb; + } + + function parseTable (rawTable) { + var i, tableLines = rawTable.split('\n'); + + for (i = 0; i < tableLines.length; ++i) { + // strip wrong first and last column if wrapped tables are used + if (/^ {0,3}\|/.test(tableLines[i])) { + tableLines[i] = tableLines[i].replace(/^ {0,3}\|/, ''); + } + if (/\|[ \t]*$/.test(tableLines[i])) { + tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, ''); + } + // parse code spans first, but we only support one line code spans + tableLines[i] = showdown.subParser('codeSpans')(tableLines[i], options, globals); + } + + var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}), + rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}), + rawCells = [], + headers = [], + styles = [], + cells = []; + + tableLines.shift(); + tableLines.shift(); + + for (i = 0; i < tableLines.length; ++i) { + if (tableLines[i].trim() === '') { + continue; + } + rawCells.push( + tableLines[i] + .split('|') + .map(function (s) { + return s.trim(); + }) + ); + } + + if (rawHeaders.length < rawStyles.length) { + return rawTable; + } + + for (i = 0; i < rawStyles.length; ++i) { + styles.push(parseStyles(rawStyles[i])); + } + + for (i = 0; i < rawHeaders.length; ++i) { + if (showdown.helper.isUndefined(styles[i])) { + styles[i] = ''; + } + headers.push(parseHeaders(rawHeaders[i], styles[i])); + } + + for (i = 0; i < rawCells.length; ++i) { + var row = []; + for (var ii = 0; ii < headers.length; ++ii) { + if (showdown.helper.isUndefined(rawCells[i][ii])) { + + } + row.push(parseCells(rawCells[i][ii], styles[ii])); + } + cells.push(row); + } + + return buildTable(headers, cells); + } + + text = globals.converter._dispatch('tables.before', text, options, globals); + + // find escaped pipe characters + text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback); + + // parse multi column tables + text = text.replace(tableRgx, parseTable); + + // parse one column tables + text = text.replace(singeColTblRgx, parseTable); + + text = globals.converter._dispatch('tables.after', text, options, globals); + + return text; +}); + +showdown.subParser('underline', function (text, options, globals) { + 'use strict'; + + if (!options.underline) { + return text; + } + + text = globals.converter._dispatch('underline.before', text, options, globals); + + if (options.literalMidWordUnderscores) { + text = text.replace(/\b_?__(\S[\s\S]*)___?\b/g, function (wm, txt) { + return '' + txt + ''; + }); + } else { + text = text.replace(/_?__(\S[\s\S]*?)___?/g, function (wm, m) { + return (/\S$/.test(m)) ? '' + m + '' : wm; + }); + } + + // escape remaining underscores to prevent them being parsed by italic and bold + text = text.replace(/(_)/g, showdown.helper.escapeCharactersCallback); + + text = globals.converter._dispatch('underline.after', text, options, globals); + + return text; +}); + +/** + * Swap back in all the special characters we've hidden. + */ +showdown.subParser('unescapeSpecialChars', function (text, options, globals) { + 'use strict'; + text = globals.converter._dispatch('unescapeSpecialChars.before', text, options, globals); + + text = text.replace(/¨E(\d+)E/g, function (wholeMatch, m1) { + var charCodeToReplace = parseInt(m1); + return String.fromCharCode(charCodeToReplace); + }); + + text = globals.converter._dispatch('unescapeSpecialChars.after', text, options, globals); + return text; +}); + +var root = this; + +// AMD Loader +if (typeof define === 'function' && define.amd) { + define(function () { + 'use strict'; + return showdown; + }); + +// CommonJS/nodeJS Loader +} else if (typeof module !== 'undefined' && module.exports) { + module.exports = showdown; + +// Regular Browser loader +} else { + root.showdown = showdown; +} +}).call(this); + +//# sourceMappingURL=showdown.js.map diff --git a/cvat/apps/documentation/static/documentation/js/3rdparty/showdown.js.map b/cvat/apps/documentation/static/documentation/js/3rdparty/showdown.js.map new file mode 100644 index 000000000000..8909ebb38e39 --- /dev/null +++ b/cvat/apps/documentation/static/documentation/js/3rdparty/showdown.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/options.js","../src/showdown.js","../src/helpers.js","../src/converter.js","../src/subParsers/anchors.js","../src/subParsers/autoLinks.js","../src/subParsers/blockGamut.js","../src/subParsers/blockQuotes.js","../src/subParsers/codeBlocks.js","../src/subParsers/codeSpans.js","../src/subParsers/completeHTMLDocument.js","../src/subParsers/detab.js","../src/subParsers/ellipsis.js","../src/subParsers/emoji.js","../src/subParsers/encodeAmpsAndAngles.js","../src/subParsers/encodeBackslashEscapes.js","../src/subParsers/encodeCode.js","../src/subParsers/escapeSpecialCharsWithinTagAttributes.js","../src/subParsers/githubCodeBlocks.js","../src/subParsers/hashBlock.js","../src/subParsers/hashCodeTags.js","../src/subParsers/hashElement.js","../src/subParsers/hashHTMLBlocks.js","../src/subParsers/hashHTMLSpans.js","../src/subParsers/hashPreCodeTags.js","../src/subParsers/headers.js","../src/subParsers/horizontalRule.js","../src/subParsers/images.js","../src/subParsers/italicsAndBold.js","../src/subParsers/lists.js","../src/subParsers/metadata.js","../src/subParsers/outdent.js","../src/subParsers/paragraphs.js","../src/subParsers/runExtension.js","../src/subParsers/spanGamut.js","../src/subParsers/strikethrough.js","../src/subParsers/stripLinkDefinitions.js","../src/subParsers/tables.js","../src/subParsers/underline.js","../src/subParsers/unescapeSpecialChars.js","../src/loader.js"],"names":[],"mappings":"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","file":"showdown.js","sourcesContent":["/**\n * Created by Tivie on 13-07-2015.\n */\n\nfunction getDefaultOpts (simple) {\n 'use strict';\n\n var defaultOptions = {\n omitExtraWLInCodeBlocks: {\n defaultValue: false,\n describe: 'Omit the default extra whiteline added to code blocks',\n type: 'boolean'\n },\n noHeaderId: {\n defaultValue: false,\n describe: 'Turn on/off generated header id',\n type: 'boolean'\n },\n prefixHeaderId: {\n defaultValue: false,\n describe: 'Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic \\'section-\\' prefix',\n type: 'string'\n },\n rawPrefixHeaderId: {\n defaultValue: false,\n describe: 'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the \" char is used in the prefix)',\n type: 'boolean'\n },\n ghCompatibleHeaderId: {\n defaultValue: false,\n describe: 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)',\n type: 'boolean'\n },\n rawHeaderId: {\n defaultValue: false,\n describe: 'Remove only spaces, \\' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids',\n type: 'boolean'\n },\n headerLevelStart: {\n defaultValue: false,\n describe: 'The header blocks level start',\n type: 'integer'\n },\n parseImgDimensions: {\n defaultValue: false,\n describe: 'Turn on/off image dimension parsing',\n type: 'boolean'\n },\n simplifiedAutoLink: {\n defaultValue: false,\n describe: 'Turn on/off GFM autolink style',\n type: 'boolean'\n },\n excludeTrailingPunctuationFromURLs: {\n defaultValue: false,\n describe: 'Excludes trailing punctuation from links generated with autoLinking',\n type: 'boolean'\n },\n literalMidWordUnderscores: {\n defaultValue: false,\n describe: 'Parse midword underscores as literal underscores',\n type: 'boolean'\n },\n literalMidWordAsterisks: {\n defaultValue: false,\n describe: 'Parse midword asterisks as literal asterisks',\n type: 'boolean'\n },\n strikethrough: {\n defaultValue: false,\n describe: 'Turn on/off strikethrough support',\n type: 'boolean'\n },\n tables: {\n defaultValue: false,\n describe: 'Turn on/off tables support',\n type: 'boolean'\n },\n tablesHeaderId: {\n defaultValue: false,\n describe: 'Add an id to table headers',\n type: 'boolean'\n },\n ghCodeBlocks: {\n defaultValue: true,\n describe: 'Turn on/off GFM fenced code blocks support',\n type: 'boolean'\n },\n tasklists: {\n defaultValue: false,\n describe: 'Turn on/off GFM tasklist support',\n type: 'boolean'\n },\n smoothLivePreview: {\n defaultValue: false,\n describe: 'Prevents weird effects in live previews due to incomplete input',\n type: 'boolean'\n },\n smartIndentationFix: {\n defaultValue: false,\n description: 'Tries to smartly fix indentation in es6 strings',\n type: 'boolean'\n },\n disableForced4SpacesIndentedSublists: {\n defaultValue: false,\n description: 'Disables the requirement of indenting nested sublists by 4 spaces',\n type: 'boolean'\n },\n simpleLineBreaks: {\n defaultValue: false,\n description: 'Parses simple line breaks as
      (GFM Style)',\n type: 'boolean'\n },\n requireSpaceBeforeHeadingText: {\n defaultValue: false,\n description: 'Makes adding a space between `#` and the header text mandatory (GFM Style)',\n type: 'boolean'\n },\n ghMentions: {\n defaultValue: false,\n description: 'Enables github @mentions',\n type: 'boolean'\n },\n ghMentionsLink: {\n defaultValue: 'https://github.com/{u}',\n description: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.',\n type: 'string'\n },\n encodeEmails: {\n defaultValue: true,\n description: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities',\n type: 'boolean'\n },\n openLinksInNewWindow: {\n defaultValue: false,\n description: 'Open all links in new windows',\n type: 'boolean'\n },\n backslashEscapesHTMLTags: {\n defaultValue: false,\n description: 'Support for HTML Tag escaping. ex: \\
      foo\\
      ',\n type: 'boolean'\n },\n emoji: {\n defaultValue: false,\n description: 'Enable emoji support. Ex: `this is a :smile: emoji`',\n type: 'boolean'\n },\n underline: {\n defaultValue: false,\n description: 'Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `` and ``',\n type: 'boolean'\n },\n completeHTMLDocument: {\n defaultValue: false,\n description: 'Outputs a complete html document, including ``, `` and `` tags',\n type: 'boolean'\n },\n metadata: {\n defaultValue: false,\n description: 'Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).',\n type: 'boolean'\n },\n splitAdjacentBlockquotes: {\n defaultValue: false,\n description: 'Split adjacent blockquote blocks',\n type: 'boolean'\n }\n };\n if (simple === false) {\n return JSON.parse(JSON.stringify(defaultOptions));\n }\n var ret = {};\n for (var opt in defaultOptions) {\n if (defaultOptions.hasOwnProperty(opt)) {\n ret[opt] = defaultOptions[opt].defaultValue;\n }\n }\n return ret;\n}\n\nfunction allOptionsOn () {\n 'use strict';\n var options = getDefaultOpts(true),\n ret = {};\n for (var opt in options) {\n if (options.hasOwnProperty(opt)) {\n ret[opt] = true;\n }\n }\n return ret;\n}\n","/**\n * Created by Tivie on 06-01-2015.\n */\n\n// Private properties\nvar showdown = {},\n parsers = {},\n extensions = {},\n globalOptions = getDefaultOpts(true),\n setFlavor = 'vanilla',\n flavor = {\n github: {\n omitExtraWLInCodeBlocks: true,\n simplifiedAutoLink: true,\n excludeTrailingPunctuationFromURLs: true,\n literalMidWordUnderscores: true,\n strikethrough: true,\n tables: true,\n tablesHeaderId: true,\n ghCodeBlocks: true,\n tasklists: true,\n disableForced4SpacesIndentedSublists: true,\n simpleLineBreaks: true,\n requireSpaceBeforeHeadingText: true,\n ghCompatibleHeaderId: true,\n ghMentions: true,\n backslashEscapesHTMLTags: true,\n emoji: true,\n splitAdjacentBlockquotes: true\n },\n original: {\n noHeaderId: true,\n ghCodeBlocks: false\n },\n ghost: {\n omitExtraWLInCodeBlocks: true,\n parseImgDimensions: true,\n simplifiedAutoLink: true,\n excludeTrailingPunctuationFromURLs: true,\n literalMidWordUnderscores: true,\n strikethrough: true,\n tables: true,\n tablesHeaderId: true,\n ghCodeBlocks: true,\n tasklists: true,\n smoothLivePreview: true,\n simpleLineBreaks: true,\n requireSpaceBeforeHeadingText: true,\n ghMentions: false,\n encodeEmails: true\n },\n vanilla: getDefaultOpts(true),\n allOn: allOptionsOn()\n };\n\n/**\n * helper namespace\n * @type {{}}\n */\nshowdown.helper = {};\n\n/**\n * TODO LEGACY SUPPORT CODE\n * @type {{}}\n */\nshowdown.extensions = {};\n\n/**\n * Set a global option\n * @static\n * @param {string} key\n * @param {*} value\n * @returns {showdown}\n */\nshowdown.setOption = function (key, value) {\n 'use strict';\n globalOptions[key] = value;\n return this;\n};\n\n/**\n * Get a global option\n * @static\n * @param {string} key\n * @returns {*}\n */\nshowdown.getOption = function (key) {\n 'use strict';\n return globalOptions[key];\n};\n\n/**\n * Get the global options\n * @static\n * @returns {{}}\n */\nshowdown.getOptions = function () {\n 'use strict';\n return globalOptions;\n};\n\n/**\n * Reset global options to the default values\n * @static\n */\nshowdown.resetOptions = function () {\n 'use strict';\n globalOptions = getDefaultOpts(true);\n};\n\n/**\n * Set the flavor showdown should use as default\n * @param {string} name\n */\nshowdown.setFlavor = function (name) {\n 'use strict';\n if (!flavor.hasOwnProperty(name)) {\n throw Error(name + ' flavor was not found');\n }\n showdown.resetOptions();\n var preset = flavor[name];\n setFlavor = name;\n for (var option in preset) {\n if (preset.hasOwnProperty(option)) {\n globalOptions[option] = preset[option];\n }\n }\n};\n\n/**\n * Get the currently set flavor\n * @returns {string}\n */\nshowdown.getFlavor = function () {\n 'use strict';\n return setFlavor;\n};\n\n/**\n * Get the options of a specified flavor. Returns undefined if the flavor was not found\n * @param {string} name Name of the flavor\n * @returns {{}|undefined}\n */\nshowdown.getFlavorOptions = function (name) {\n 'use strict';\n if (flavor.hasOwnProperty(name)) {\n return flavor[name];\n }\n};\n\n/**\n * Get the default options\n * @static\n * @param {boolean} [simple=true]\n * @returns {{}}\n */\nshowdown.getDefaultOptions = function (simple) {\n 'use strict';\n return getDefaultOpts(simple);\n};\n\n/**\n * Get or set a subParser\n *\n * subParser(name) - Get a registered subParser\n * subParser(name, func) - Register a subParser\n * @static\n * @param {string} name\n * @param {function} [func]\n * @returns {*}\n */\nshowdown.subParser = function (name, func) {\n 'use strict';\n if (showdown.helper.isString(name)) {\n if (typeof func !== 'undefined') {\n parsers[name] = func;\n } else {\n if (parsers.hasOwnProperty(name)) {\n return parsers[name];\n } else {\n throw Error('SubParser named ' + name + ' not registered!');\n }\n }\n }\n};\n\n/**\n * Gets or registers an extension\n * @static\n * @param {string} name\n * @param {object|function=} ext\n * @returns {*}\n */\nshowdown.extension = function (name, ext) {\n 'use strict';\n\n if (!showdown.helper.isString(name)) {\n throw Error('Extension \\'name\\' must be a string');\n }\n\n name = showdown.helper.stdExtName(name);\n\n // Getter\n if (showdown.helper.isUndefined(ext)) {\n if (!extensions.hasOwnProperty(name)) {\n throw Error('Extension named ' + name + ' is not registered!');\n }\n return extensions[name];\n\n // Setter\n } else {\n // Expand extension if it's wrapped in a function\n if (typeof ext === 'function') {\n ext = ext();\n }\n\n // Ensure extension is an array\n if (!showdown.helper.isArray(ext)) {\n ext = [ext];\n }\n\n var validExtension = validate(ext, name);\n\n if (validExtension.valid) {\n extensions[name] = ext;\n } else {\n throw Error(validExtension.error);\n }\n }\n};\n\n/**\n * Gets all extensions registered\n * @returns {{}}\n */\nshowdown.getAllExtensions = function () {\n 'use strict';\n return extensions;\n};\n\n/**\n * Remove an extension\n * @param {string} name\n */\nshowdown.removeExtension = function (name) {\n 'use strict';\n delete extensions[name];\n};\n\n/**\n * Removes all extensions\n */\nshowdown.resetExtensions = function () {\n 'use strict';\n extensions = {};\n};\n\n/**\n * Validate extension\n * @param {array} extension\n * @param {string} name\n * @returns {{valid: boolean, error: string}}\n */\nfunction validate (extension, name) {\n 'use strict';\n\n var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',\n ret = {\n valid: true,\n error: ''\n };\n\n if (!showdown.helper.isArray(extension)) {\n extension = [extension];\n }\n\n for (var i = 0; i < extension.length; ++i) {\n var baseMsg = errMsg + ' sub-extension ' + i + ': ',\n ext = extension[i];\n if (typeof ext !== 'object') {\n ret.valid = false;\n ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';\n return ret;\n }\n\n if (!showdown.helper.isString(ext.type)) {\n ret.valid = false;\n ret.error = baseMsg + 'property \"type\" must be a string, but ' + typeof ext.type + ' given';\n return ret;\n }\n\n var type = ext.type = ext.type.toLowerCase();\n\n // normalize extension type\n if (type === 'language') {\n type = ext.type = 'lang';\n }\n\n if (type === 'html') {\n type = ext.type = 'output';\n }\n\n if (type !== 'lang' && type !== 'output' && type !== 'listener') {\n ret.valid = false;\n ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: \"lang/language\", \"output/html\" or \"listener\"';\n return ret;\n }\n\n if (type === 'listener') {\n if (showdown.helper.isUndefined(ext.listeners)) {\n ret.valid = false;\n ret.error = baseMsg + '. Extensions of type \"listener\" must have a property called \"listeners\"';\n return ret;\n }\n } else {\n if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {\n ret.valid = false;\n ret.error = baseMsg + type + ' extensions must define either a \"regex\" property or a \"filter\" method';\n return ret;\n }\n }\n\n if (ext.listeners) {\n if (typeof ext.listeners !== 'object') {\n ret.valid = false;\n ret.error = baseMsg + '\"listeners\" property must be an object but ' + typeof ext.listeners + ' given';\n return ret;\n }\n for (var ln in ext.listeners) {\n if (ext.listeners.hasOwnProperty(ln)) {\n if (typeof ext.listeners[ln] !== 'function') {\n ret.valid = false;\n ret.error = baseMsg + '\"listeners\" property must be an hash of [event name]: [callback]. listeners.' + ln +\n ' must be a function but ' + typeof ext.listeners[ln] + ' given';\n return ret;\n }\n }\n }\n }\n\n if (ext.filter) {\n if (typeof ext.filter !== 'function') {\n ret.valid = false;\n ret.error = baseMsg + '\"filter\" must be a function, but ' + typeof ext.filter + ' given';\n return ret;\n }\n } else if (ext.regex) {\n if (showdown.helper.isString(ext.regex)) {\n ext.regex = new RegExp(ext.regex, 'g');\n }\n if (!(ext.regex instanceof RegExp)) {\n ret.valid = false;\n ret.error = baseMsg + '\"regex\" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';\n return ret;\n }\n if (showdown.helper.isUndefined(ext.replace)) {\n ret.valid = false;\n ret.error = baseMsg + '\"regex\" extensions must implement a replace string or function';\n return ret;\n }\n }\n }\n return ret;\n}\n\n/**\n * Validate extension\n * @param {object} ext\n * @returns {boolean}\n */\nshowdown.validateExtension = function (ext) {\n 'use strict';\n\n var validateExtension = validate(ext, null);\n if (!validateExtension.valid) {\n console.warn(validateExtension.error);\n return false;\n }\n return true;\n};\n","/**\n * showdownjs helper functions\n */\n\nif (!showdown.hasOwnProperty('helper')) {\n showdown.helper = {};\n}\n\n/**\n * Check if var is string\n * @static\n * @param {string} a\n * @returns {boolean}\n */\nshowdown.helper.isString = function (a) {\n 'use strict';\n return (typeof a === 'string' || a instanceof String);\n};\n\n/**\n * Check if var is a function\n * @static\n * @param {*} a\n * @returns {boolean}\n */\nshowdown.helper.isFunction = function (a) {\n 'use strict';\n var getType = {};\n return a && getType.toString.call(a) === '[object Function]';\n};\n\n/**\n * isArray helper function\n * @static\n * @param {*} a\n * @returns {boolean}\n */\nshowdown.helper.isArray = function (a) {\n 'use strict';\n return Array.isArray(a);\n};\n\n/**\n * Check if value is undefined\n * @static\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.\n */\nshowdown.helper.isUndefined = function (value) {\n 'use strict';\n return typeof value === 'undefined';\n};\n\n/**\n * ForEach helper function\n * Iterates over Arrays and Objects (own properties only)\n * @static\n * @param {*} obj\n * @param {function} callback Accepts 3 params: 1. value, 2. key, 3. the original array/object\n */\nshowdown.helper.forEach = function (obj, callback) {\n 'use strict';\n // check if obj is defined\n if (showdown.helper.isUndefined(obj)) {\n throw new Error('obj param is required');\n }\n\n if (showdown.helper.isUndefined(callback)) {\n throw new Error('callback param is required');\n }\n\n if (!showdown.helper.isFunction(callback)) {\n throw new Error('callback param must be a function/closure');\n }\n\n if (typeof obj.forEach === 'function') {\n obj.forEach(callback);\n } else if (showdown.helper.isArray(obj)) {\n for (var i = 0; i < obj.length; i++) {\n callback(obj[i], i, obj);\n }\n } else if (typeof (obj) === 'object') {\n for (var prop in obj) {\n if (obj.hasOwnProperty(prop)) {\n callback(obj[prop], prop, obj);\n }\n }\n } else {\n throw new Error('obj does not seem to be an array or an iterable object');\n }\n};\n\n/**\n * Standardidize extension name\n * @static\n * @param {string} s extension name\n * @returns {string}\n */\nshowdown.helper.stdExtName = function (s) {\n 'use strict';\n return s.replace(/[_?*+\\/\\\\.^-]/g, '').replace(/\\s/g, '').toLowerCase();\n};\n\nfunction escapeCharactersCallback (wholeMatch, m1) {\n 'use strict';\n var charCodeToEscape = m1.charCodeAt(0);\n return '¨E' + charCodeToEscape + 'E';\n}\n\n/**\n * Callback used to escape characters when passing through String.replace\n * @static\n * @param {string} wholeMatch\n * @param {string} m1\n * @returns {string}\n */\nshowdown.helper.escapeCharactersCallback = escapeCharactersCallback;\n\n/**\n * Escape characters in a string\n * @static\n * @param {string} text\n * @param {string} charsToEscape\n * @param {boolean} afterBackslash\n * @returns {XML|string|void|*}\n */\nshowdown.helper.escapeCharacters = function (text, charsToEscape, afterBackslash) {\n 'use strict';\n // First we have to escape the escape characters so that\n // we can build a character class out of them\n var regexString = '([' + charsToEscape.replace(/([\\[\\]\\\\])/g, '\\\\$1') + '])';\n\n if (afterBackslash) {\n regexString = '\\\\\\\\' + regexString;\n }\n\n var regex = new RegExp(regexString, 'g');\n text = text.replace(regex, escapeCharactersCallback);\n\n return text;\n};\n\nvar rgxFindMatchPos = function (str, left, right, flags) {\n 'use strict';\n var f = flags || '',\n g = f.indexOf('g') > -1,\n x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),\n l = new RegExp(left, f.replace(/g/g, '')),\n pos = [],\n t, s, m, start, end;\n\n do {\n t = 0;\n while ((m = x.exec(str))) {\n if (l.test(m[0])) {\n if (!(t++)) {\n s = x.lastIndex;\n start = s - m[0].length;\n }\n } else if (t) {\n if (!--t) {\n end = m.index + m[0].length;\n var obj = {\n left: {start: start, end: s},\n match: {start: s, end: m.index},\n right: {start: m.index, end: end},\n wholeMatch: {start: start, end: end}\n };\n pos.push(obj);\n if (!g) {\n return pos;\n }\n }\n }\n }\n } while (t && (x.lastIndex = s));\n\n return pos;\n};\n\n/**\n * matchRecursiveRegExp\n *\n * (c) 2007 Steven Levithan \n * MIT License\n *\n * Accepts a string to search, a left and right format delimiter\n * as regex patterns, and optional regex flags. Returns an array\n * of matches, allowing nested instances of left/right delimiters.\n * Use the \"g\" flag to return all matches, otherwise only the\n * first is returned. Be careful to ensure that the left and\n * right format delimiters produce mutually exclusive matches.\n * Backreferences are not supported within the right delimiter\n * due to how it is internally combined with the left delimiter.\n * When matching strings whose format delimiters are unbalanced\n * to the left or right, the output is intentionally as a\n * conventional regex library with recursion support would\n * produce, e.g. \"<\" and \">\" both produce [\"x\"] when using\n * \"<\" and \">\" as the delimiters (both strings contain a single,\n * balanced instance of \"\").\n *\n * examples:\n * matchRecursiveRegExp(\"test\", \"\\\\(\", \"\\\\)\")\n * returns: []\n * matchRecursiveRegExp(\">>t<>\", \"<\", \">\", \"g\")\n * returns: [\"t<>\", \"\"]\n * matchRecursiveRegExp(\"
      test
      \", \"]*>\", \"\", \"gi\")\n * returns: [\"test\"]\n */\nshowdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {\n 'use strict';\n\n var matchPos = rgxFindMatchPos (str, left, right, flags),\n results = [];\n\n for (var i = 0; i < matchPos.length; ++i) {\n results.push([\n str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),\n str.slice(matchPos[i].match.start, matchPos[i].match.end),\n str.slice(matchPos[i].left.start, matchPos[i].left.end),\n str.slice(matchPos[i].right.start, matchPos[i].right.end)\n ]);\n }\n return results;\n};\n\n/**\n *\n * @param {string} str\n * @param {string|function} replacement\n * @param {string} left\n * @param {string} right\n * @param {string} flags\n * @returns {string}\n */\nshowdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {\n 'use strict';\n\n if (!showdown.helper.isFunction(replacement)) {\n var repStr = replacement;\n replacement = function () {\n return repStr;\n };\n }\n\n var matchPos = rgxFindMatchPos(str, left, right, flags),\n finalStr = str,\n lng = matchPos.length;\n\n if (lng > 0) {\n var bits = [];\n if (matchPos[0].wholeMatch.start !== 0) {\n bits.push(str.slice(0, matchPos[0].wholeMatch.start));\n }\n for (var i = 0; i < lng; ++i) {\n bits.push(\n replacement(\n str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),\n str.slice(matchPos[i].match.start, matchPos[i].match.end),\n str.slice(matchPos[i].left.start, matchPos[i].left.end),\n str.slice(matchPos[i].right.start, matchPos[i].right.end)\n )\n );\n if (i < lng - 1) {\n bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));\n }\n }\n if (matchPos[lng - 1].wholeMatch.end < str.length) {\n bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));\n }\n finalStr = bits.join('');\n }\n return finalStr;\n};\n\n/**\n * Returns the index within the passed String object of the first occurrence of the specified regex,\n * starting the search at fromIndex. Returns -1 if the value is not found.\n *\n * @param {string} str string to search\n * @param {RegExp} regex Regular expression to search\n * @param {int} [fromIndex = 0] Index to start the search\n * @returns {Number}\n * @throws InvalidArgumentError\n */\nshowdown.helper.regexIndexOf = function (str, regex, fromIndex) {\n 'use strict';\n if (!showdown.helper.isString(str)) {\n throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string';\n }\n if (regex instanceof RegExp === false) {\n throw 'InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp';\n }\n var indexOf = str.substring(fromIndex || 0).search(regex);\n return (indexOf >= 0) ? (indexOf + (fromIndex || 0)) : indexOf;\n};\n\n/**\n * Splits the passed string object at the defined index, and returns an array composed of the two substrings\n * @param {string} str string to split\n * @param {int} index index to split string at\n * @returns {[string,string]}\n * @throws InvalidArgumentError\n */\nshowdown.helper.splitAtIndex = function (str, index) {\n 'use strict';\n if (!showdown.helper.isString(str)) {\n throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string';\n }\n return [str.substring(0, index), str.substring(index)];\n};\n\n/**\n * Obfuscate an e-mail address through the use of Character Entities,\n * transforming ASCII characters into their equivalent decimal or hex entities.\n *\n * Since it has a random component, subsequent calls to this function produce different results\n *\n * @param {string} mail\n * @returns {string}\n */\nshowdown.helper.encodeEmailAddress = function (mail) {\n 'use strict';\n var encode = [\n function (ch) {\n return '&#' + ch.charCodeAt(0) + ';';\n },\n function (ch) {\n return '&#x' + ch.charCodeAt(0).toString(16) + ';';\n },\n function (ch) {\n return ch;\n }\n ];\n\n mail = mail.replace(/./g, function (ch) {\n if (ch === '@') {\n // this *must* be encoded. I insist.\n ch = encode[Math.floor(Math.random() * 2)](ch);\n } else {\n var r = Math.random();\n // roughly 10% raw, 45% hex, 45% dec\n ch = (\n r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)\n );\n }\n return ch;\n });\n\n return mail;\n};\n\n/**\n * POLYFILLS\n */\n// use this instead of builtin is undefined for IE8 compatibility\nif (typeof(console) === 'undefined') {\n console = {\n warn: function (msg) {\n 'use strict';\n alert(msg);\n },\n log: function (msg) {\n 'use strict';\n alert(msg);\n },\n error: function (msg) {\n 'use strict';\n throw msg;\n }\n };\n}\n\n/**\n * Common regexes.\n * We declare some common regexes to improve performance\n */\nshowdown.helper.regexes = {\n asteriskDashAndColon: /([*_:~])/g\n};\n\n/**\n * EMOJIS LIST\n */\nshowdown.helper.emojis = {\n '+1':'\\ud83d\\udc4d',\n '-1':'\\ud83d\\udc4e',\n '100':'\\ud83d\\udcaf',\n '1234':'\\ud83d\\udd22',\n '1st_place_medal':'\\ud83e\\udd47',\n '2nd_place_medal':'\\ud83e\\udd48',\n '3rd_place_medal':'\\ud83e\\udd49',\n '8ball':'\\ud83c\\udfb1',\n 'a':'\\ud83c\\udd70\\ufe0f',\n 'ab':'\\ud83c\\udd8e',\n 'abc':'\\ud83d\\udd24',\n 'abcd':'\\ud83d\\udd21',\n 'accept':'\\ud83c\\ude51',\n 'aerial_tramway':'\\ud83d\\udea1',\n 'airplane':'\\u2708\\ufe0f',\n 'alarm_clock':'\\u23f0',\n 'alembic':'\\u2697\\ufe0f',\n 'alien':'\\ud83d\\udc7d',\n 'ambulance':'\\ud83d\\ude91',\n 'amphora':'\\ud83c\\udffa',\n 'anchor':'\\u2693\\ufe0f',\n 'angel':'\\ud83d\\udc7c',\n 'anger':'\\ud83d\\udca2',\n 'angry':'\\ud83d\\ude20',\n 'anguished':'\\ud83d\\ude27',\n 'ant':'\\ud83d\\udc1c',\n 'apple':'\\ud83c\\udf4e',\n 'aquarius':'\\u2652\\ufe0f',\n 'aries':'\\u2648\\ufe0f',\n 'arrow_backward':'\\u25c0\\ufe0f',\n 'arrow_double_down':'\\u23ec',\n 'arrow_double_up':'\\u23eb',\n 'arrow_down':'\\u2b07\\ufe0f',\n 'arrow_down_small':'\\ud83d\\udd3d',\n 'arrow_forward':'\\u25b6\\ufe0f',\n 'arrow_heading_down':'\\u2935\\ufe0f',\n 'arrow_heading_up':'\\u2934\\ufe0f',\n 'arrow_left':'\\u2b05\\ufe0f',\n 'arrow_lower_left':'\\u2199\\ufe0f',\n 'arrow_lower_right':'\\u2198\\ufe0f',\n 'arrow_right':'\\u27a1\\ufe0f',\n 'arrow_right_hook':'\\u21aa\\ufe0f',\n 'arrow_up':'\\u2b06\\ufe0f',\n 'arrow_up_down':'\\u2195\\ufe0f',\n 'arrow_up_small':'\\ud83d\\udd3c',\n 'arrow_upper_left':'\\u2196\\ufe0f',\n 'arrow_upper_right':'\\u2197\\ufe0f',\n 'arrows_clockwise':'\\ud83d\\udd03',\n 'arrows_counterclockwise':'\\ud83d\\udd04',\n 'art':'\\ud83c\\udfa8',\n 'articulated_lorry':'\\ud83d\\ude9b',\n 'artificial_satellite':'\\ud83d\\udef0',\n 'astonished':'\\ud83d\\ude32',\n 'athletic_shoe':'\\ud83d\\udc5f',\n 'atm':'\\ud83c\\udfe7',\n 'atom_symbol':'\\u269b\\ufe0f',\n 'avocado':'\\ud83e\\udd51',\n 'b':'\\ud83c\\udd71\\ufe0f',\n 'baby':'\\ud83d\\udc76',\n 'baby_bottle':'\\ud83c\\udf7c',\n 'baby_chick':'\\ud83d\\udc24',\n 'baby_symbol':'\\ud83d\\udebc',\n 'back':'\\ud83d\\udd19',\n 'bacon':'\\ud83e\\udd53',\n 'badminton':'\\ud83c\\udff8',\n 'baggage_claim':'\\ud83d\\udec4',\n 'baguette_bread':'\\ud83e\\udd56',\n 'balance_scale':'\\u2696\\ufe0f',\n 'balloon':'\\ud83c\\udf88',\n 'ballot_box':'\\ud83d\\uddf3',\n 'ballot_box_with_check':'\\u2611\\ufe0f',\n 'bamboo':'\\ud83c\\udf8d',\n 'banana':'\\ud83c\\udf4c',\n 'bangbang':'\\u203c\\ufe0f',\n 'bank':'\\ud83c\\udfe6',\n 'bar_chart':'\\ud83d\\udcca',\n 'barber':'\\ud83d\\udc88',\n 'baseball':'\\u26be\\ufe0f',\n 'basketball':'\\ud83c\\udfc0',\n 'basketball_man':'\\u26f9\\ufe0f',\n 'basketball_woman':'\\u26f9\\ufe0f‍\\u2640\\ufe0f',\n 'bat':'\\ud83e\\udd87',\n 'bath':'\\ud83d\\udec0',\n 'bathtub':'\\ud83d\\udec1',\n 'battery':'\\ud83d\\udd0b',\n 'beach_umbrella':'\\ud83c\\udfd6',\n 'bear':'\\ud83d\\udc3b',\n 'bed':'\\ud83d\\udecf',\n 'bee':'\\ud83d\\udc1d',\n 'beer':'\\ud83c\\udf7a',\n 'beers':'\\ud83c\\udf7b',\n 'beetle':'\\ud83d\\udc1e',\n 'beginner':'\\ud83d\\udd30',\n 'bell':'\\ud83d\\udd14',\n 'bellhop_bell':'\\ud83d\\udece',\n 'bento':'\\ud83c\\udf71',\n 'biking_man':'\\ud83d\\udeb4',\n 'bike':'\\ud83d\\udeb2',\n 'biking_woman':'\\ud83d\\udeb4‍\\u2640\\ufe0f',\n 'bikini':'\\ud83d\\udc59',\n 'biohazard':'\\u2623\\ufe0f',\n 'bird':'\\ud83d\\udc26',\n 'birthday':'\\ud83c\\udf82',\n 'black_circle':'\\u26ab\\ufe0f',\n 'black_flag':'\\ud83c\\udff4',\n 'black_heart':'\\ud83d\\udda4',\n 'black_joker':'\\ud83c\\udccf',\n 'black_large_square':'\\u2b1b\\ufe0f',\n 'black_medium_small_square':'\\u25fe\\ufe0f',\n 'black_medium_square':'\\u25fc\\ufe0f',\n 'black_nib':'\\u2712\\ufe0f',\n 'black_small_square':'\\u25aa\\ufe0f',\n 'black_square_button':'\\ud83d\\udd32',\n 'blonde_man':'\\ud83d\\udc71',\n 'blonde_woman':'\\ud83d\\udc71‍\\u2640\\ufe0f',\n 'blossom':'\\ud83c\\udf3c',\n 'blowfish':'\\ud83d\\udc21',\n 'blue_book':'\\ud83d\\udcd8',\n 'blue_car':'\\ud83d\\ude99',\n 'blue_heart':'\\ud83d\\udc99',\n 'blush':'\\ud83d\\ude0a',\n 'boar':'\\ud83d\\udc17',\n 'boat':'\\u26f5\\ufe0f',\n 'bomb':'\\ud83d\\udca3',\n 'book':'\\ud83d\\udcd6',\n 'bookmark':'\\ud83d\\udd16',\n 'bookmark_tabs':'\\ud83d\\udcd1',\n 'books':'\\ud83d\\udcda',\n 'boom':'\\ud83d\\udca5',\n 'boot':'\\ud83d\\udc62',\n 'bouquet':'\\ud83d\\udc90',\n 'bowing_man':'\\ud83d\\ude47',\n 'bow_and_arrow':'\\ud83c\\udff9',\n 'bowing_woman':'\\ud83d\\ude47‍\\u2640\\ufe0f',\n 'bowling':'\\ud83c\\udfb3',\n 'boxing_glove':'\\ud83e\\udd4a',\n 'boy':'\\ud83d\\udc66',\n 'bread':'\\ud83c\\udf5e',\n 'bride_with_veil':'\\ud83d\\udc70',\n 'bridge_at_night':'\\ud83c\\udf09',\n 'briefcase':'\\ud83d\\udcbc',\n 'broken_heart':'\\ud83d\\udc94',\n 'bug':'\\ud83d\\udc1b',\n 'building_construction':'\\ud83c\\udfd7',\n 'bulb':'\\ud83d\\udca1',\n 'bullettrain_front':'\\ud83d\\ude85',\n 'bullettrain_side':'\\ud83d\\ude84',\n 'burrito':'\\ud83c\\udf2f',\n 'bus':'\\ud83d\\ude8c',\n 'business_suit_levitating':'\\ud83d\\udd74',\n 'busstop':'\\ud83d\\ude8f',\n 'bust_in_silhouette':'\\ud83d\\udc64',\n 'busts_in_silhouette':'\\ud83d\\udc65',\n 'butterfly':'\\ud83e\\udd8b',\n 'cactus':'\\ud83c\\udf35',\n 'cake':'\\ud83c\\udf70',\n 'calendar':'\\ud83d\\udcc6',\n 'call_me_hand':'\\ud83e\\udd19',\n 'calling':'\\ud83d\\udcf2',\n 'camel':'\\ud83d\\udc2b',\n 'camera':'\\ud83d\\udcf7',\n 'camera_flash':'\\ud83d\\udcf8',\n 'camping':'\\ud83c\\udfd5',\n 'cancer':'\\u264b\\ufe0f',\n 'candle':'\\ud83d\\udd6f',\n 'candy':'\\ud83c\\udf6c',\n 'canoe':'\\ud83d\\udef6',\n 'capital_abcd':'\\ud83d\\udd20',\n 'capricorn':'\\u2651\\ufe0f',\n 'car':'\\ud83d\\ude97',\n 'card_file_box':'\\ud83d\\uddc3',\n 'card_index':'\\ud83d\\udcc7',\n 'card_index_dividers':'\\ud83d\\uddc2',\n 'carousel_horse':'\\ud83c\\udfa0',\n 'carrot':'\\ud83e\\udd55',\n 'cat':'\\ud83d\\udc31',\n 'cat2':'\\ud83d\\udc08',\n 'cd':'\\ud83d\\udcbf',\n 'chains':'\\u26d3',\n 'champagne':'\\ud83c\\udf7e',\n 'chart':'\\ud83d\\udcb9',\n 'chart_with_downwards_trend':'\\ud83d\\udcc9',\n 'chart_with_upwards_trend':'\\ud83d\\udcc8',\n 'checkered_flag':'\\ud83c\\udfc1',\n 'cheese':'\\ud83e\\uddc0',\n 'cherries':'\\ud83c\\udf52',\n 'cherry_blossom':'\\ud83c\\udf38',\n 'chestnut':'\\ud83c\\udf30',\n 'chicken':'\\ud83d\\udc14',\n 'children_crossing':'\\ud83d\\udeb8',\n 'chipmunk':'\\ud83d\\udc3f',\n 'chocolate_bar':'\\ud83c\\udf6b',\n 'christmas_tree':'\\ud83c\\udf84',\n 'church':'\\u26ea\\ufe0f',\n 'cinema':'\\ud83c\\udfa6',\n 'circus_tent':'\\ud83c\\udfaa',\n 'city_sunrise':'\\ud83c\\udf07',\n 'city_sunset':'\\ud83c\\udf06',\n 'cityscape':'\\ud83c\\udfd9',\n 'cl':'\\ud83c\\udd91',\n 'clamp':'\\ud83d\\udddc',\n 'clap':'\\ud83d\\udc4f',\n 'clapper':'\\ud83c\\udfac',\n 'classical_building':'\\ud83c\\udfdb',\n 'clinking_glasses':'\\ud83e\\udd42',\n 'clipboard':'\\ud83d\\udccb',\n 'clock1':'\\ud83d\\udd50',\n 'clock10':'\\ud83d\\udd59',\n 'clock1030':'\\ud83d\\udd65',\n 'clock11':'\\ud83d\\udd5a',\n 'clock1130':'\\ud83d\\udd66',\n 'clock12':'\\ud83d\\udd5b',\n 'clock1230':'\\ud83d\\udd67',\n 'clock130':'\\ud83d\\udd5c',\n 'clock2':'\\ud83d\\udd51',\n 'clock230':'\\ud83d\\udd5d',\n 'clock3':'\\ud83d\\udd52',\n 'clock330':'\\ud83d\\udd5e',\n 'clock4':'\\ud83d\\udd53',\n 'clock430':'\\ud83d\\udd5f',\n 'clock5':'\\ud83d\\udd54',\n 'clock530':'\\ud83d\\udd60',\n 'clock6':'\\ud83d\\udd55',\n 'clock630':'\\ud83d\\udd61',\n 'clock7':'\\ud83d\\udd56',\n 'clock730':'\\ud83d\\udd62',\n 'clock8':'\\ud83d\\udd57',\n 'clock830':'\\ud83d\\udd63',\n 'clock9':'\\ud83d\\udd58',\n 'clock930':'\\ud83d\\udd64',\n 'closed_book':'\\ud83d\\udcd5',\n 'closed_lock_with_key':'\\ud83d\\udd10',\n 'closed_umbrella':'\\ud83c\\udf02',\n 'cloud':'\\u2601\\ufe0f',\n 'cloud_with_lightning':'\\ud83c\\udf29',\n 'cloud_with_lightning_and_rain':'\\u26c8',\n 'cloud_with_rain':'\\ud83c\\udf27',\n 'cloud_with_snow':'\\ud83c\\udf28',\n 'clown_face':'\\ud83e\\udd21',\n 'clubs':'\\u2663\\ufe0f',\n 'cocktail':'\\ud83c\\udf78',\n 'coffee':'\\u2615\\ufe0f',\n 'coffin':'\\u26b0\\ufe0f',\n 'cold_sweat':'\\ud83d\\ude30',\n 'comet':'\\u2604\\ufe0f',\n 'computer':'\\ud83d\\udcbb',\n 'computer_mouse':'\\ud83d\\uddb1',\n 'confetti_ball':'\\ud83c\\udf8a',\n 'confounded':'\\ud83d\\ude16',\n 'confused':'\\ud83d\\ude15',\n 'congratulations':'\\u3297\\ufe0f',\n 'construction':'\\ud83d\\udea7',\n 'construction_worker_man':'\\ud83d\\udc77',\n 'construction_worker_woman':'\\ud83d\\udc77‍\\u2640\\ufe0f',\n 'control_knobs':'\\ud83c\\udf9b',\n 'convenience_store':'\\ud83c\\udfea',\n 'cookie':'\\ud83c\\udf6a',\n 'cool':'\\ud83c\\udd92',\n 'policeman':'\\ud83d\\udc6e',\n 'copyright':'\\u00a9\\ufe0f',\n 'corn':'\\ud83c\\udf3d',\n 'couch_and_lamp':'\\ud83d\\udecb',\n 'couple':'\\ud83d\\udc6b',\n 'couple_with_heart_woman_man':'\\ud83d\\udc91',\n 'couple_with_heart_man_man':'\\ud83d\\udc68‍\\u2764\\ufe0f‍\\ud83d\\udc68',\n 'couple_with_heart_woman_woman':'\\ud83d\\udc69‍\\u2764\\ufe0f‍\\ud83d\\udc69',\n 'couplekiss_man_man':'\\ud83d\\udc68‍\\u2764\\ufe0f‍\\ud83d\\udc8b‍\\ud83d\\udc68',\n 'couplekiss_man_woman':'\\ud83d\\udc8f',\n 'couplekiss_woman_woman':'\\ud83d\\udc69‍\\u2764\\ufe0f‍\\ud83d\\udc8b‍\\ud83d\\udc69',\n 'cow':'\\ud83d\\udc2e',\n 'cow2':'\\ud83d\\udc04',\n 'cowboy_hat_face':'\\ud83e\\udd20',\n 'crab':'\\ud83e\\udd80',\n 'crayon':'\\ud83d\\udd8d',\n 'credit_card':'\\ud83d\\udcb3',\n 'crescent_moon':'\\ud83c\\udf19',\n 'cricket':'\\ud83c\\udfcf',\n 'crocodile':'\\ud83d\\udc0a',\n 'croissant':'\\ud83e\\udd50',\n 'crossed_fingers':'\\ud83e\\udd1e',\n 'crossed_flags':'\\ud83c\\udf8c',\n 'crossed_swords':'\\u2694\\ufe0f',\n 'crown':'\\ud83d\\udc51',\n 'cry':'\\ud83d\\ude22',\n 'crying_cat_face':'\\ud83d\\ude3f',\n 'crystal_ball':'\\ud83d\\udd2e',\n 'cucumber':'\\ud83e\\udd52',\n 'cupid':'\\ud83d\\udc98',\n 'curly_loop':'\\u27b0',\n 'currency_exchange':'\\ud83d\\udcb1',\n 'curry':'\\ud83c\\udf5b',\n 'custard':'\\ud83c\\udf6e',\n 'customs':'\\ud83d\\udec3',\n 'cyclone':'\\ud83c\\udf00',\n 'dagger':'\\ud83d\\udde1',\n 'dancer':'\\ud83d\\udc83',\n 'dancing_women':'\\ud83d\\udc6f',\n 'dancing_men':'\\ud83d\\udc6f‍\\u2642\\ufe0f',\n 'dango':'\\ud83c\\udf61',\n 'dark_sunglasses':'\\ud83d\\udd76',\n 'dart':'\\ud83c\\udfaf',\n 'dash':'\\ud83d\\udca8',\n 'date':'\\ud83d\\udcc5',\n 'deciduous_tree':'\\ud83c\\udf33',\n 'deer':'\\ud83e\\udd8c',\n 'department_store':'\\ud83c\\udfec',\n 'derelict_house':'\\ud83c\\udfda',\n 'desert':'\\ud83c\\udfdc',\n 'desert_island':'\\ud83c\\udfdd',\n 'desktop_computer':'\\ud83d\\udda5',\n 'male_detective':'\\ud83d\\udd75\\ufe0f',\n 'diamond_shape_with_a_dot_inside':'\\ud83d\\udca0',\n 'diamonds':'\\u2666\\ufe0f',\n 'disappointed':'\\ud83d\\ude1e',\n 'disappointed_relieved':'\\ud83d\\ude25',\n 'dizzy':'\\ud83d\\udcab',\n 'dizzy_face':'\\ud83d\\ude35',\n 'do_not_litter':'\\ud83d\\udeaf',\n 'dog':'\\ud83d\\udc36',\n 'dog2':'\\ud83d\\udc15',\n 'dollar':'\\ud83d\\udcb5',\n 'dolls':'\\ud83c\\udf8e',\n 'dolphin':'\\ud83d\\udc2c',\n 'door':'\\ud83d\\udeaa',\n 'doughnut':'\\ud83c\\udf69',\n 'dove':'\\ud83d\\udd4a',\n 'dragon':'\\ud83d\\udc09',\n 'dragon_face':'\\ud83d\\udc32',\n 'dress':'\\ud83d\\udc57',\n 'dromedary_camel':'\\ud83d\\udc2a',\n 'drooling_face':'\\ud83e\\udd24',\n 'droplet':'\\ud83d\\udca7',\n 'drum':'\\ud83e\\udd41',\n 'duck':'\\ud83e\\udd86',\n 'dvd':'\\ud83d\\udcc0',\n 'e-mail':'\\ud83d\\udce7',\n 'eagle':'\\ud83e\\udd85',\n 'ear':'\\ud83d\\udc42',\n 'ear_of_rice':'\\ud83c\\udf3e',\n 'earth_africa':'\\ud83c\\udf0d',\n 'earth_americas':'\\ud83c\\udf0e',\n 'earth_asia':'\\ud83c\\udf0f',\n 'egg':'\\ud83e\\udd5a',\n 'eggplant':'\\ud83c\\udf46',\n 'eight_pointed_black_star':'\\u2734\\ufe0f',\n 'eight_spoked_asterisk':'\\u2733\\ufe0f',\n 'electric_plug':'\\ud83d\\udd0c',\n 'elephant':'\\ud83d\\udc18',\n 'email':'\\u2709\\ufe0f',\n 'end':'\\ud83d\\udd1a',\n 'envelope_with_arrow':'\\ud83d\\udce9',\n 'euro':'\\ud83d\\udcb6',\n 'european_castle':'\\ud83c\\udff0',\n 'european_post_office':'\\ud83c\\udfe4',\n 'evergreen_tree':'\\ud83c\\udf32',\n 'exclamation':'\\u2757\\ufe0f',\n 'expressionless':'\\ud83d\\ude11',\n 'eye':'\\ud83d\\udc41',\n 'eye_speech_bubble':'\\ud83d\\udc41‍\\ud83d\\udde8',\n 'eyeglasses':'\\ud83d\\udc53',\n 'eyes':'\\ud83d\\udc40',\n 'face_with_head_bandage':'\\ud83e\\udd15',\n 'face_with_thermometer':'\\ud83e\\udd12',\n 'fist_oncoming':'\\ud83d\\udc4a',\n 'factory':'\\ud83c\\udfed',\n 'fallen_leaf':'\\ud83c\\udf42',\n 'family_man_woman_boy':'\\ud83d\\udc6a',\n 'family_man_boy':'\\ud83d\\udc68‍\\ud83d\\udc66',\n 'family_man_boy_boy':'\\ud83d\\udc68‍\\ud83d\\udc66‍\\ud83d\\udc66',\n 'family_man_girl':'\\ud83d\\udc68‍\\ud83d\\udc67',\n 'family_man_girl_boy':'\\ud83d\\udc68‍\\ud83d\\udc67‍\\ud83d\\udc66',\n 'family_man_girl_girl':'\\ud83d\\udc68‍\\ud83d\\udc67‍\\ud83d\\udc67',\n 'family_man_man_boy':'\\ud83d\\udc68‍\\ud83d\\udc68‍\\ud83d\\udc66',\n 'family_man_man_boy_boy':'\\ud83d\\udc68‍\\ud83d\\udc68‍\\ud83d\\udc66‍\\ud83d\\udc66',\n 'family_man_man_girl':'\\ud83d\\udc68‍\\ud83d\\udc68‍\\ud83d\\udc67',\n 'family_man_man_girl_boy':'\\ud83d\\udc68‍\\ud83d\\udc68‍\\ud83d\\udc67‍\\ud83d\\udc66',\n 'family_man_man_girl_girl':'\\ud83d\\udc68‍\\ud83d\\udc68‍\\ud83d\\udc67‍\\ud83d\\udc67',\n 'family_man_woman_boy_boy':'\\ud83d\\udc68‍\\ud83d\\udc69‍\\ud83d\\udc66‍\\ud83d\\udc66',\n 'family_man_woman_girl':'\\ud83d\\udc68‍\\ud83d\\udc69‍\\ud83d\\udc67',\n 'family_man_woman_girl_boy':'\\ud83d\\udc68‍\\ud83d\\udc69‍\\ud83d\\udc67‍\\ud83d\\udc66',\n 'family_man_woman_girl_girl':'\\ud83d\\udc68‍\\ud83d\\udc69‍\\ud83d\\udc67‍\\ud83d\\udc67',\n 'family_woman_boy':'\\ud83d\\udc69‍\\ud83d\\udc66',\n 'family_woman_boy_boy':'\\ud83d\\udc69‍\\ud83d\\udc66‍\\ud83d\\udc66',\n 'family_woman_girl':'\\ud83d\\udc69‍\\ud83d\\udc67',\n 'family_woman_girl_boy':'\\ud83d\\udc69‍\\ud83d\\udc67‍\\ud83d\\udc66',\n 'family_woman_girl_girl':'\\ud83d\\udc69‍\\ud83d\\udc67‍\\ud83d\\udc67',\n 'family_woman_woman_boy':'\\ud83d\\udc69‍\\ud83d\\udc69‍\\ud83d\\udc66',\n 'family_woman_woman_boy_boy':'\\ud83d\\udc69‍\\ud83d\\udc69‍\\ud83d\\udc66‍\\ud83d\\udc66',\n 'family_woman_woman_girl':'\\ud83d\\udc69‍\\ud83d\\udc69‍\\ud83d\\udc67',\n 'family_woman_woman_girl_boy':'\\ud83d\\udc69‍\\ud83d\\udc69‍\\ud83d\\udc67‍\\ud83d\\udc66',\n 'family_woman_woman_girl_girl':'\\ud83d\\udc69‍\\ud83d\\udc69‍\\ud83d\\udc67‍\\ud83d\\udc67',\n 'fast_forward':'\\u23e9',\n 'fax':'\\ud83d\\udce0',\n 'fearful':'\\ud83d\\ude28',\n 'feet':'\\ud83d\\udc3e',\n 'female_detective':'\\ud83d\\udd75\\ufe0f‍\\u2640\\ufe0f',\n 'ferris_wheel':'\\ud83c\\udfa1',\n 'ferry':'\\u26f4',\n 'field_hockey':'\\ud83c\\udfd1',\n 'file_cabinet':'\\ud83d\\uddc4',\n 'file_folder':'\\ud83d\\udcc1',\n 'film_projector':'\\ud83d\\udcfd',\n 'film_strip':'\\ud83c\\udf9e',\n 'fire':'\\ud83d\\udd25',\n 'fire_engine':'\\ud83d\\ude92',\n 'fireworks':'\\ud83c\\udf86',\n 'first_quarter_moon':'\\ud83c\\udf13',\n 'first_quarter_moon_with_face':'\\ud83c\\udf1b',\n 'fish':'\\ud83d\\udc1f',\n 'fish_cake':'\\ud83c\\udf65',\n 'fishing_pole_and_fish':'\\ud83c\\udfa3',\n 'fist_raised':'\\u270a',\n 'fist_left':'\\ud83e\\udd1b',\n 'fist_right':'\\ud83e\\udd1c',\n 'flags':'\\ud83c\\udf8f',\n 'flashlight':'\\ud83d\\udd26',\n 'fleur_de_lis':'\\u269c\\ufe0f',\n 'flight_arrival':'\\ud83d\\udeec',\n 'flight_departure':'\\ud83d\\udeeb',\n 'floppy_disk':'\\ud83d\\udcbe',\n 'flower_playing_cards':'\\ud83c\\udfb4',\n 'flushed':'\\ud83d\\ude33',\n 'fog':'\\ud83c\\udf2b',\n 'foggy':'\\ud83c\\udf01',\n 'football':'\\ud83c\\udfc8',\n 'footprints':'\\ud83d\\udc63',\n 'fork_and_knife':'\\ud83c\\udf74',\n 'fountain':'\\u26f2\\ufe0f',\n 'fountain_pen':'\\ud83d\\udd8b',\n 'four_leaf_clover':'\\ud83c\\udf40',\n 'fox_face':'\\ud83e\\udd8a',\n 'framed_picture':'\\ud83d\\uddbc',\n 'free':'\\ud83c\\udd93',\n 'fried_egg':'\\ud83c\\udf73',\n 'fried_shrimp':'\\ud83c\\udf64',\n 'fries':'\\ud83c\\udf5f',\n 'frog':'\\ud83d\\udc38',\n 'frowning':'\\ud83d\\ude26',\n 'frowning_face':'\\u2639\\ufe0f',\n 'frowning_man':'\\ud83d\\ude4d‍\\u2642\\ufe0f',\n 'frowning_woman':'\\ud83d\\ude4d',\n 'middle_finger':'\\ud83d\\udd95',\n 'fuelpump':'\\u26fd\\ufe0f',\n 'full_moon':'\\ud83c\\udf15',\n 'full_moon_with_face':'\\ud83c\\udf1d',\n 'funeral_urn':'\\u26b1\\ufe0f',\n 'game_die':'\\ud83c\\udfb2',\n 'gear':'\\u2699\\ufe0f',\n 'gem':'\\ud83d\\udc8e',\n 'gemini':'\\u264a\\ufe0f',\n 'ghost':'\\ud83d\\udc7b',\n 'gift':'\\ud83c\\udf81',\n 'gift_heart':'\\ud83d\\udc9d',\n 'girl':'\\ud83d\\udc67',\n 'globe_with_meridians':'\\ud83c\\udf10',\n 'goal_net':'\\ud83e\\udd45',\n 'goat':'\\ud83d\\udc10',\n 'golf':'\\u26f3\\ufe0f',\n 'golfing_man':'\\ud83c\\udfcc\\ufe0f',\n 'golfing_woman':'\\ud83c\\udfcc\\ufe0f‍\\u2640\\ufe0f',\n 'gorilla':'\\ud83e\\udd8d',\n 'grapes':'\\ud83c\\udf47',\n 'green_apple':'\\ud83c\\udf4f',\n 'green_book':'\\ud83d\\udcd7',\n 'green_heart':'\\ud83d\\udc9a',\n 'green_salad':'\\ud83e\\udd57',\n 'grey_exclamation':'\\u2755',\n 'grey_question':'\\u2754',\n 'grimacing':'\\ud83d\\ude2c',\n 'grin':'\\ud83d\\ude01',\n 'grinning':'\\ud83d\\ude00',\n 'guardsman':'\\ud83d\\udc82',\n 'guardswoman':'\\ud83d\\udc82‍\\u2640\\ufe0f',\n 'guitar':'\\ud83c\\udfb8',\n 'gun':'\\ud83d\\udd2b',\n 'haircut_woman':'\\ud83d\\udc87',\n 'haircut_man':'\\ud83d\\udc87‍\\u2642\\ufe0f',\n 'hamburger':'\\ud83c\\udf54',\n 'hammer':'\\ud83d\\udd28',\n 'hammer_and_pick':'\\u2692',\n 'hammer_and_wrench':'\\ud83d\\udee0',\n 'hamster':'\\ud83d\\udc39',\n 'hand':'\\u270b',\n 'handbag':'\\ud83d\\udc5c',\n 'handshake':'\\ud83e\\udd1d',\n 'hankey':'\\ud83d\\udca9',\n 'hatched_chick':'\\ud83d\\udc25',\n 'hatching_chick':'\\ud83d\\udc23',\n 'headphones':'\\ud83c\\udfa7',\n 'hear_no_evil':'\\ud83d\\ude49',\n 'heart':'\\u2764\\ufe0f',\n 'heart_decoration':'\\ud83d\\udc9f',\n 'heart_eyes':'\\ud83d\\ude0d',\n 'heart_eyes_cat':'\\ud83d\\ude3b',\n 'heartbeat':'\\ud83d\\udc93',\n 'heartpulse':'\\ud83d\\udc97',\n 'hearts':'\\u2665\\ufe0f',\n 'heavy_check_mark':'\\u2714\\ufe0f',\n 'heavy_division_sign':'\\u2797',\n 'heavy_dollar_sign':'\\ud83d\\udcb2',\n 'heavy_heart_exclamation':'\\u2763\\ufe0f',\n 'heavy_minus_sign':'\\u2796',\n 'heavy_multiplication_x':'\\u2716\\ufe0f',\n 'heavy_plus_sign':'\\u2795',\n 'helicopter':'\\ud83d\\ude81',\n 'herb':'\\ud83c\\udf3f',\n 'hibiscus':'\\ud83c\\udf3a',\n 'high_brightness':'\\ud83d\\udd06',\n 'high_heel':'\\ud83d\\udc60',\n 'hocho':'\\ud83d\\udd2a',\n 'hole':'\\ud83d\\udd73',\n 'honey_pot':'\\ud83c\\udf6f',\n 'horse':'\\ud83d\\udc34',\n 'horse_racing':'\\ud83c\\udfc7',\n 'hospital':'\\ud83c\\udfe5',\n 'hot_pepper':'\\ud83c\\udf36',\n 'hotdog':'\\ud83c\\udf2d',\n 'hotel':'\\ud83c\\udfe8',\n 'hotsprings':'\\u2668\\ufe0f',\n 'hourglass':'\\u231b\\ufe0f',\n 'hourglass_flowing_sand':'\\u23f3',\n 'house':'\\ud83c\\udfe0',\n 'house_with_garden':'\\ud83c\\udfe1',\n 'houses':'\\ud83c\\udfd8',\n 'hugs':'\\ud83e\\udd17',\n 'hushed':'\\ud83d\\ude2f',\n 'ice_cream':'\\ud83c\\udf68',\n 'ice_hockey':'\\ud83c\\udfd2',\n 'ice_skate':'\\u26f8',\n 'icecream':'\\ud83c\\udf66',\n 'id':'\\ud83c\\udd94',\n 'ideograph_advantage':'\\ud83c\\ude50',\n 'imp':'\\ud83d\\udc7f',\n 'inbox_tray':'\\ud83d\\udce5',\n 'incoming_envelope':'\\ud83d\\udce8',\n 'tipping_hand_woman':'\\ud83d\\udc81',\n 'information_source':'\\u2139\\ufe0f',\n 'innocent':'\\ud83d\\ude07',\n 'interrobang':'\\u2049\\ufe0f',\n 'iphone':'\\ud83d\\udcf1',\n 'izakaya_lantern':'\\ud83c\\udfee',\n 'jack_o_lantern':'\\ud83c\\udf83',\n 'japan':'\\ud83d\\uddfe',\n 'japanese_castle':'\\ud83c\\udfef',\n 'japanese_goblin':'\\ud83d\\udc7a',\n 'japanese_ogre':'\\ud83d\\udc79',\n 'jeans':'\\ud83d\\udc56',\n 'joy':'\\ud83d\\ude02',\n 'joy_cat':'\\ud83d\\ude39',\n 'joystick':'\\ud83d\\udd79',\n 'kaaba':'\\ud83d\\udd4b',\n 'key':'\\ud83d\\udd11',\n 'keyboard':'\\u2328\\ufe0f',\n 'keycap_ten':'\\ud83d\\udd1f',\n 'kick_scooter':'\\ud83d\\udef4',\n 'kimono':'\\ud83d\\udc58',\n 'kiss':'\\ud83d\\udc8b',\n 'kissing':'\\ud83d\\ude17',\n 'kissing_cat':'\\ud83d\\ude3d',\n 'kissing_closed_eyes':'\\ud83d\\ude1a',\n 'kissing_heart':'\\ud83d\\ude18',\n 'kissing_smiling_eyes':'\\ud83d\\ude19',\n 'kiwi_fruit':'\\ud83e\\udd5d',\n 'koala':'\\ud83d\\udc28',\n 'koko':'\\ud83c\\ude01',\n 'label':'\\ud83c\\udff7',\n 'large_blue_circle':'\\ud83d\\udd35',\n 'large_blue_diamond':'\\ud83d\\udd37',\n 'large_orange_diamond':'\\ud83d\\udd36',\n 'last_quarter_moon':'\\ud83c\\udf17',\n 'last_quarter_moon_with_face':'\\ud83c\\udf1c',\n 'latin_cross':'\\u271d\\ufe0f',\n 'laughing':'\\ud83d\\ude06',\n 'leaves':'\\ud83c\\udf43',\n 'ledger':'\\ud83d\\udcd2',\n 'left_luggage':'\\ud83d\\udec5',\n 'left_right_arrow':'\\u2194\\ufe0f',\n 'leftwards_arrow_with_hook':'\\u21a9\\ufe0f',\n 'lemon':'\\ud83c\\udf4b',\n 'leo':'\\u264c\\ufe0f',\n 'leopard':'\\ud83d\\udc06',\n 'level_slider':'\\ud83c\\udf9a',\n 'libra':'\\u264e\\ufe0f',\n 'light_rail':'\\ud83d\\ude88',\n 'link':'\\ud83d\\udd17',\n 'lion':'\\ud83e\\udd81',\n 'lips':'\\ud83d\\udc44',\n 'lipstick':'\\ud83d\\udc84',\n 'lizard':'\\ud83e\\udd8e',\n 'lock':'\\ud83d\\udd12',\n 'lock_with_ink_pen':'\\ud83d\\udd0f',\n 'lollipop':'\\ud83c\\udf6d',\n 'loop':'\\u27bf',\n 'loud_sound':'\\ud83d\\udd0a',\n 'loudspeaker':'\\ud83d\\udce2',\n 'love_hotel':'\\ud83c\\udfe9',\n 'love_letter':'\\ud83d\\udc8c',\n 'low_brightness':'\\ud83d\\udd05',\n 'lying_face':'\\ud83e\\udd25',\n 'm':'\\u24c2\\ufe0f',\n 'mag':'\\ud83d\\udd0d',\n 'mag_right':'\\ud83d\\udd0e',\n 'mahjong':'\\ud83c\\udc04\\ufe0f',\n 'mailbox':'\\ud83d\\udceb',\n 'mailbox_closed':'\\ud83d\\udcea',\n 'mailbox_with_mail':'\\ud83d\\udcec',\n 'mailbox_with_no_mail':'\\ud83d\\udced',\n 'man':'\\ud83d\\udc68',\n 'man_artist':'\\ud83d\\udc68‍\\ud83c\\udfa8',\n 'man_astronaut':'\\ud83d\\udc68‍\\ud83d\\ude80',\n 'man_cartwheeling':'\\ud83e\\udd38‍\\u2642\\ufe0f',\n 'man_cook':'\\ud83d\\udc68‍\\ud83c\\udf73',\n 'man_dancing':'\\ud83d\\udd7a',\n 'man_facepalming':'\\ud83e\\udd26‍\\u2642\\ufe0f',\n 'man_factory_worker':'\\ud83d\\udc68‍\\ud83c\\udfed',\n 'man_farmer':'\\ud83d\\udc68‍\\ud83c\\udf3e',\n 'man_firefighter':'\\ud83d\\udc68‍\\ud83d\\ude92',\n 'man_health_worker':'\\ud83d\\udc68‍\\u2695\\ufe0f',\n 'man_in_tuxedo':'\\ud83e\\udd35',\n 'man_judge':'\\ud83d\\udc68‍\\u2696\\ufe0f',\n 'man_juggling':'\\ud83e\\udd39‍\\u2642\\ufe0f',\n 'man_mechanic':'\\ud83d\\udc68‍\\ud83d\\udd27',\n 'man_office_worker':'\\ud83d\\udc68‍\\ud83d\\udcbc',\n 'man_pilot':'\\ud83d\\udc68‍\\u2708\\ufe0f',\n 'man_playing_handball':'\\ud83e\\udd3e‍\\u2642\\ufe0f',\n 'man_playing_water_polo':'\\ud83e\\udd3d‍\\u2642\\ufe0f',\n 'man_scientist':'\\ud83d\\udc68‍\\ud83d\\udd2c',\n 'man_shrugging':'\\ud83e\\udd37‍\\u2642\\ufe0f',\n 'man_singer':'\\ud83d\\udc68‍\\ud83c\\udfa4',\n 'man_student':'\\ud83d\\udc68‍\\ud83c\\udf93',\n 'man_teacher':'\\ud83d\\udc68‍\\ud83c\\udfeb',\n 'man_technologist':'\\ud83d\\udc68‍\\ud83d\\udcbb',\n 'man_with_gua_pi_mao':'\\ud83d\\udc72',\n 'man_with_turban':'\\ud83d\\udc73',\n 'tangerine':'\\ud83c\\udf4a',\n 'mans_shoe':'\\ud83d\\udc5e',\n 'mantelpiece_clock':'\\ud83d\\udd70',\n 'maple_leaf':'\\ud83c\\udf41',\n 'martial_arts_uniform':'\\ud83e\\udd4b',\n 'mask':'\\ud83d\\ude37',\n 'massage_woman':'\\ud83d\\udc86',\n 'massage_man':'\\ud83d\\udc86‍\\u2642\\ufe0f',\n 'meat_on_bone':'\\ud83c\\udf56',\n 'medal_military':'\\ud83c\\udf96',\n 'medal_sports':'\\ud83c\\udfc5',\n 'mega':'\\ud83d\\udce3',\n 'melon':'\\ud83c\\udf48',\n 'memo':'\\ud83d\\udcdd',\n 'men_wrestling':'\\ud83e\\udd3c‍\\u2642\\ufe0f',\n 'menorah':'\\ud83d\\udd4e',\n 'mens':'\\ud83d\\udeb9',\n 'metal':'\\ud83e\\udd18',\n 'metro':'\\ud83d\\ude87',\n 'microphone':'\\ud83c\\udfa4',\n 'microscope':'\\ud83d\\udd2c',\n 'milk_glass':'\\ud83e\\udd5b',\n 'milky_way':'\\ud83c\\udf0c',\n 'minibus':'\\ud83d\\ude90',\n 'minidisc':'\\ud83d\\udcbd',\n 'mobile_phone_off':'\\ud83d\\udcf4',\n 'money_mouth_face':'\\ud83e\\udd11',\n 'money_with_wings':'\\ud83d\\udcb8',\n 'moneybag':'\\ud83d\\udcb0',\n 'monkey':'\\ud83d\\udc12',\n 'monkey_face':'\\ud83d\\udc35',\n 'monorail':'\\ud83d\\ude9d',\n 'moon':'\\ud83c\\udf14',\n 'mortar_board':'\\ud83c\\udf93',\n 'mosque':'\\ud83d\\udd4c',\n 'motor_boat':'\\ud83d\\udee5',\n 'motor_scooter':'\\ud83d\\udef5',\n 'motorcycle':'\\ud83c\\udfcd',\n 'motorway':'\\ud83d\\udee3',\n 'mount_fuji':'\\ud83d\\uddfb',\n 'mountain':'\\u26f0',\n 'mountain_biking_man':'\\ud83d\\udeb5',\n 'mountain_biking_woman':'\\ud83d\\udeb5‍\\u2640\\ufe0f',\n 'mountain_cableway':'\\ud83d\\udea0',\n 'mountain_railway':'\\ud83d\\ude9e',\n 'mountain_snow':'\\ud83c\\udfd4',\n 'mouse':'\\ud83d\\udc2d',\n 'mouse2':'\\ud83d\\udc01',\n 'movie_camera':'\\ud83c\\udfa5',\n 'moyai':'\\ud83d\\uddff',\n 'mrs_claus':'\\ud83e\\udd36',\n 'muscle':'\\ud83d\\udcaa',\n 'mushroom':'\\ud83c\\udf44',\n 'musical_keyboard':'\\ud83c\\udfb9',\n 'musical_note':'\\ud83c\\udfb5',\n 'musical_score':'\\ud83c\\udfbc',\n 'mute':'\\ud83d\\udd07',\n 'nail_care':'\\ud83d\\udc85',\n 'name_badge':'\\ud83d\\udcdb',\n 'national_park':'\\ud83c\\udfde',\n 'nauseated_face':'\\ud83e\\udd22',\n 'necktie':'\\ud83d\\udc54',\n 'negative_squared_cross_mark':'\\u274e',\n 'nerd_face':'\\ud83e\\udd13',\n 'neutral_face':'\\ud83d\\ude10',\n 'new':'\\ud83c\\udd95',\n 'new_moon':'\\ud83c\\udf11',\n 'new_moon_with_face':'\\ud83c\\udf1a',\n 'newspaper':'\\ud83d\\udcf0',\n 'newspaper_roll':'\\ud83d\\uddde',\n 'next_track_button':'\\u23ed',\n 'ng':'\\ud83c\\udd96',\n 'no_good_man':'\\ud83d\\ude45‍\\u2642\\ufe0f',\n 'no_good_woman':'\\ud83d\\ude45',\n 'night_with_stars':'\\ud83c\\udf03',\n 'no_bell':'\\ud83d\\udd15',\n 'no_bicycles':'\\ud83d\\udeb3',\n 'no_entry':'\\u26d4\\ufe0f',\n 'no_entry_sign':'\\ud83d\\udeab',\n 'no_mobile_phones':'\\ud83d\\udcf5',\n 'no_mouth':'\\ud83d\\ude36',\n 'no_pedestrians':'\\ud83d\\udeb7',\n 'no_smoking':'\\ud83d\\udead',\n 'non-potable_water':'\\ud83d\\udeb1',\n 'nose':'\\ud83d\\udc43',\n 'notebook':'\\ud83d\\udcd3',\n 'notebook_with_decorative_cover':'\\ud83d\\udcd4',\n 'notes':'\\ud83c\\udfb6',\n 'nut_and_bolt':'\\ud83d\\udd29',\n 'o':'\\u2b55\\ufe0f',\n 'o2':'\\ud83c\\udd7e\\ufe0f',\n 'ocean':'\\ud83c\\udf0a',\n 'octopus':'\\ud83d\\udc19',\n 'oden':'\\ud83c\\udf62',\n 'office':'\\ud83c\\udfe2',\n 'oil_drum':'\\ud83d\\udee2',\n 'ok':'\\ud83c\\udd97',\n 'ok_hand':'\\ud83d\\udc4c',\n 'ok_man':'\\ud83d\\ude46‍\\u2642\\ufe0f',\n 'ok_woman':'\\ud83d\\ude46',\n 'old_key':'\\ud83d\\udddd',\n 'older_man':'\\ud83d\\udc74',\n 'older_woman':'\\ud83d\\udc75',\n 'om':'\\ud83d\\udd49',\n 'on':'\\ud83d\\udd1b',\n 'oncoming_automobile':'\\ud83d\\ude98',\n 'oncoming_bus':'\\ud83d\\ude8d',\n 'oncoming_police_car':'\\ud83d\\ude94',\n 'oncoming_taxi':'\\ud83d\\ude96',\n 'open_file_folder':'\\ud83d\\udcc2',\n 'open_hands':'\\ud83d\\udc50',\n 'open_mouth':'\\ud83d\\ude2e',\n 'open_umbrella':'\\u2602\\ufe0f',\n 'ophiuchus':'\\u26ce',\n 'orange_book':'\\ud83d\\udcd9',\n 'orthodox_cross':'\\u2626\\ufe0f',\n 'outbox_tray':'\\ud83d\\udce4',\n 'owl':'\\ud83e\\udd89',\n 'ox':'\\ud83d\\udc02',\n 'package':'\\ud83d\\udce6',\n 'page_facing_up':'\\ud83d\\udcc4',\n 'page_with_curl':'\\ud83d\\udcc3',\n 'pager':'\\ud83d\\udcdf',\n 'paintbrush':'\\ud83d\\udd8c',\n 'palm_tree':'\\ud83c\\udf34',\n 'pancakes':'\\ud83e\\udd5e',\n 'panda_face':'\\ud83d\\udc3c',\n 'paperclip':'\\ud83d\\udcce',\n 'paperclips':'\\ud83d\\udd87',\n 'parasol_on_ground':'\\u26f1',\n 'parking':'\\ud83c\\udd7f\\ufe0f',\n 'part_alternation_mark':'\\u303d\\ufe0f',\n 'partly_sunny':'\\u26c5\\ufe0f',\n 'passenger_ship':'\\ud83d\\udef3',\n 'passport_control':'\\ud83d\\udec2',\n 'pause_button':'\\u23f8',\n 'peace_symbol':'\\u262e\\ufe0f',\n 'peach':'\\ud83c\\udf51',\n 'peanuts':'\\ud83e\\udd5c',\n 'pear':'\\ud83c\\udf50',\n 'pen':'\\ud83d\\udd8a',\n 'pencil2':'\\u270f\\ufe0f',\n 'penguin':'\\ud83d\\udc27',\n 'pensive':'\\ud83d\\ude14',\n 'performing_arts':'\\ud83c\\udfad',\n 'persevere':'\\ud83d\\ude23',\n 'person_fencing':'\\ud83e\\udd3a',\n 'pouting_woman':'\\ud83d\\ude4e',\n 'phone':'\\u260e\\ufe0f',\n 'pick':'\\u26cf',\n 'pig':'\\ud83d\\udc37',\n 'pig2':'\\ud83d\\udc16',\n 'pig_nose':'\\ud83d\\udc3d',\n 'pill':'\\ud83d\\udc8a',\n 'pineapple':'\\ud83c\\udf4d',\n 'ping_pong':'\\ud83c\\udfd3',\n 'pisces':'\\u2653\\ufe0f',\n 'pizza':'\\ud83c\\udf55',\n 'place_of_worship':'\\ud83d\\uded0',\n 'plate_with_cutlery':'\\ud83c\\udf7d',\n 'play_or_pause_button':'\\u23ef',\n 'point_down':'\\ud83d\\udc47',\n 'point_left':'\\ud83d\\udc48',\n 'point_right':'\\ud83d\\udc49',\n 'point_up':'\\u261d\\ufe0f',\n 'point_up_2':'\\ud83d\\udc46',\n 'police_car':'\\ud83d\\ude93',\n 'policewoman':'\\ud83d\\udc6e‍\\u2640\\ufe0f',\n 'poodle':'\\ud83d\\udc29',\n 'popcorn':'\\ud83c\\udf7f',\n 'post_office':'\\ud83c\\udfe3',\n 'postal_horn':'\\ud83d\\udcef',\n 'postbox':'\\ud83d\\udcee',\n 'potable_water':'\\ud83d\\udeb0',\n 'potato':'\\ud83e\\udd54',\n 'pouch':'\\ud83d\\udc5d',\n 'poultry_leg':'\\ud83c\\udf57',\n 'pound':'\\ud83d\\udcb7',\n 'rage':'\\ud83d\\ude21',\n 'pouting_cat':'\\ud83d\\ude3e',\n 'pouting_man':'\\ud83d\\ude4e‍\\u2642\\ufe0f',\n 'pray':'\\ud83d\\ude4f',\n 'prayer_beads':'\\ud83d\\udcff',\n 'pregnant_woman':'\\ud83e\\udd30',\n 'previous_track_button':'\\u23ee',\n 'prince':'\\ud83e\\udd34',\n 'princess':'\\ud83d\\udc78',\n 'printer':'\\ud83d\\udda8',\n 'purple_heart':'\\ud83d\\udc9c',\n 'purse':'\\ud83d\\udc5b',\n 'pushpin':'\\ud83d\\udccc',\n 'put_litter_in_its_place':'\\ud83d\\udeae',\n 'question':'\\u2753',\n 'rabbit':'\\ud83d\\udc30',\n 'rabbit2':'\\ud83d\\udc07',\n 'racehorse':'\\ud83d\\udc0e',\n 'racing_car':'\\ud83c\\udfce',\n 'radio':'\\ud83d\\udcfb',\n 'radio_button':'\\ud83d\\udd18',\n 'radioactive':'\\u2622\\ufe0f',\n 'railway_car':'\\ud83d\\ude83',\n 'railway_track':'\\ud83d\\udee4',\n 'rainbow':'\\ud83c\\udf08',\n 'rainbow_flag':'\\ud83c\\udff3\\ufe0f‍\\ud83c\\udf08',\n 'raised_back_of_hand':'\\ud83e\\udd1a',\n 'raised_hand_with_fingers_splayed':'\\ud83d\\udd90',\n 'raised_hands':'\\ud83d\\ude4c',\n 'raising_hand_woman':'\\ud83d\\ude4b',\n 'raising_hand_man':'\\ud83d\\ude4b‍\\u2642\\ufe0f',\n 'ram':'\\ud83d\\udc0f',\n 'ramen':'\\ud83c\\udf5c',\n 'rat':'\\ud83d\\udc00',\n 'record_button':'\\u23fa',\n 'recycle':'\\u267b\\ufe0f',\n 'red_circle':'\\ud83d\\udd34',\n 'registered':'\\u00ae\\ufe0f',\n 'relaxed':'\\u263a\\ufe0f',\n 'relieved':'\\ud83d\\ude0c',\n 'reminder_ribbon':'\\ud83c\\udf97',\n 'repeat':'\\ud83d\\udd01',\n 'repeat_one':'\\ud83d\\udd02',\n 'rescue_worker_helmet':'\\u26d1',\n 'restroom':'\\ud83d\\udebb',\n 'revolving_hearts':'\\ud83d\\udc9e',\n 'rewind':'\\u23ea',\n 'rhinoceros':'\\ud83e\\udd8f',\n 'ribbon':'\\ud83c\\udf80',\n 'rice':'\\ud83c\\udf5a',\n 'rice_ball':'\\ud83c\\udf59',\n 'rice_cracker':'\\ud83c\\udf58',\n 'rice_scene':'\\ud83c\\udf91',\n 'right_anger_bubble':'\\ud83d\\uddef',\n 'ring':'\\ud83d\\udc8d',\n 'robot':'\\ud83e\\udd16',\n 'rocket':'\\ud83d\\ude80',\n 'rofl':'\\ud83e\\udd23',\n 'roll_eyes':'\\ud83d\\ude44',\n 'roller_coaster':'\\ud83c\\udfa2',\n 'rooster':'\\ud83d\\udc13',\n 'rose':'\\ud83c\\udf39',\n 'rosette':'\\ud83c\\udff5',\n 'rotating_light':'\\ud83d\\udea8',\n 'round_pushpin':'\\ud83d\\udccd',\n 'rowing_man':'\\ud83d\\udea3',\n 'rowing_woman':'\\ud83d\\udea3‍\\u2640\\ufe0f',\n 'rugby_football':'\\ud83c\\udfc9',\n 'running_man':'\\ud83c\\udfc3',\n 'running_shirt_with_sash':'\\ud83c\\udfbd',\n 'running_woman':'\\ud83c\\udfc3‍\\u2640\\ufe0f',\n 'sa':'\\ud83c\\ude02\\ufe0f',\n 'sagittarius':'\\u2650\\ufe0f',\n 'sake':'\\ud83c\\udf76',\n 'sandal':'\\ud83d\\udc61',\n 'santa':'\\ud83c\\udf85',\n 'satellite':'\\ud83d\\udce1',\n 'saxophone':'\\ud83c\\udfb7',\n 'school':'\\ud83c\\udfeb',\n 'school_satchel':'\\ud83c\\udf92',\n 'scissors':'\\u2702\\ufe0f',\n 'scorpion':'\\ud83e\\udd82',\n 'scorpius':'\\u264f\\ufe0f',\n 'scream':'\\ud83d\\ude31',\n 'scream_cat':'\\ud83d\\ude40',\n 'scroll':'\\ud83d\\udcdc',\n 'seat':'\\ud83d\\udcba',\n 'secret':'\\u3299\\ufe0f',\n 'see_no_evil':'\\ud83d\\ude48',\n 'seedling':'\\ud83c\\udf31',\n 'selfie':'\\ud83e\\udd33',\n 'shallow_pan_of_food':'\\ud83e\\udd58',\n 'shamrock':'\\u2618\\ufe0f',\n 'shark':'\\ud83e\\udd88',\n 'shaved_ice':'\\ud83c\\udf67',\n 'sheep':'\\ud83d\\udc11',\n 'shell':'\\ud83d\\udc1a',\n 'shield':'\\ud83d\\udee1',\n 'shinto_shrine':'\\u26e9',\n 'ship':'\\ud83d\\udea2',\n 'shirt':'\\ud83d\\udc55',\n 'shopping':'\\ud83d\\udecd',\n 'shopping_cart':'\\ud83d\\uded2',\n 'shower':'\\ud83d\\udebf',\n 'shrimp':'\\ud83e\\udd90',\n 'signal_strength':'\\ud83d\\udcf6',\n 'six_pointed_star':'\\ud83d\\udd2f',\n 'ski':'\\ud83c\\udfbf',\n 'skier':'\\u26f7',\n 'skull':'\\ud83d\\udc80',\n 'skull_and_crossbones':'\\u2620\\ufe0f',\n 'sleeping':'\\ud83d\\ude34',\n 'sleeping_bed':'\\ud83d\\udecc',\n 'sleepy':'\\ud83d\\ude2a',\n 'slightly_frowning_face':'\\ud83d\\ude41',\n 'slightly_smiling_face':'\\ud83d\\ude42',\n 'slot_machine':'\\ud83c\\udfb0',\n 'small_airplane':'\\ud83d\\udee9',\n 'small_blue_diamond':'\\ud83d\\udd39',\n 'small_orange_diamond':'\\ud83d\\udd38',\n 'small_red_triangle':'\\ud83d\\udd3a',\n 'small_red_triangle_down':'\\ud83d\\udd3b',\n 'smile':'\\ud83d\\ude04',\n 'smile_cat':'\\ud83d\\ude38',\n 'smiley':'\\ud83d\\ude03',\n 'smiley_cat':'\\ud83d\\ude3a',\n 'smiling_imp':'\\ud83d\\ude08',\n 'smirk':'\\ud83d\\ude0f',\n 'smirk_cat':'\\ud83d\\ude3c',\n 'smoking':'\\ud83d\\udeac',\n 'snail':'\\ud83d\\udc0c',\n 'snake':'\\ud83d\\udc0d',\n 'sneezing_face':'\\ud83e\\udd27',\n 'snowboarder':'\\ud83c\\udfc2',\n 'snowflake':'\\u2744\\ufe0f',\n 'snowman':'\\u26c4\\ufe0f',\n 'snowman_with_snow':'\\u2603\\ufe0f',\n 'sob':'\\ud83d\\ude2d',\n 'soccer':'\\u26bd\\ufe0f',\n 'soon':'\\ud83d\\udd1c',\n 'sos':'\\ud83c\\udd98',\n 'sound':'\\ud83d\\udd09',\n 'space_invader':'\\ud83d\\udc7e',\n 'spades':'\\u2660\\ufe0f',\n 'spaghetti':'\\ud83c\\udf5d',\n 'sparkle':'\\u2747\\ufe0f',\n 'sparkler':'\\ud83c\\udf87',\n 'sparkles':'\\u2728',\n 'sparkling_heart':'\\ud83d\\udc96',\n 'speak_no_evil':'\\ud83d\\ude4a',\n 'speaker':'\\ud83d\\udd08',\n 'speaking_head':'\\ud83d\\udde3',\n 'speech_balloon':'\\ud83d\\udcac',\n 'speedboat':'\\ud83d\\udea4',\n 'spider':'\\ud83d\\udd77',\n 'spider_web':'\\ud83d\\udd78',\n 'spiral_calendar':'\\ud83d\\uddd3',\n 'spiral_notepad':'\\ud83d\\uddd2',\n 'spoon':'\\ud83e\\udd44',\n 'squid':'\\ud83e\\udd91',\n 'stadium':'\\ud83c\\udfdf',\n 'star':'\\u2b50\\ufe0f',\n 'star2':'\\ud83c\\udf1f',\n 'star_and_crescent':'\\u262a\\ufe0f',\n 'star_of_david':'\\u2721\\ufe0f',\n 'stars':'\\ud83c\\udf20',\n 'station':'\\ud83d\\ude89',\n 'statue_of_liberty':'\\ud83d\\uddfd',\n 'steam_locomotive':'\\ud83d\\ude82',\n 'stew':'\\ud83c\\udf72',\n 'stop_button':'\\u23f9',\n 'stop_sign':'\\ud83d\\uded1',\n 'stopwatch':'\\u23f1',\n 'straight_ruler':'\\ud83d\\udccf',\n 'strawberry':'\\ud83c\\udf53',\n 'stuck_out_tongue':'\\ud83d\\ude1b',\n 'stuck_out_tongue_closed_eyes':'\\ud83d\\ude1d',\n 'stuck_out_tongue_winking_eye':'\\ud83d\\ude1c',\n 'studio_microphone':'\\ud83c\\udf99',\n 'stuffed_flatbread':'\\ud83e\\udd59',\n 'sun_behind_large_cloud':'\\ud83c\\udf25',\n 'sun_behind_rain_cloud':'\\ud83c\\udf26',\n 'sun_behind_small_cloud':'\\ud83c\\udf24',\n 'sun_with_face':'\\ud83c\\udf1e',\n 'sunflower':'\\ud83c\\udf3b',\n 'sunglasses':'\\ud83d\\ude0e',\n 'sunny':'\\u2600\\ufe0f',\n 'sunrise':'\\ud83c\\udf05',\n 'sunrise_over_mountains':'\\ud83c\\udf04',\n 'surfing_man':'\\ud83c\\udfc4',\n 'surfing_woman':'\\ud83c\\udfc4‍\\u2640\\ufe0f',\n 'sushi':'\\ud83c\\udf63',\n 'suspension_railway':'\\ud83d\\ude9f',\n 'sweat':'\\ud83d\\ude13',\n 'sweat_drops':'\\ud83d\\udca6',\n 'sweat_smile':'\\ud83d\\ude05',\n 'sweet_potato':'\\ud83c\\udf60',\n 'swimming_man':'\\ud83c\\udfca',\n 'swimming_woman':'\\ud83c\\udfca‍\\u2640\\ufe0f',\n 'symbols':'\\ud83d\\udd23',\n 'synagogue':'\\ud83d\\udd4d',\n 'syringe':'\\ud83d\\udc89',\n 'taco':'\\ud83c\\udf2e',\n 'tada':'\\ud83c\\udf89',\n 'tanabata_tree':'\\ud83c\\udf8b',\n 'taurus':'\\u2649\\ufe0f',\n 'taxi':'\\ud83d\\ude95',\n 'tea':'\\ud83c\\udf75',\n 'telephone_receiver':'\\ud83d\\udcde',\n 'telescope':'\\ud83d\\udd2d',\n 'tennis':'\\ud83c\\udfbe',\n 'tent':'\\u26fa\\ufe0f',\n 'thermometer':'\\ud83c\\udf21',\n 'thinking':'\\ud83e\\udd14',\n 'thought_balloon':'\\ud83d\\udcad',\n 'ticket':'\\ud83c\\udfab',\n 'tickets':'\\ud83c\\udf9f',\n 'tiger':'\\ud83d\\udc2f',\n 'tiger2':'\\ud83d\\udc05',\n 'timer_clock':'\\u23f2',\n 'tipping_hand_man':'\\ud83d\\udc81‍\\u2642\\ufe0f',\n 'tired_face':'\\ud83d\\ude2b',\n 'tm':'\\u2122\\ufe0f',\n 'toilet':'\\ud83d\\udebd',\n 'tokyo_tower':'\\ud83d\\uddfc',\n 'tomato':'\\ud83c\\udf45',\n 'tongue':'\\ud83d\\udc45',\n 'top':'\\ud83d\\udd1d',\n 'tophat':'\\ud83c\\udfa9',\n 'tornado':'\\ud83c\\udf2a',\n 'trackball':'\\ud83d\\uddb2',\n 'tractor':'\\ud83d\\ude9c',\n 'traffic_light':'\\ud83d\\udea5',\n 'train':'\\ud83d\\ude8b',\n 'train2':'\\ud83d\\ude86',\n 'tram':'\\ud83d\\ude8a',\n 'triangular_flag_on_post':'\\ud83d\\udea9',\n 'triangular_ruler':'\\ud83d\\udcd0',\n 'trident':'\\ud83d\\udd31',\n 'triumph':'\\ud83d\\ude24',\n 'trolleybus':'\\ud83d\\ude8e',\n 'trophy':'\\ud83c\\udfc6',\n 'tropical_drink':'\\ud83c\\udf79',\n 'tropical_fish':'\\ud83d\\udc20',\n 'truck':'\\ud83d\\ude9a',\n 'trumpet':'\\ud83c\\udfba',\n 'tulip':'\\ud83c\\udf37',\n 'tumbler_glass':'\\ud83e\\udd43',\n 'turkey':'\\ud83e\\udd83',\n 'turtle':'\\ud83d\\udc22',\n 'tv':'\\ud83d\\udcfa',\n 'twisted_rightwards_arrows':'\\ud83d\\udd00',\n 'two_hearts':'\\ud83d\\udc95',\n 'two_men_holding_hands':'\\ud83d\\udc6c',\n 'two_women_holding_hands':'\\ud83d\\udc6d',\n 'u5272':'\\ud83c\\ude39',\n 'u5408':'\\ud83c\\ude34',\n 'u55b6':'\\ud83c\\ude3a',\n 'u6307':'\\ud83c\\ude2f\\ufe0f',\n 'u6708':'\\ud83c\\ude37\\ufe0f',\n 'u6709':'\\ud83c\\ude36',\n 'u6e80':'\\ud83c\\ude35',\n 'u7121':'\\ud83c\\ude1a\\ufe0f',\n 'u7533':'\\ud83c\\ude38',\n 'u7981':'\\ud83c\\ude32',\n 'u7a7a':'\\ud83c\\ude33',\n 'umbrella':'\\u2614\\ufe0f',\n 'unamused':'\\ud83d\\ude12',\n 'underage':'\\ud83d\\udd1e',\n 'unicorn':'\\ud83e\\udd84',\n 'unlock':'\\ud83d\\udd13',\n 'up':'\\ud83c\\udd99',\n 'upside_down_face':'\\ud83d\\ude43',\n 'v':'\\u270c\\ufe0f',\n 'vertical_traffic_light':'\\ud83d\\udea6',\n 'vhs':'\\ud83d\\udcfc',\n 'vibration_mode':'\\ud83d\\udcf3',\n 'video_camera':'\\ud83d\\udcf9',\n 'video_game':'\\ud83c\\udfae',\n 'violin':'\\ud83c\\udfbb',\n 'virgo':'\\u264d\\ufe0f',\n 'volcano':'\\ud83c\\udf0b',\n 'volleyball':'\\ud83c\\udfd0',\n 'vs':'\\ud83c\\udd9a',\n 'vulcan_salute':'\\ud83d\\udd96',\n 'walking_man':'\\ud83d\\udeb6',\n 'walking_woman':'\\ud83d\\udeb6‍\\u2640\\ufe0f',\n 'waning_crescent_moon':'\\ud83c\\udf18',\n 'waning_gibbous_moon':'\\ud83c\\udf16',\n 'warning':'\\u26a0\\ufe0f',\n 'wastebasket':'\\ud83d\\uddd1',\n 'watch':'\\u231a\\ufe0f',\n 'water_buffalo':'\\ud83d\\udc03',\n 'watermelon':'\\ud83c\\udf49',\n 'wave':'\\ud83d\\udc4b',\n 'wavy_dash':'\\u3030\\ufe0f',\n 'waxing_crescent_moon':'\\ud83c\\udf12',\n 'wc':'\\ud83d\\udebe',\n 'weary':'\\ud83d\\ude29',\n 'wedding':'\\ud83d\\udc92',\n 'weight_lifting_man':'\\ud83c\\udfcb\\ufe0f',\n 'weight_lifting_woman':'\\ud83c\\udfcb\\ufe0f‍\\u2640\\ufe0f',\n 'whale':'\\ud83d\\udc33',\n 'whale2':'\\ud83d\\udc0b',\n 'wheel_of_dharma':'\\u2638\\ufe0f',\n 'wheelchair':'\\u267f\\ufe0f',\n 'white_check_mark':'\\u2705',\n 'white_circle':'\\u26aa\\ufe0f',\n 'white_flag':'\\ud83c\\udff3\\ufe0f',\n 'white_flower':'\\ud83d\\udcae',\n 'white_large_square':'\\u2b1c\\ufe0f',\n 'white_medium_small_square':'\\u25fd\\ufe0f',\n 'white_medium_square':'\\u25fb\\ufe0f',\n 'white_small_square':'\\u25ab\\ufe0f',\n 'white_square_button':'\\ud83d\\udd33',\n 'wilted_flower':'\\ud83e\\udd40',\n 'wind_chime':'\\ud83c\\udf90',\n 'wind_face':'\\ud83c\\udf2c',\n 'wine_glass':'\\ud83c\\udf77',\n 'wink':'\\ud83d\\ude09',\n 'wolf':'\\ud83d\\udc3a',\n 'woman':'\\ud83d\\udc69',\n 'woman_artist':'\\ud83d\\udc69‍\\ud83c\\udfa8',\n 'woman_astronaut':'\\ud83d\\udc69‍\\ud83d\\ude80',\n 'woman_cartwheeling':'\\ud83e\\udd38‍\\u2640\\ufe0f',\n 'woman_cook':'\\ud83d\\udc69‍\\ud83c\\udf73',\n 'woman_facepalming':'\\ud83e\\udd26‍\\u2640\\ufe0f',\n 'woman_factory_worker':'\\ud83d\\udc69‍\\ud83c\\udfed',\n 'woman_farmer':'\\ud83d\\udc69‍\\ud83c\\udf3e',\n 'woman_firefighter':'\\ud83d\\udc69‍\\ud83d\\ude92',\n 'woman_health_worker':'\\ud83d\\udc69‍\\u2695\\ufe0f',\n 'woman_judge':'\\ud83d\\udc69‍\\u2696\\ufe0f',\n 'woman_juggling':'\\ud83e\\udd39‍\\u2640\\ufe0f',\n 'woman_mechanic':'\\ud83d\\udc69‍\\ud83d\\udd27',\n 'woman_office_worker':'\\ud83d\\udc69‍\\ud83d\\udcbc',\n 'woman_pilot':'\\ud83d\\udc69‍\\u2708\\ufe0f',\n 'woman_playing_handball':'\\ud83e\\udd3e‍\\u2640\\ufe0f',\n 'woman_playing_water_polo':'\\ud83e\\udd3d‍\\u2640\\ufe0f',\n 'woman_scientist':'\\ud83d\\udc69‍\\ud83d\\udd2c',\n 'woman_shrugging':'\\ud83e\\udd37‍\\u2640\\ufe0f',\n 'woman_singer':'\\ud83d\\udc69‍\\ud83c\\udfa4',\n 'woman_student':'\\ud83d\\udc69‍\\ud83c\\udf93',\n 'woman_teacher':'\\ud83d\\udc69‍\\ud83c\\udfeb',\n 'woman_technologist':'\\ud83d\\udc69‍\\ud83d\\udcbb',\n 'woman_with_turban':'\\ud83d\\udc73‍\\u2640\\ufe0f',\n 'womans_clothes':'\\ud83d\\udc5a',\n 'womans_hat':'\\ud83d\\udc52',\n 'women_wrestling':'\\ud83e\\udd3c‍\\u2640\\ufe0f',\n 'womens':'\\ud83d\\udeba',\n 'world_map':'\\ud83d\\uddfa',\n 'worried':'\\ud83d\\ude1f',\n 'wrench':'\\ud83d\\udd27',\n 'writing_hand':'\\u270d\\ufe0f',\n 'x':'\\u274c',\n 'yellow_heart':'\\ud83d\\udc9b',\n 'yen':'\\ud83d\\udcb4',\n 'yin_yang':'\\u262f\\ufe0f',\n 'yum':'\\ud83d\\ude0b',\n 'zap':'\\u26a1\\ufe0f',\n 'zipper_mouth_face':'\\ud83e\\udd10',\n 'zzz':'\\ud83d\\udca4',\n\n /* special emojis :P */\n 'octocat': '',\n 'showdown': ''\n};\n","/**\n * Created by Estevao on 31-05-2015.\n */\n\n/**\n * Showdown Converter class\n * @class\n * @param {object} [converterOptions]\n * @returns {Converter}\n */\nshowdown.Converter = function (converterOptions) {\n 'use strict';\n\n var\n /**\n * Options used by this converter\n * @private\n * @type {{}}\n */\n options = {},\n\n /**\n * Language extensions used by this converter\n * @private\n * @type {Array}\n */\n langExtensions = [],\n\n /**\n * Output modifiers extensions used by this converter\n * @private\n * @type {Array}\n */\n outputModifiers = [],\n\n /**\n * Event listeners\n * @private\n * @type {{}}\n */\n listeners = {},\n\n /**\n * The flavor set in this converter\n */\n setConvFlavor = setFlavor,\n\n /**\n * Metadata of the document\n * @type {{parsed: {}, raw: string, format: string}}\n */\n metadata = {\n parsed: {},\n raw: '',\n format: ''\n };\n\n _constructor();\n\n /**\n * Converter constructor\n * @private\n */\n function _constructor () {\n converterOptions = converterOptions || {};\n\n for (var gOpt in globalOptions) {\n if (globalOptions.hasOwnProperty(gOpt)) {\n options[gOpt] = globalOptions[gOpt];\n }\n }\n\n // Merge options\n if (typeof converterOptions === 'object') {\n for (var opt in converterOptions) {\n if (converterOptions.hasOwnProperty(opt)) {\n options[opt] = converterOptions[opt];\n }\n }\n } else {\n throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +\n ' was passed instead.');\n }\n\n if (options.extensions) {\n showdown.helper.forEach(options.extensions, _parseExtension);\n }\n }\n\n /**\n * Parse extension\n * @param {*} ext\n * @param {string} [name='']\n * @private\n */\n function _parseExtension (ext, name) {\n\n name = name || null;\n // If it's a string, the extension was previously loaded\n if (showdown.helper.isString(ext)) {\n ext = showdown.helper.stdExtName(ext);\n name = ext;\n\n // LEGACY_SUPPORT CODE\n if (showdown.extensions[ext]) {\n console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +\n 'Please inform the developer that the extension should be updated!');\n legacyExtensionLoading(showdown.extensions[ext], ext);\n return;\n // END LEGACY SUPPORT CODE\n\n } else if (!showdown.helper.isUndefined(extensions[ext])) {\n ext = extensions[ext];\n\n } else {\n throw Error('Extension \"' + ext + '\" could not be loaded. It was either not found or is not a valid extension.');\n }\n }\n\n if (typeof ext === 'function') {\n ext = ext();\n }\n\n if (!showdown.helper.isArray(ext)) {\n ext = [ext];\n }\n\n var validExt = validate(ext, name);\n if (!validExt.valid) {\n throw Error(validExt.error);\n }\n\n for (var i = 0; i < ext.length; ++i) {\n switch (ext[i].type) {\n\n case 'lang':\n langExtensions.push(ext[i]);\n break;\n\n case 'output':\n outputModifiers.push(ext[i]);\n break;\n }\n if (ext[i].hasOwnProperty('listeners')) {\n for (var ln in ext[i].listeners) {\n if (ext[i].listeners.hasOwnProperty(ln)) {\n listen(ln, ext[i].listeners[ln]);\n }\n }\n }\n }\n\n }\n\n /**\n * LEGACY_SUPPORT\n * @param {*} ext\n * @param {string} name\n */\n function legacyExtensionLoading (ext, name) {\n if (typeof ext === 'function') {\n ext = ext(new showdown.Converter());\n }\n if (!showdown.helper.isArray(ext)) {\n ext = [ext];\n }\n var valid = validate(ext, name);\n\n if (!valid.valid) {\n throw Error(valid.error);\n }\n\n for (var i = 0; i < ext.length; ++i) {\n switch (ext[i].type) {\n case 'lang':\n langExtensions.push(ext[i]);\n break;\n case 'output':\n outputModifiers.push(ext[i]);\n break;\n default:// should never reach here\n throw Error('Extension loader error: Type unrecognized!!!');\n }\n }\n }\n\n /**\n * Listen to an event\n * @param {string} name\n * @param {function} callback\n */\n function listen (name, callback) {\n if (!showdown.helper.isString(name)) {\n throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');\n }\n\n if (typeof callback !== 'function') {\n throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');\n }\n\n if (!listeners.hasOwnProperty(name)) {\n listeners[name] = [];\n }\n listeners[name].push(callback);\n }\n\n function rTrimInputText (text) {\n var rsp = text.match(/^\\s*/)[0].length,\n rgx = new RegExp('^\\\\s{0,' + rsp + '}', 'gm');\n return text.replace(rgx, '');\n }\n\n /**\n * Dispatch an event\n * @private\n * @param {string} evtName Event name\n * @param {string} text Text\n * @param {{}} options Converter Options\n * @param {{}} globals\n * @returns {string}\n */\n this._dispatch = function dispatch (evtName, text, options, globals) {\n if (listeners.hasOwnProperty(evtName)) {\n for (var ei = 0; ei < listeners[evtName].length; ++ei) {\n var nText = listeners[evtName][ei](evtName, text, this, options, globals);\n if (nText && typeof nText !== 'undefined') {\n text = nText;\n }\n }\n }\n return text;\n };\n\n /**\n * Listen to an event\n * @param {string} name\n * @param {function} callback\n * @returns {showdown.Converter}\n */\n this.listen = function (name, callback) {\n listen(name, callback);\n return this;\n };\n\n /**\n * Converts a markdown string into HTML\n * @param {string} text\n * @returns {*}\n */\n this.makeHtml = function (text) {\n //check if text is not falsy\n if (!text) {\n return text;\n }\n\n var globals = {\n gHtmlBlocks: [],\n gHtmlMdBlocks: [],\n gHtmlSpans: [],\n gUrls: {},\n gTitles: {},\n gDimensions: {},\n gListLevel: 0,\n hashLinkCounts: {},\n langExtensions: langExtensions,\n outputModifiers: outputModifiers,\n converter: this,\n ghCodeBlocks: [],\n metadata: {\n parsed: {},\n raw: '',\n format: ''\n }\n };\n\n // This lets us use ¨ trema as an escape char to avoid md5 hashes\n // The choice of character is arbitrary; anything that isn't\n // magic in Markdown will work.\n text = text.replace(/¨/g, '¨T');\n\n // Replace $ with ¨D\n // RegExp interprets $ as a special character\n // when it's in a replacement string\n text = text.replace(/\\$/g, '¨D');\n\n // Standardize line endings\n text = text.replace(/\\r\\n/g, '\\n'); // DOS to Unix\n text = text.replace(/\\r/g, '\\n'); // Mac to Unix\n\n // Stardardize line spaces (nbsp causes trouble in older browsers and some regex flavors)\n text = text.replace(/\\u00A0/g, ' ');\n\n if (options.smartIndentationFix) {\n text = rTrimInputText(text);\n }\n\n // Make sure text begins and ends with a couple of newlines:\n text = '\\n\\n' + text + '\\n\\n';\n\n // detab\n text = showdown.subParser('detab')(text, options, globals);\n\n /**\n * Strip any lines consisting only of spaces and tabs.\n * This makes subsequent regexs easier to write, because we can\n * match consecutive blank lines with /\\n+/ instead of something\n * contorted like /[ \\t]*\\n+/\n */\n text = text.replace(/^[ \\t]+$/mg, '');\n\n //run languageExtensions\n showdown.helper.forEach(langExtensions, function (ext) {\n text = showdown.subParser('runExtension')(ext, text, options, globals);\n });\n\n // run the sub parsers\n text = showdown.subParser('metadata')(text, options, globals);\n text = showdown.subParser('hashPreCodeTags')(text, options, globals);\n text = showdown.subParser('githubCodeBlocks')(text, options, globals);\n text = showdown.subParser('hashHTMLBlocks')(text, options, globals);\n text = showdown.subParser('hashCodeTags')(text, options, globals);\n text = showdown.subParser('stripLinkDefinitions')(text, options, globals);\n text = showdown.subParser('blockGamut')(text, options, globals);\n text = showdown.subParser('unhashHTMLSpans')(text, options, globals);\n text = showdown.subParser('unescapeSpecialChars')(text, options, globals);\n\n // attacklab: Restore dollar signs\n text = text.replace(/¨D/g, '$$');\n\n // attacklab: Restore tremas\n text = text.replace(/¨T/g, '¨');\n\n // render a complete html document instead of a partial if the option is enabled\n text = showdown.subParser('completeHTMLDocument')(text, options, globals);\n\n // Run output modifiers\n showdown.helper.forEach(outputModifiers, function (ext) {\n text = showdown.subParser('runExtension')(ext, text, options, globals);\n });\n\n // update metadata\n metadata = globals.metadata;\n return text;\n };\n\n /**\n * Set an option of this Converter instance\n * @param {string} key\n * @param {*} value\n */\n this.setOption = function (key, value) {\n options[key] = value;\n };\n\n /**\n * Get the option of this Converter instance\n * @param {string} key\n * @returns {*}\n */\n this.getOption = function (key) {\n return options[key];\n };\n\n /**\n * Get the options of this Converter instance\n * @returns {{}}\n */\n this.getOptions = function () {\n return options;\n };\n\n /**\n * Add extension to THIS converter\n * @param {{}} extension\n * @param {string} [name=null]\n */\n this.addExtension = function (extension, name) {\n name = name || null;\n _parseExtension(extension, name);\n };\n\n /**\n * Use a global registered extension with THIS converter\n * @param {string} extensionName Name of the previously registered extension\n */\n this.useExtension = function (extensionName) {\n _parseExtension(extensionName);\n };\n\n /**\n * Set the flavor THIS converter should use\n * @param {string} name\n */\n this.setFlavor = function (name) {\n if (!flavor.hasOwnProperty(name)) {\n throw Error(name + ' flavor was not found');\n }\n var preset = flavor[name];\n setConvFlavor = name;\n for (var option in preset) {\n if (preset.hasOwnProperty(option)) {\n options[option] = preset[option];\n }\n }\n };\n\n /**\n * Get the currently set flavor of this converter\n * @returns {string}\n */\n this.getFlavor = function () {\n return setConvFlavor;\n };\n\n /**\n * Remove an extension from THIS converter.\n * Note: This is a costly operation. It's better to initialize a new converter\n * and specify the extensions you wish to use\n * @param {Array} extension\n */\n this.removeExtension = function (extension) {\n if (!showdown.helper.isArray(extension)) {\n extension = [extension];\n }\n for (var a = 0; a < extension.length; ++a) {\n var ext = extension[a];\n for (var i = 0; i < langExtensions.length; ++i) {\n if (langExtensions[i] === ext) {\n langExtensions[i].splice(i, 1);\n }\n }\n for (var ii = 0; ii < outputModifiers.length; ++i) {\n if (outputModifiers[ii] === ext) {\n outputModifiers[ii].splice(i, 1);\n }\n }\n }\n };\n\n /**\n * Get all extension of THIS converter\n * @returns {{language: Array, output: Array}}\n */\n this.getAllExtensions = function () {\n return {\n language: langExtensions,\n output: outputModifiers\n };\n };\n\n /**\n * Get the metadata of the previously parsed document\n * @param raw\n * @returns {string|{}}\n */\n this.getMetadata = function (raw) {\n if (raw) {\n return metadata.raw;\n } else {\n return metadata.parsed;\n }\n };\n\n /**\n * Get the metadata format of the previously parsed document\n * @returns {string}\n */\n this.getMetadataFormat = function () {\n return metadata.format;\n };\n\n /**\n * Private: set a single key, value metadata pair\n * @param {string} key\n * @param {string} value\n */\n this._setMetadataPair = function (key, value) {\n metadata.parsed[key] = value;\n };\n\n /**\n * Private: set metadata format\n * @param {string} format\n */\n this._setMetadataFormat = function (format) {\n metadata.format = format;\n };\n\n /**\n * Private: set metadata raw text\n * @param {string} raw\n */\n this._setMetadataRaw = function (raw) {\n metadata.raw = raw;\n };\n};\n","/**\n * Turn Markdown link shortcuts into XHTML
      tags.\n */\nshowdown.subParser('anchors', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('anchors.before', text, options, globals);\n\n var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) {\n if (showdown.helper.isUndefined(title)) {\n title = '';\n }\n linkId = linkId.toLowerCase();\n\n // Special case for explicit empty url\n if (wholeMatch.search(/\\(? ?(['\"].*['\"])?\\)$/m) > -1) {\n url = '';\n } else if (!url) {\n if (!linkId) {\n // lower-case and turn embedded newlines into spaces\n linkId = linkText.toLowerCase().replace(/ ?\\n/g, ' ');\n }\n url = '#' + linkId;\n\n if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {\n url = globals.gUrls[linkId];\n if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {\n title = globals.gTitles[linkId];\n }\n } else {\n return wholeMatch;\n }\n }\n\n //url = showdown.helper.escapeCharacters(url, '*_', false); // replaced line to improve performance\n url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);\n\n var result = '';\n\n return result;\n };\n\n // First, handle reference-style links: [link text] [id]\n text = text.replace(/\\[((?:\\[[^\\]]*]|[^\\[\\]])*)] ?(?:\\n *)?\\[(.*?)]()()()()/g, writeAnchorTag);\n\n // Next, inline-style links: [link text](url \"optional title\")\n // cases with crazy urls like ./image/cat1).png\n text = text.replace(/\\[((?:\\[[^\\]]*]|[^\\[\\]])*)]()[ \\t]*\\([ \\t]?<([^>]*)>(?:[ \\t]*(([\"'])([^\"]*?)\\5))?[ \\t]?\\)/g,\n writeAnchorTag);\n\n // normal cases\n text = text.replace(/\\[((?:\\[[^\\]]*]|[^\\[\\]])*)]()[ \\t]*\\([ \\t]??(?:[ \\t]*(([\"'])([^\"]*?)\\5))?[ \\t]?\\)/g,\n writeAnchorTag);\n\n // handle reference-style shortcuts: [link text]\n // These must come last in case you've also got [link test][1]\n // or [link test](/foo)\n text = text.replace(/\\[([^\\[\\]]+)]()()()()()/g, writeAnchorTag);\n\n // Lastly handle GithubMentions if option is enabled\n if (options.ghMentions) {\n text = text.replace(/(^|\\s)(\\\\)?(@([a-z\\d\\-]+))(?=[.!?;,[\\]()]|\\s|$)/gmi, function (wm, st, escape, mentions, username) {\n if (escape === '\\\\') {\n return st + mentions;\n }\n\n //check if options.ghMentionsLink is a string\n if (!showdown.helper.isString(options.ghMentionsLink)) {\n throw new Error('ghMentionsLink option must be a string');\n }\n var lnk = options.ghMentionsLink.replace(/\\{u}/g, username),\n target = '';\n if (options.openLinksInNewWindow) {\n target = ' target=\"¨E95Eblank\"';\n }\n return st + '' + mentions + '';\n });\n }\n\n text = globals.converter._dispatch('anchors.after', text, options, globals);\n return text;\n});\n","// url allowed chars [a-z\\d_.~:/?#[]@!$&'()*+,;=-]\n\nvar simpleURLRegex = /([*~_]+|\\b)(((https?|ftp|dict):\\/\\/|www\\.)[^'\">\\s]+?\\.[^'\">\\s]+?)()(\\1)?(?=\\s|$)(?![\"<>])/gi,\n simpleURLRegex2 = /([*~_]+|\\b)(((https?|ftp|dict):\\/\\/|www\\.)[^'\">\\s]+\\.[^'\">\\s]+?)([.!?,()\\[\\]])?(\\1)?(?=\\s|$)(?![\"<>])/gi,\n delimUrlRegex = /()<(((https?|ftp|dict):\\/\\/|www\\.)[^'\">\\s]+)()>()/gi,\n simpleMailRegex = /(^|\\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+)(?=$|\\s)/gmi,\n delimMailRegex = /<()(?:mailto:)?([-.\\w]+@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+)>/gi,\n\n replaceLink = function (options) {\n 'use strict';\n return function (wm, leadingMagicChars, link, m2, m3, trailingPunctuation, trailingMagicChars) {\n link = link.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);\n var lnkTxt = link,\n append = '',\n target = '',\n lmc = leadingMagicChars || '',\n tmc = trailingMagicChars || '';\n if (/^www\\./i.test(link)) {\n link = link.replace(/^www\\./i, 'http://www.');\n }\n if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) {\n append = trailingPunctuation;\n }\n if (options.openLinksInNewWindow) {\n target = ' target=\"¨E95Eblank\"';\n }\n return lmc + '' + lnkTxt + '' + append + tmc;\n };\n },\n\n replaceMail = function (options, globals) {\n 'use strict';\n return function (wholeMatch, b, mail) {\n var href = 'mailto:';\n b = b || '';\n mail = showdown.subParser('unescapeSpecialChars')(mail, options, globals);\n if (options.encodeEmails) {\n href = showdown.helper.encodeEmailAddress(href + mail);\n mail = showdown.helper.encodeEmailAddress(mail);\n } else {\n href = href + mail;\n }\n return b + '' + mail + '';\n };\n };\n\nshowdown.subParser('autoLinks', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('autoLinks.before', text, options, globals);\n\n text = text.replace(delimUrlRegex, replaceLink(options));\n text = text.replace(delimMailRegex, replaceMail(options, globals));\n\n text = globals.converter._dispatch('autoLinks.after', text, options, globals);\n\n return text;\n});\n\nshowdown.subParser('simplifiedAutoLinks', function (text, options, globals) {\n 'use strict';\n\n if (!options.simplifiedAutoLink) {\n return text;\n }\n\n text = globals.converter._dispatch('simplifiedAutoLinks.before', text, options, globals);\n\n if (options.excludeTrailingPunctuationFromURLs) {\n text = text.replace(simpleURLRegex2, replaceLink(options));\n } else {\n text = text.replace(simpleURLRegex, replaceLink(options));\n }\n text = text.replace(simpleMailRegex, replaceMail(options, globals));\n\n text = globals.converter._dispatch('simplifiedAutoLinks.after', text, options, globals);\n\n return text;\n});\n","/**\n * These are all the transformations that form block-level\n * tags like paragraphs, headers, and list items.\n */\nshowdown.subParser('blockGamut', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('blockGamut.before', text, options, globals);\n\n // we parse blockquotes first so that we can have headings and hrs\n // inside blockquotes\n text = showdown.subParser('blockQuotes')(text, options, globals);\n text = showdown.subParser('headers')(text, options, globals);\n\n // Do Horizontal Rules:\n text = showdown.subParser('horizontalRule')(text, options, globals);\n\n text = showdown.subParser('lists')(text, options, globals);\n text = showdown.subParser('codeBlocks')(text, options, globals);\n text = showdown.subParser('tables')(text, options, globals);\n\n // We already ran _HashHTMLBlocks() before, in Markdown(), but that\n // was to escape raw HTML in the original Markdown source. This time,\n // we're escaping the markup we've just created, so that we don't wrap\n //

      tags around block-level tags.\n text = showdown.subParser('hashHTMLBlocks')(text, options, globals);\n text = showdown.subParser('paragraphs')(text, options, globals);\n\n text = globals.converter._dispatch('blockGamut.after', text, options, globals);\n\n return text;\n});\n","showdown.subParser('blockQuotes', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('blockQuotes.before', text, options, globals);\n\n // add a couple extra lines after the text and endtext mark\n text = text + '\\n\\n';\n\n var rgx = /(^ {0,3}>[ \\t]?.+\\n(.+\\n)*\\n*)+/gm;\n\n if (options.splitAdjacentBlockquotes) {\n rgx = /^ {0,3}>[\\s\\S]*?(?:\\n\\n)/gm;\n }\n\n text = text.replace(rgx, function (bq) {\n // attacklab: hack around Konqueror 3.5.4 bug:\n // \"----------bug\".replace(/^-/g,\"\") == \"bug\"\n bq = bq.replace(/^[ \\t]*>[ \\t]?/gm, ''); // trim one level of quoting\n\n // attacklab: clean up hack\n bq = bq.replace(/¨0/g, '');\n\n bq = bq.replace(/^[ \\t]+$/gm, ''); // trim whitespace-only lines\n bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);\n bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse\n\n bq = bq.replace(/(^|\\n)/g, '$1 ');\n // These leading spaces screw with

       content, so we need to fix that:\n    bq = bq.replace(/(\\s*
      [^\\r]+?<\\/pre>)/gm, function (wholeMatch, m1) {\n      var pre = m1;\n      // attacklab: hack around Konqueror 3.5.4 bug:\n      pre = pre.replace(/^  /mg, '¨0');\n      pre = pre.replace(/¨0/g, '');\n      return pre;\n    });\n\n    return showdown.subParser('hashBlock')('
      \\n' + bq + '\\n
      ', options, globals);\n });\n\n text = globals.converter._dispatch('blockQuotes.after', text, options, globals);\n return text;\n});\n","/**\n * Process Markdown `
      ` blocks.\n */\nshowdown.subParser('codeBlocks', function (text, options, globals) {\n  'use strict';\n\n  text = globals.converter._dispatch('codeBlocks.before', text, options, globals);\n\n  // sentinel workarounds for lack of \\A and \\Z, safari\\khtml bug\n  text += '¨0';\n\n  var pattern = /(?:\\n\\n|^)((?:(?:[ ]{4}|\\t).*\\n+)+)(\\n*[ ]{0,3}[^ \\t\\n]|(?=¨0))/g;\n  text = text.replace(pattern, function (wholeMatch, m1, m2) {\n    var codeblock = m1,\n        nextChar = m2,\n        end = '\\n';\n\n    codeblock = showdown.subParser('outdent')(codeblock, options, globals);\n    codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);\n    codeblock = showdown.subParser('detab')(codeblock, options, globals);\n    codeblock = codeblock.replace(/^\\n+/g, ''); // trim leading newlines\n    codeblock = codeblock.replace(/\\n+$/g, ''); // trim trailing newlines\n\n    if (options.omitExtraWLInCodeBlocks) {\n      end = '';\n    }\n\n    codeblock = '
      ' + codeblock + end + '
      ';\n\n return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;\n });\n\n // strip sentinel\n text = text.replace(/¨0/, '');\n\n text = globals.converter._dispatch('codeBlocks.after', text, options, globals);\n return text;\n});\n","/**\n *\n * * Backtick quotes are used for spans.\n *\n * * You can use multiple backticks as the delimiters if you want to\n * include literal backticks in the code span. So, this input:\n *\n * Just type ``foo `bar` baz`` at the prompt.\n *\n * Will translate to:\n *\n *

      Just type foo `bar` baz at the prompt.

      \n *\n * There's no arbitrary limit to the number of backticks you\n * can use as delimters. If you need three consecutive backticks\n * in your code, use four for delimiters, etc.\n *\n * * You can use spaces to get literal backticks at the edges:\n *\n * ... type `` `bar` `` ...\n *\n * Turns to:\n *\n * ... type `bar` ...\n */\nshowdown.subParser('codeSpans', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('codeSpans.before', text, options, globals);\n\n if (typeof(text) === 'undefined') {\n text = '';\n }\n text = text.replace(/(^|[^\\\\])(`+)([^\\r]*?[^`])\\2(?!`)/gm,\n function (wholeMatch, m1, m2, m3) {\n var c = m3;\n c = c.replace(/^([ \\t]*)/g, '');\t// leading whitespace\n c = c.replace(/[ \\t]*$/g, '');\t// trailing whitespace\n c = showdown.subParser('encodeCode')(c, options, globals);\n c = m1 + '' + c + '';\n c = showdown.subParser('hashHTMLSpans')(c, options, globals);\n return c;\n }\n );\n\n text = globals.converter._dispatch('codeSpans.after', text, options, globals);\n return text;\n});\n","/**\n * Turn Markdown link shortcuts into XHTML tags.\n */\nshowdown.subParser('completeHTMLDocument', function (text, options, globals) {\n 'use strict';\n\n if (!options.completeHTMLDocument) {\n return text;\n }\n\n text = globals.converter._dispatch('completeHTMLDocument.before', text, options, globals);\n\n var doctype = 'html',\n doctypeParsed = '\\n',\n title = '',\n charset = '\\n',\n lang = '',\n metadata = '';\n\n if (typeof globals.metadata.parsed.doctype !== 'undefined') {\n doctypeParsed = '\\n';\n doctype = globals.metadata.parsed.doctype.toString().toLowerCase();\n if (doctype === 'html' || doctype === 'html5') {\n charset = '';\n }\n }\n\n for (var meta in globals.metadata.parsed) {\n if (globals.metadata.parsed.hasOwnProperty(meta)) {\n switch (meta.toLowerCase()) {\n case 'doctype':\n break;\n\n case 'title':\n title = '' + globals.metadata.parsed.title + '\\n';\n break;\n\n case 'charset':\n if (doctype === 'html' || doctype === 'html5') {\n charset = '\\n';\n } else {\n charset = '\\n';\n }\n break;\n\n case 'language':\n case 'lang':\n lang = ' lang=\"' + globals.metadata.parsed[meta] + '\"';\n metadata += '\\n';\n break;\n\n default:\n metadata += '\\n';\n }\n }\n }\n\n text = doctypeParsed + '\\n\\n' + title + charset + metadata + '\\n\\n' + text.trim() + '\\n\\n';\n\n text = globals.converter._dispatch('completeHTMLDocument.after', text, options, globals);\n return text;\n});\n","/**\n * Convert all tabs to spaces\n */\nshowdown.subParser('detab', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('detab.before', text, options, globals);\n\n // expand first n-1 tabs\n text = text.replace(/\\t(?=\\t)/g, ' '); // g_tab_width\n\n // replace the nth with two sentinels\n text = text.replace(/\\t/g, '¨A¨B');\n\n // use the sentinel to anchor our regex so it doesn't explode\n text = text.replace(/¨B(.+?)¨A/g, function (wholeMatch, m1) {\n var leadingText = m1,\n numSpaces = 4 - leadingText.length % 4; // g_tab_width\n\n // there *must* be a better way to do this:\n for (var i = 0; i < numSpaces; i++) {\n leadingText += ' ';\n }\n\n return leadingText;\n });\n\n // clean up sentinels\n text = text.replace(/¨A/g, ' '); // g_tab_width\n text = text.replace(/¨B/g, '');\n\n text = globals.converter._dispatch('detab.after', text, options, globals);\n return text;\n});\n","showdown.subParser('ellipsis', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('ellipsis.before', text, options, globals);\n\n text = text.replace(/\\.\\.\\./g, '…');\n\n text = globals.converter._dispatch('ellipsis.after', text, options, globals);\n\n return text;\n});\n","/**\n * These are all the transformations that occur *within* block-level\n * tags like paragraphs, headers, and list items.\n */\nshowdown.subParser('emoji', function (text, options, globals) {\n 'use strict';\n\n if (!options.emoji) {\n return text;\n }\n\n text = globals.converter._dispatch('emoji.before', text, options, globals);\n\n var emojiRgx = /:([\\S]+?):/g;\n\n text = text.replace(emojiRgx, function (wm, emojiCode) {\n if (showdown.helper.emojis.hasOwnProperty(emojiCode)) {\n return showdown.helper.emojis[emojiCode];\n }\n return wm;\n });\n\n text = globals.converter._dispatch('emoji.after', text, options, globals);\n\n return text;\n});\n","/**\n * Smart processing for ampersands and angle brackets that need to be encoded.\n */\nshowdown.subParser('encodeAmpsAndAngles', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('encodeAmpsAndAngles.before', text, options, globals);\n\n // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:\n // http://bumppo.net/projects/amputator/\n text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\\w+);)/g, '&');\n\n // Encode naked <'s\n text = text.replace(/<(?![a-z\\/?$!])/gi, '<');\n\n // Encode <\n text = text.replace(/\n text = text.replace(/>/g, '>');\n\n text = globals.converter._dispatch('encodeAmpsAndAngles.after', text, options, globals);\n return text;\n});\n","/**\n * Returns the string, with after processing the following backslash escape sequences.\n *\n * attacklab: The polite way to do this is with the new escapeCharacters() function:\n *\n * text = escapeCharacters(text,\"\\\\\",true);\n * text = escapeCharacters(text,\"`*_{}[]()>#+-.!\",true);\n *\n * ...but we're sidestepping its use of the (slow) RegExp constructor\n * as an optimization for Firefox. This function gets called a LOT.\n */\nshowdown.subParser('encodeBackslashEscapes', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('encodeBackslashEscapes.before', text, options, globals);\n\n text = text.replace(/\\\\(\\\\)/g, showdown.helper.escapeCharactersCallback);\n text = text.replace(/\\\\([`*_{}\\[\\]()>#+.!~=|-])/g, showdown.helper.escapeCharactersCallback);\n\n text = globals.converter._dispatch('encodeBackslashEscapes.after', text, options, globals);\n return text;\n});\n","/**\n * Encode/escape certain characters inside Markdown code runs.\n * The point is that in code, these characters are literals,\n * and lose their special Markdown meanings.\n */\nshowdown.subParser('encodeCode', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('encodeCode.before', text, options, globals);\n\n // Encode all ampersands; HTML entities are not\n // entities within a Markdown code span.\n text = text\n .replace(/&/g, '&')\n // Do the angle bracket song and dance:\n .replace(//g, '>')\n // Now, escape characters that are magic in Markdown:\n .replace(/([*_{}\\[\\]\\\\=~-])/g, showdown.helper.escapeCharactersCallback);\n\n text = globals.converter._dispatch('encodeCode.after', text, options, globals);\n return text;\n});\n","/**\n * Within tags -- meaning between < and > -- encode [\\ ` * _ ~ =] so they\n * don't conflict with their use in Markdown for code, italics and strong.\n */\nshowdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.before', text, options, globals);\n\n // Build a regex to find HTML tags.\n var tags = /<\\/?[a-z\\d_:-]+(?:[\\s]+[\\s\\S]+?)?>/gi,\n comments = /-]|-[^>])(?:[^-]|-[^-])*)--)>/gi;\n\n text = text.replace(tags, function (wholeMatch) {\n return wholeMatch\n .replace(/(.)<\\/?code>(?=.)/g, '$1`')\n .replace(/([\\\\`*_~=|])/g, showdown.helper.escapeCharactersCallback);\n });\n\n text = text.replace(comments, function (wholeMatch) {\n return wholeMatch\n .replace(/([\\\\`*_~=|])/g, showdown.helper.escapeCharactersCallback);\n });\n\n text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.after', text, options, globals);\n return text;\n});\n","/**\n * Handle github codeblocks prior to running HashHTML so that\n * HTML contained within the codeblock gets escaped properly\n * Example:\n * ```ruby\n * def hello_world(x)\n * puts \"Hello, #{x}\"\n * end\n * ```\n */\nshowdown.subParser('githubCodeBlocks', function (text, options, globals) {\n 'use strict';\n\n // early exit if option is not enabled\n if (!options.ghCodeBlocks) {\n return text;\n }\n\n text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);\n\n text += '¨0';\n\n text = text.replace(/(?:^|\\n)(```+|~~~+)([^\\s`~]*)\\n([\\s\\S]*?)\\n\\1/g, function (wholeMatch, delim, language, codeblock) {\n var end = (options.omitExtraWLInCodeBlocks) ? '' : '\\n';\n\n // First parse the github code block\n codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);\n codeblock = showdown.subParser('detab')(codeblock, options, globals);\n codeblock = codeblock.replace(/^\\n+/g, ''); // trim leading newlines\n codeblock = codeblock.replace(/\\n+$/g, ''); // trim trailing whitespace\n\n codeblock = '
      ' + codeblock + end + '
      ';\n\n codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);\n\n // Since GHCodeblocks can be false positives, we need to\n // store the primitive text and the parsed text in a global var,\n // and then return a token\n return '\\n\\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\\n\\n';\n });\n\n // attacklab: strip sentinel\n text = text.replace(/¨0/, '');\n\n return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);\n});\n","showdown.subParser('hashBlock', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('hashBlock.before', text, options, globals);\n text = text.replace(/(^\\n+|\\n+$)/g, '');\n text = '\\n\\n¨K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\\n\\n';\n text = globals.converter._dispatch('hashBlock.after', text, options, globals);\n return text;\n});\n","/**\n * Hash and escape elements that should not be parsed as markdown\n */\nshowdown.subParser('hashCodeTags', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('hashCodeTags.before', text, options, globals);\n\n var repFunc = function (wholeMatch, match, left, right) {\n var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;\n return '¨C' + (globals.gHtmlSpans.push(codeblock) - 1) + 'C';\n };\n\n // Hash naked \n text = showdown.helper.replaceRecursiveRegExp(text, repFunc, ']*>', '', 'gim');\n\n text = globals.converter._dispatch('hashCodeTags.after', text, options, globals);\n return text;\n});\n","showdown.subParser('hashElement', function (text, options, globals) {\n 'use strict';\n\n return function (wholeMatch, m1) {\n var blockText = m1;\n\n // Undo double lines\n blockText = blockText.replace(/\\n\\n/g, '\\n');\n blockText = blockText.replace(/^\\n/, '');\n\n // strip trailing blank lines\n blockText = blockText.replace(/\\n+$/g, '');\n\n // Replace the element text with a marker (\"¨KxK\" where x is its key)\n blockText = '\\n\\n¨K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\\n\\n';\n\n return blockText;\n };\n});\n","showdown.subParser('hashHTMLBlocks', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('hashHTMLBlocks.before', text, options, globals);\n\n var blockTags = [\n 'pre',\n 'div',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'blockquote',\n 'table',\n 'dl',\n 'ol',\n 'ul',\n 'script',\n 'noscript',\n 'form',\n 'fieldset',\n 'iframe',\n 'math',\n 'style',\n 'section',\n 'header',\n 'footer',\n 'nav',\n 'article',\n 'aside',\n 'address',\n 'audio',\n 'canvas',\n 'figure',\n 'hgroup',\n 'output',\n 'video',\n 'p'\n ],\n repFunc = function (wholeMatch, match, left, right) {\n var txt = wholeMatch;\n // check if this html element is marked as markdown\n // if so, it's contents should be parsed as markdown\n if (left.search(/\\bmarkdown\\b/) !== -1) {\n txt = left + globals.converter.makeHtml(match) + right;\n }\n return '\\n\\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\\n\\n';\n };\n\n if (options.backslashEscapesHTMLTags) {\n // encode backslash escaped HTML tags\n text = text.replace(/\\\\<(\\/?[^>]+?)>/g, function (wm, inside) {\n return '<' + inside + '>';\n });\n }\n\n // hash HTML Blocks\n for (var i = 0; i < blockTags.length; ++i) {\n\n var opTagPos,\n rgx1 = new RegExp('^ {0,3}(<' + blockTags[i] + '\\\\b[^>]*>)', 'im'),\n patLeft = '<' + blockTags[i] + '\\\\b[^>]*>',\n patRight = '';\n // 1. Look for the first position of the first opening HTML tag in the text\n while ((opTagPos = showdown.helper.regexIndexOf(text, rgx1)) !== -1) {\n\n // if the HTML tag is \\ escaped, we need to escape it and break\n\n\n //2. Split the text in that position\n var subTexts = showdown.helper.splitAtIndex(text, opTagPos),\n //3. Match recursively\n newSubText1 = showdown.helper.replaceRecursiveRegExp(subTexts[1], repFunc, patLeft, patRight, 'im');\n\n // prevent an infinite loop\n if (newSubText1 === subTexts[1]) {\n break;\n }\n text = subTexts[0].concat(newSubText1);\n }\n }\n // HR SPECIAL CASE\n text = text.replace(/(\\n {0,3}(<(hr)\\b([^<>])*?\\/?>)[ \\t]*(?=\\n{2,}))/g,\n showdown.subParser('hashElement')(text, options, globals));\n\n // Special case for standalone HTML comments\n text = showdown.helper.replaceRecursiveRegExp(text, function (txt) {\n return '\\n\\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\\n\\n';\n }, '^ {0,3}', 'gm');\n\n // PHP and ASP-style processor instructions ( and <%...%>)\n text = text.replace(/(?:\\n\\n)( {0,3}(?:<([?%])[^\\r]*?\\2>)[ \\t]*(?=\\n{2,}))/g,\n showdown.subParser('hashElement')(text, options, globals));\n\n text = globals.converter._dispatch('hashHTMLBlocks.after', text, options, globals);\n return text;\n});\n","/**\n * Hash span elements that should not be parsed as markdown\n */\nshowdown.subParser('hashHTMLSpans', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('hashHTMLSpans.before', text, options, globals);\n\n function hashHTMLSpan (html) {\n return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C';\n }\n\n // Hash Self Closing tags\n text = text.replace(/<[^>]+?\\/>/gi, function (wm) {\n return hashHTMLSpan(wm);\n });\n\n // Hash tags without properties\n text = text.replace(/<([^>]+?)>[\\s\\S]*?<\\/\\1>/g, function (wm) {\n return hashHTMLSpan(wm);\n });\n\n // Hash tags with properties\n text = text.replace(/<([^>]+?)\\s[^>]+?>[\\s\\S]*?<\\/\\1>/g, function (wm) {\n return hashHTMLSpan(wm);\n });\n\n // Hash self closing tags without />\n text = text.replace(/<[^>]+?>/gi, function (wm) {\n return hashHTMLSpan(wm);\n });\n\n /*showdown.helper.matchRecursiveRegExp(text, ']*>', '', 'gi');*/\n\n text = globals.converter._dispatch('hashHTMLSpans.after', text, options, globals);\n return text;\n});\n\n/**\n * Unhash HTML spans\n */\nshowdown.subParser('unhashHTMLSpans', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('unhashHTMLSpans.before', text, options, globals);\n\n for (var i = 0; i < globals.gHtmlSpans.length; ++i) {\n var repText = globals.gHtmlSpans[i],\n // limiter to prevent infinite loop (assume 10 as limit for recurse)\n limit = 0;\n\n while (/¨C(\\d+)C/.test(repText)) {\n var num = RegExp.$1;\n repText = repText.replace('¨C' + num + 'C', globals.gHtmlSpans[num]);\n if (limit === 10) {\n console.error('maximum nesting of 10 spans reached!!!');\n break;\n }\n ++limit;\n }\n text = text.replace('¨C' + i + 'C', repText);\n }\n\n text = globals.converter._dispatch('unhashHTMLSpans.after', text, options, globals);\n return text;\n});\n","/**\n * Hash and escape
       elements that should not be parsed as markdown\n */\nshowdown.subParser('hashPreCodeTags', function (text, options, globals) {\n  'use strict';\n  text = globals.converter._dispatch('hashPreCodeTags.before', text, options, globals);\n\n  var repFunc = function (wholeMatch, match, left, right) {\n    // encode html entities\n    var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;\n    return '\\n\\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\\n\\n';\n  };\n\n  // Hash 
      \n  text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^ {0,3}]*>\\\\s*]*>', '^ {0,3}\\\\s*
      ', 'gim');\n\n text = globals.converter._dispatch('hashPreCodeTags.after', text, options, globals);\n return text;\n});\n","showdown.subParser('headers', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('headers.before', text, options, globals);\n\n var headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),\n\n // Set text-style headers:\n //\tHeader 1\n //\t========\n //\n //\tHeader 2\n //\t--------\n //\n setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \\t]*\\n={2,}[ \\t]*\\n+/gm : /^(.+)[ \\t]*\\n=+[ \\t]*\\n+/gm,\n setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \\t]*\\n-{2,}[ \\t]*\\n+/gm : /^(.+)[ \\t]*\\n-+[ \\t]*\\n+/gm;\n\n text = text.replace(setextRegexH1, function (wholeMatch, m1) {\n\n var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),\n hID = (options.noHeaderId) ? '' : ' id=\"' + headerId(m1) + '\"',\n hLevel = headerLevelStart,\n hashBlock = '' + spanGamut + '';\n return showdown.subParser('hashBlock')(hashBlock, options, globals);\n });\n\n text = text.replace(setextRegexH2, function (matchFound, m1) {\n var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),\n hID = (options.noHeaderId) ? '' : ' id=\"' + headerId(m1) + '\"',\n hLevel = headerLevelStart + 1,\n hashBlock = '' + spanGamut + '';\n return showdown.subParser('hashBlock')(hashBlock, options, globals);\n });\n\n // atx-style headers:\n // # Header 1\n // ## Header 2\n // ## Header 2 with closing hashes ##\n // ...\n // ###### Header 6\n //\n var atxStyle = (options.requireSpaceBeforeHeadingText) ? /^(#{1,6})[ \\t]+(.+?)[ \\t]*#*\\n+/gm : /^(#{1,6})[ \\t]*(.+?)[ \\t]*#*\\n+/gm;\n\n text = text.replace(atxStyle, function (wholeMatch, m1, m2) {\n var hText = m2;\n if (options.customizedHeaderId) {\n hText = m2.replace(/\\s?\\{([^{]+?)}\\s*$/, '');\n }\n\n var span = showdown.subParser('spanGamut')(hText, options, globals),\n hID = (options.noHeaderId) ? '' : ' id=\"' + headerId(m2) + '\"',\n hLevel = headerLevelStart - 1 + m1.length,\n header = '' + span + '';\n\n return showdown.subParser('hashBlock')(header, options, globals);\n });\n\n function headerId (m) {\n var title,\n prefix;\n\n // It is separate from other options to allow combining prefix and customized\n if (options.customizedHeaderId) {\n var match = m.match(/\\{([^{]+?)}\\s*$/);\n if (match && match[1]) {\n m = match[1];\n }\n }\n\n title = m;\n\n // Prefix id to prevent causing inadvertent pre-existing style matches.\n if (showdown.helper.isString(options.prefixHeaderId)) {\n prefix = options.prefixHeaderId;\n } else if (options.prefixHeaderId === true) {\n prefix = 'section-';\n } else {\n prefix = '';\n }\n\n if (!options.rawPrefixHeaderId) {\n title = prefix + title;\n }\n\n if (options.ghCompatibleHeaderId) {\n title = title\n .replace(/ /g, '-')\n // replace previously escaped chars (&, ¨ and $)\n .replace(/&/g, '')\n .replace(/¨T/g, '')\n .replace(/¨D/g, '')\n // replace rest of the chars (&~$ are repeated as they might have been escaped)\n // borrowed from github's redcarpet (some they should produce similar results)\n .replace(/[&+$,\\/:;=?@\"#{}|^¨~\\[\\]`\\\\*)(%.!'<>]/g, '')\n .toLowerCase();\n } else if (options.rawHeaderId) {\n title = title\n .replace(/ /g, '-')\n // replace previously escaped chars (&, ¨ and $)\n .replace(/&/g, '&')\n .replace(/¨T/g, '¨')\n .replace(/¨D/g, '$')\n // replace \" and '\n .replace(/[\"']/g, '-')\n .toLowerCase();\n } else {\n title = title\n .replace(/[^\\w]/g, '')\n .toLowerCase();\n }\n\n if (options.rawPrefixHeaderId) {\n title = prefix + title;\n }\n\n if (globals.hashLinkCounts[title]) {\n title = title + '-' + (globals.hashLinkCounts[title]++);\n } else {\n globals.hashLinkCounts[title] = 1;\n }\n return title;\n }\n\n text = globals.converter._dispatch('headers.after', text, options, globals);\n return text;\n});\n","/**\n * Turn Markdown link shortcuts into XHTML
      tags.\n */\nshowdown.subParser('horizontalRule', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('horizontalRule.before', text, options, globals);\n\n var key = showdown.subParser('hashBlock')('
      ', options, globals);\n text = text.replace(/^ {0,2}( ?-){3,}[ \\t]*$/gm, key);\n text = text.replace(/^ {0,2}( ?\\*){3,}[ \\t]*$/gm, key);\n text = text.replace(/^ {0,2}( ?_){3,}[ \\t]*$/gm, key);\n\n text = globals.converter._dispatch('horizontalRule.after', text, options, globals);\n return text;\n});\n","/**\n * Turn Markdown image shortcuts into tags.\n */\nshowdown.subParser('images', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('images.before', text, options, globals);\n\n var inlineRegExp = /!\\[([^\\]]*?)][ \\t]*()\\([ \\t]??(?: =([*\\d]+[A-Za-z%]{0,4})x([*\\d]+[A-Za-z%]{0,4}))?[ \\t]*(?:([\"'])([^\"]*?)\\6)?[ \\t]?\\)/g,\n crazyRegExp = /!\\[([^\\]]*?)][ \\t]*()\\([ \\t]?<([^>]*)>(?: =([*\\d]+[A-Za-z%]{0,4})x([*\\d]+[A-Za-z%]{0,4}))?[ \\t]*(?:(?:([\"'])([^\"]*?)\\6))?[ \\t]?\\)/g,\n base64RegExp = /!\\[([^\\]]*?)][ \\t]*()\\([ \\t]??(?: =([*\\d]+[A-Za-z%]{0,4})x([*\\d]+[A-Za-z%]{0,4}))?[ \\t]*(?:([\"'])([^\"]*?)\\6)?[ \\t]?\\)/g,\n referenceRegExp = /!\\[([^\\]]*?)] ?(?:\\n *)?\\[([\\s\\S]*?)]()()()()()/g,\n refShortcutRegExp = /!\\[([^\\[\\]]+)]()()()()()/g;\n\n function writeImageTagBase64 (wholeMatch, altText, linkId, url, width, height, m5, title) {\n url = url.replace(/\\s/g, '');\n return writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title);\n }\n\n function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {\n\n var gUrls = globals.gUrls,\n gTitles = globals.gTitles,\n gDims = globals.gDimensions;\n\n linkId = linkId.toLowerCase();\n\n if (!title) {\n title = '';\n }\n // Special case for explicit empty url\n if (wholeMatch.search(/\\(? ?(['\"].*['\"])?\\)$/m) > -1) {\n url = '';\n\n } else if (url === '' || url === null) {\n if (linkId === '' || linkId === null) {\n // lower-case and turn embedded newlines into spaces\n linkId = altText.toLowerCase().replace(/ ?\\n/g, ' ');\n }\n url = '#' + linkId;\n\n if (!showdown.helper.isUndefined(gUrls[linkId])) {\n url = gUrls[linkId];\n if (!showdown.helper.isUndefined(gTitles[linkId])) {\n title = gTitles[linkId];\n }\n if (!showdown.helper.isUndefined(gDims[linkId])) {\n width = gDims[linkId].width;\n height = gDims[linkId].height;\n }\n } else {\n return wholeMatch;\n }\n }\n\n altText = altText\n .replace(/\"/g, '"')\n //altText = showdown.helper.escapeCharacters(altText, '*_', false);\n .replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);\n //url = showdown.helper.escapeCharacters(url, '*_', false);\n url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);\n var result = '\"'x \"optional title\")\n\n // base64 encoded images\n text = text.replace(base64RegExp, writeImageTagBase64);\n\n // cases with crazy urls like ./image/cat1).png\n text = text.replace(crazyRegExp, writeImageTag);\n\n // normal cases\n text = text.replace(inlineRegExp, writeImageTag);\n\n // handle reference-style shortcuts: ![img text]\n text = text.replace(refShortcutRegExp, writeImageTag);\n\n text = globals.converter._dispatch('images.after', text, options, globals);\n return text;\n});\n","showdown.subParser('italicsAndBold', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);\n\n // it's faster to have 3 separate regexes for each case than have just one\n // because of backtracing, in some cases, it could lead to an exponential effect\n // called \"catastrophic backtrace\". Ominous!\n\n function parseInside (txt, left, right) {\n /*\n if (options.simplifiedAutoLink) {\n txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals);\n }\n */\n return left + txt + right;\n }\n\n // Parse underscores\n if (options.literalMidWordUnderscores) {\n text = text.replace(/\\b___(\\S[\\s\\S]*)___\\b/g, function (wm, txt) {\n return parseInside (txt, '', '');\n });\n text = text.replace(/\\b__(\\S[\\s\\S]*)__\\b/g, function (wm, txt) {\n return parseInside (txt, '', '');\n });\n text = text.replace(/\\b_(\\S[\\s\\S]*?)_\\b/g, function (wm, txt) {\n return parseInside (txt, '', '');\n });\n } else {\n text = text.replace(/___(\\S[\\s\\S]*?)___/g, function (wm, m) {\n return (/\\S$/.test(m)) ? parseInside (m, '', '') : wm;\n });\n text = text.replace(/__(\\S[\\s\\S]*?)__/g, function (wm, m) {\n return (/\\S$/.test(m)) ? parseInside (m, '', '') : wm;\n });\n text = text.replace(/_([^\\s_][\\s\\S]*?)_/g, function (wm, m) {\n // !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it)\n return (/\\S$/.test(m)) ? parseInside (m, '', '') : wm;\n });\n }\n\n // Now parse asterisks\n if (options.literalMidWordAsterisks) {\n text = text.replace(/([^*]|^)\\B\\*\\*\\*(\\S[\\s\\S]+?)\\*\\*\\*\\B(?!\\*)/g, function (wm, lead, txt) {\n return parseInside (txt, lead + '', '');\n });\n text = text.replace(/([^*]|^)\\B\\*\\*(\\S[\\s\\S]+?)\\*\\*\\B(?!\\*)/g, function (wm, lead, txt) {\n return parseInside (txt, lead + '', '');\n });\n text = text.replace(/([^*]|^)\\B\\*(\\S[\\s\\S]+?)\\*\\B(?!\\*)/g, function (wm, lead, txt) {\n return parseInside (txt, lead + '', '');\n });\n } else {\n text = text.replace(/\\*\\*\\*(\\S[\\s\\S]*?)\\*\\*\\*/g, function (wm, m) {\n return (/\\S$/.test(m)) ? parseInside (m, '', '') : wm;\n });\n text = text.replace(/\\*\\*(\\S[\\s\\S]*?)\\*\\*/g, function (wm, m) {\n return (/\\S$/.test(m)) ? parseInside (m, '', '') : wm;\n });\n text = text.replace(/\\*([^\\s*][\\s\\S]*?)\\*/g, function (wm, m) {\n // !/^\\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it)\n return (/\\S$/.test(m)) ? parseInside (m, '', '') : wm;\n });\n }\n\n\n text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);\n return text;\n});\n","/**\n * Form HTML ordered (numbered) and unordered (bulleted) lists.\n */\nshowdown.subParser('lists', function (text, options, globals) {\n 'use strict';\n\n /**\n * Process the contents of a single ordered or unordered list, splitting it\n * into individual list items.\n * @param {string} listStr\n * @param {boolean} trimTrailing\n * @returns {string}\n */\n function processListItems (listStr, trimTrailing) {\n // The $g_list_level global keeps track of when we're inside a list.\n // Each time we enter a list, we increment it; when we leave a list,\n // we decrement. If it's zero, we're not in a list anymore.\n //\n // We do this because when we're not inside a list, we want to treat\n // something like this:\n //\n // I recommend upgrading to version\n // 8. Oops, now this line is treated\n // as a sub-list.\n //\n // As a single paragraph, despite the fact that the second line starts\n // with a digit-period-space sequence.\n //\n // Whereas when we're inside a list (or sub-list), that line will be\n // treated as the start of a sub-list. What a kludge, huh? This is\n // an aspect of Markdown's syntax that's hard to parse perfectly\n // without resorting to mind-reading. Perhaps the solution is to\n // change the syntax rules such that sub-lists must start with a\n // starting cardinal number; e.g. \"1.\" or \"a.\".\n globals.gListLevel++;\n\n // trim trailing blank lines:\n listStr = listStr.replace(/\\n{2,}$/, '\\n');\n\n // attacklab: add sentinel to emulate \\z\n listStr += '¨0';\n\n var rgx = /(\\n)?(^ {0,3})([*+-]|\\d+[.])[ \\t]+((\\[(x|X| )?])?[ \\t]*[^\\r]+?(\\n{1,2}))(?=\\n*(¨0| {0,3}([*+-]|\\d+[.])[ \\t]+))/gm,\n isParagraphed = (/\\n[ \\t]*\\n(?!¨0)/.test(listStr));\n\n // Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation,\n // which is a syntax breaking change\n // activating this option reverts to old behavior\n if (options.disableForced4SpacesIndentedSublists) {\n rgx = /(\\n)?(^ {0,3})([*+-]|\\d+[.])[ \\t]+((\\[(x|X| )?])?[ \\t]*[^\\r]+?(\\n{1,2}))(?=\\n*(¨0|\\2([*+-]|\\d+[.])[ \\t]+))/gm;\n }\n\n listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {\n checked = (checked && checked.trim() !== '');\n\n var item = showdown.subParser('outdent')(m4, options, globals),\n bulletStyle = '';\n\n // Support for github tasklists\n if (taskbtn && options.tasklists) {\n bulletStyle = ' class=\"task-list-item\" style=\"list-style-type: none;\"';\n item = item.replace(/^[ \\t]*\\[(x|X| )?]/m, function () {\n var otp = '
    • a
    • \n // instead of:\n //
      • - - a
      \n // So, to prevent it, we will put a marker (¨A)in the beginning of the line\n // Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser\n item = item.replace(/^([-*+]|\\d\\.)[ \\t]+[\\S\\n ]*/g, function (wm2) {\n return '¨A' + wm2;\n });\n\n // m1 - Leading line or\n // Has a double return (multi paragraph) or\n // Has sublist\n if (m1 || (item.search(/\\n{2,}/) > -1)) {\n item = showdown.subParser('githubCodeBlocks')(item, options, globals);\n item = showdown.subParser('blockGamut')(item, options, globals);\n } else {\n // Recursion for sub-lists:\n item = showdown.subParser('lists')(item, options, globals);\n item = item.replace(/\\n$/, ''); // chomp(item)\n item = showdown.subParser('hashHTMLBlocks')(item, options, globals);\n\n // Colapse double linebreaks\n item = item.replace(/\\n\\n+/g, '\\n\\n');\n if (isParagraphed) {\n item = showdown.subParser('paragraphs')(item, options, globals);\n } else {\n item = showdown.subParser('spanGamut')(item, options, globals);\n }\n }\n\n // now we need to remove the marker (¨A)\n item = item.replace('¨A', '');\n // we can finally wrap the line in list item tags\n item = '' + item + '\\n';\n\n return item;\n });\n\n // attacklab: strip sentinel\n listStr = listStr.replace(/¨0/g, '');\n\n globals.gListLevel--;\n\n if (trimTrailing) {\n listStr = listStr.replace(/\\s+$/, '');\n }\n\n return listStr;\n }\n\n function styleStartNumber (list, listType) {\n // check if ol and starts by a number different than 1\n if (listType === 'ol') {\n var res = list.match(/^ *(\\d+)\\./);\n if (res && res[1] !== '1') {\n return ' start=\"' + res[1] + '\"';\n }\n }\n return '';\n }\n\n /**\n * Check and parse consecutive lists (better fix for issue #142)\n * @param {string} list\n * @param {string} listType\n * @param {boolean} trimTrailing\n * @returns {string}\n */\n function parseConsecutiveLists (list, listType, trimTrailing) {\n // check if we caught 2 or more consecutive lists by mistake\n // we use the counterRgx, meaning if listType is UL we look for OL and vice versa\n var olRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?\\d+\\.[ \\t]/gm : /^ {0,3}\\d+\\.[ \\t]/gm,\n ulRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?[*+-][ \\t]/gm : /^ {0,3}[*+-][ \\t]/gm,\n counterRxg = (listType === 'ul') ? olRgx : ulRgx,\n result = '';\n\n if (list.search(counterRxg) !== -1) {\n (function parseCL (txt) {\n var pos = txt.search(counterRxg),\n style = styleStartNumber(list, listType);\n if (pos !== -1) {\n // slice\n result += '\\n\\n<' + listType + style + '>\\n' + processListItems(txt.slice(0, pos), !!trimTrailing) + '\\n';\n\n // invert counterType and listType\n listType = (listType === 'ul') ? 'ol' : 'ul';\n counterRxg = (listType === 'ul') ? olRgx : ulRgx;\n\n //recurse\n parseCL(txt.slice(pos));\n } else {\n result += '\\n\\n<' + listType + style + '>\\n' + processListItems(txt, !!trimTrailing) + '\\n';\n }\n })(list);\n } else {\n var style = styleStartNumber(list, listType);\n result = '\\n\\n<' + listType + style + '>\\n' + processListItems(list, !!trimTrailing) + '\\n';\n }\n\n return result;\n }\n\n /** Start of list parsing **/\n text = globals.converter._dispatch('lists.before', text, options, globals);\n // add sentinel to hack around khtml/safari bug:\n // http://bugs.webkit.org/show_bug.cgi?id=11231\n text += '¨0';\n\n if (globals.gListLevel) {\n text = text.replace(/^(( {0,3}([*+-]|\\d+[.])[ \\t]+)[^\\r]+?(¨0|\\n{2,}(?=\\S)(?![ \\t]*(?:[*+-]|\\d+[.])[ \\t]+)))/gm,\n function (wholeMatch, list, m2) {\n var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';\n return parseConsecutiveLists(list, listType, true);\n }\n );\n } else {\n text = text.replace(/(\\n\\n|^\\n?)(( {0,3}([*+-]|\\d+[.])[ \\t]+)[^\\r]+?(¨0|\\n{2,}(?=\\S)(?![ \\t]*(?:[*+-]|\\d+[.])[ \\t]+)))/gm,\n function (wholeMatch, m1, list, m3) {\n var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';\n return parseConsecutiveLists(list, listType, false);\n }\n );\n }\n\n // strip sentinel\n text = text.replace(/¨0/, '');\n text = globals.converter._dispatch('lists.after', text, options, globals);\n return text;\n});\n","/**\n * Parse metadata at the top of the document\n */\nshowdown.subParser('metadata', function (text, options, globals) {\n 'use strict';\n\n if (!options.metadata) {\n return text;\n }\n\n text = globals.converter._dispatch('metadata.before', text, options, globals);\n\n function parseMetadataContents (content) {\n // raw is raw so it's not changed in any way\n globals.metadata.raw = content;\n\n // escape chars forbidden in html attributes\n // double quotes\n content = content\n // ampersand first\n .replace(/&/g, '&')\n // double quotes\n .replace(/\"/g, '"');\n\n content = content.replace(/\\n {4}/g, ' ');\n content.replace(/^([\\S ]+): +([\\s\\S]+?)$/gm, function (wm, key, value) {\n globals.metadata.parsed[key] = value;\n return '';\n });\n }\n\n text = text.replace(/^\\s*«««+(\\S*?)\\n([\\s\\S]+?)\\n»»»+\\n/, function (wholematch, format, content) {\n parseMetadataContents(content);\n return '¨M';\n });\n\n text = text.replace(/^\\s*---+(\\S*?)\\n([\\s\\S]+?)\\n---+\\n/, function (wholematch, format, content) {\n if (format) {\n globals.metadata.format = format;\n }\n parseMetadataContents(content);\n return '¨M';\n });\n\n text = text.replace(/¨M/g, '');\n\n text = globals.converter._dispatch('metadata.after', text, options, globals);\n return text;\n});\n","/**\n * Remove one level of line-leading tabs or spaces\n */\nshowdown.subParser('outdent', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('outdent.before', text, options, globals);\n\n // attacklab: hack around Konqueror 3.5.4 bug:\n // \"----------bug\".replace(/^-/g,\"\") == \"bug\"\n text = text.replace(/^(\\t|[ ]{1,4})/gm, '¨0'); // attacklab: g_tab_width\n\n // attacklab: clean up hack\n text = text.replace(/¨0/g, '');\n\n text = globals.converter._dispatch('outdent.after', text, options, globals);\n return text;\n});\n","/**\n *\n */\nshowdown.subParser('paragraphs', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('paragraphs.before', text, options, globals);\n // Strip leading and trailing lines:\n text = text.replace(/^\\n+/g, '');\n text = text.replace(/\\n+$/g, '');\n\n var grafs = text.split(/\\n{2,}/g),\n grafsOut = [],\n end = grafs.length; // Wrap

      tags\n\n for (var i = 0; i < end; i++) {\n var str = grafs[i];\n // if this is an HTML marker, copy it\n if (str.search(/¨(K|G)(\\d+)\\1/g) >= 0) {\n grafsOut.push(str);\n\n // test for presence of characters to prevent empty lines being parsed\n // as paragraphs (resulting in undesired extra empty paragraphs)\n } else if (str.search(/\\S/) >= 0) {\n str = showdown.subParser('spanGamut')(str, options, globals);\n str = str.replace(/^([ \\t]*)/g, '

      ');\n str += '

      ';\n grafsOut.push(str);\n }\n }\n\n /** Unhashify HTML blocks */\n end = grafsOut.length;\n for (i = 0; i < end; i++) {\n var blockText = '',\n grafsOutIt = grafsOut[i],\n codeFlag = false;\n // if this is a marker for an html block...\n // use RegExp.test instead of string.search because of QML bug\n while (/¨(K|G)(\\d+)\\1/.test(grafsOutIt)) {\n var delim = RegExp.$1,\n num = RegExp.$2;\n\n if (delim === 'K') {\n blockText = globals.gHtmlBlocks[num];\n } else {\n // we need to check if ghBlock is a false positive\n if (codeFlag) {\n // use encoded version of all text\n blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text, options, globals);\n } else {\n blockText = globals.ghCodeBlocks[num].codeblock;\n }\n }\n blockText = blockText.replace(/\\$/g, '$$$$'); // Escape any dollar signs\n\n grafsOutIt = grafsOutIt.replace(/(\\n\\n)?¨(K|G)\\d+\\2(\\n\\n)?/, blockText);\n // Check if grafsOutIt is a pre->code\n if (/^]*>\\s*]*>/.test(grafsOutIt)) {\n codeFlag = true;\n }\n }\n grafsOut[i] = grafsOutIt;\n }\n text = grafsOut.join('\\n');\n // Strip leading and trailing lines:\n text = text.replace(/^\\n+/g, '');\n text = text.replace(/\\n+$/g, '');\n return globals.converter._dispatch('paragraphs.after', text, options, globals);\n});\n","/**\n * Run extension\n */\nshowdown.subParser('runExtension', function (ext, text, options, globals) {\n 'use strict';\n\n if (ext.filter) {\n text = ext.filter(text, globals.converter, options);\n\n } else if (ext.regex) {\n // TODO remove this when old extension loading mechanism is deprecated\n var re = ext.regex;\n if (!(re instanceof RegExp)) {\n re = new RegExp(re, 'g');\n }\n text = text.replace(re, ext.replace);\n }\n\n return text;\n});\n","/**\n * These are all the transformations that occur *within* block-level\n * tags like paragraphs, headers, and list items.\n */\nshowdown.subParser('spanGamut', function (text, options, globals) {\n 'use strict';\n\n text = globals.converter._dispatch('spanGamut.before', text, options, globals);\n text = showdown.subParser('codeSpans')(text, options, globals);\n text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);\n text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);\n\n // Process anchor and image tags. Images must come first,\n // because ![foo][f] looks like an anchor.\n text = showdown.subParser('images')(text, options, globals);\n text = showdown.subParser('anchors')(text, options, globals);\n\n // Make links out of things like ``\n // Must come after anchors, because you can use < and >\n // delimiters in inline links like [this]().\n text = showdown.subParser('autoLinks')(text, options, globals);\n text = showdown.subParser('simplifiedAutoLinks')(text, options, globals);\n text = showdown.subParser('emoji')(text, options, globals);\n text = showdown.subParser('underline')(text, options, globals);\n text = showdown.subParser('italicsAndBold')(text, options, globals);\n text = showdown.subParser('strikethrough')(text, options, globals);\n text = showdown.subParser('ellipsis')(text, options, globals);\n\n // we need to hash HTML tags inside spans\n text = showdown.subParser('hashHTMLSpans')(text, options, globals);\n\n // now we encode amps and angles\n text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);\n\n // Do hard breaks\n if (options.simpleLineBreaks) {\n // GFM style hard breaks\n // only add line breaks if the text does not contain a block (special case for lists)\n if (!/\\n\\n¨K/.test(text)) {\n text = text.replace(/\\n+/g, '
      \\n');\n }\n } else {\n // Vanilla hard breaks\n text = text.replace(/ +\\n/g, '
      \\n');\n }\n\n text = globals.converter._dispatch('spanGamut.after', text, options, globals);\n return text;\n});\n","showdown.subParser('strikethrough', function (text, options, globals) {\n 'use strict';\n\n function parseInside (txt) {\n if (options.simplifiedAutoLink) {\n txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals);\n }\n return '' + txt + '';\n }\n\n if (options.strikethrough) {\n text = globals.converter._dispatch('strikethrough.before', text, options, globals);\n text = text.replace(/(?:~){2}([\\s\\S]+?)(?:~){2}/g, function (wm, txt) { return parseInside(txt); });\n text = globals.converter._dispatch('strikethrough.after', text, options, globals);\n }\n\n return text;\n});\n","/**\n * Strips link definitions from text, stores the URLs and titles in\n * hash references.\n * Link defs are in the form: ^[id]: url \"optional title\"\n */\nshowdown.subParser('stripLinkDefinitions', function (text, options, globals) {\n 'use strict';\n\n var regex = /^ {0,3}\\[(.+)]:[ \\t]*\\n?[ \\t]*\\s]+)>?(?: =([*\\d]+[A-Za-z%]{0,4})x([*\\d]+[A-Za-z%]{0,4}))?[ \\t]*\\n?[ \\t]*(?:(\\n*)[\"|'(](.+?)[\"|')][ \\t]*)?(?:\\n+|(?=¨0))/gm,\n base64Regex = /^ {0,3}\\[(.+)]:[ \\t]*\\n?[ \\t]*?(?: =([*\\d]+[A-Za-z%]{0,4})x([*\\d]+[A-Za-z%]{0,4}))?[ \\t]*\\n?[ \\t]*(?:(\\n*)[\"|'(](.+?)[\"|')][ \\t]*)?(?:\\n\\n|(?=¨0)|(?=\\n\\[))/gm;\n\n // attacklab: sentinel workarounds for lack of \\A and \\Z, safari\\khtml bug\n text += '¨0';\n\n var replaceFunc = function (wholeMatch, linkId, url, width, height, blankLines, title) {\n linkId = linkId.toLowerCase();\n if (url.match(/^data:.+?\\/.+?;base64,/)) {\n // remove newlines\n globals.gUrls[linkId] = url.replace(/\\s/g, '');\n } else {\n globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url, options, globals); // Link IDs are case-insensitive\n }\n\n if (blankLines) {\n // Oops, found blank lines, so it's not a title.\n // Put back the parenthetical statement we stole.\n return blankLines + title;\n\n } else {\n if (title) {\n globals.gTitles[linkId] = title.replace(/\"|'/g, '"');\n }\n if (options.parseImgDimensions && width && height) {\n globals.gDimensions[linkId] = {\n width: width,\n height: height\n };\n }\n }\n // Completely remove the definition from the text\n return '';\n };\n\n // first we try to find base64 link references\n text = text.replace(base64Regex, replaceFunc);\n\n text = text.replace(regex, replaceFunc);\n\n // attacklab: strip sentinel\n text = text.replace(/¨0/, '');\n\n return text;\n});\n","showdown.subParser('tables', function (text, options, globals) {\n 'use strict';\n\n if (!options.tables) {\n return text;\n }\n\n var tableRgx = /^ {0,3}\\|?.+\\|.+\\n {0,3}\\|?[ \\t]*:?[ \\t]*(?:[-=]){2,}[ \\t]*:?[ \\t]*\\|[ \\t]*:?[ \\t]*(?:[-=]){2,}[\\s\\S]+?(?:\\n\\n|¨0)/gm,\n //singeColTblRgx = /^ {0,3}\\|.+\\|\\n {0,3}\\|[ \\t]*:?[ \\t]*(?:[-=]){2,}[ \\t]*:?[ \\t]*\\|[ \\t]*\\n(?: {0,3}\\|.+\\|\\n)+(?:\\n\\n|¨0)/gm;\n singeColTblRgx = /^ {0,3}\\|.+\\|[ \\t]*\\n {0,3}\\|[ \\t]*:?[ \\t]*(?:[-=]){2,}[ \\t]*:?[ \\t]*\\|[ \\t]*\\n( {0,3}\\|.+\\|[ \\t]*\\n)*(?:\\n|¨0)/gm;\n\n function parseStyles (sLine) {\n if (/^:[ \\t]*--*$/.test(sLine)) {\n return ' style=\"text-align:left;\"';\n } else if (/^--*[ \\t]*:[ \\t]*$/.test(sLine)) {\n return ' style=\"text-align:right;\"';\n } else if (/^:[ \\t]*--*[ \\t]*:$/.test(sLine)) {\n return ' style=\"text-align:center;\"';\n } else {\n return '';\n }\n }\n\n function parseHeaders (header, style) {\n var id = '';\n header = header.trim();\n // support both tablesHeaderId and tableHeaderId due to error in documentation so we don't break backwards compatibility\n if (options.tablesHeaderId || options.tableHeaderId) {\n id = ' id=\"' + header.replace(/ /g, '_').toLowerCase() + '\"';\n }\n header = showdown.subParser('spanGamut')(header, options, globals);\n\n return '' + header + '\\n';\n }\n\n function parseCells (cell, style) {\n var subText = showdown.subParser('spanGamut')(cell, options, globals);\n return '' + subText + '\\n';\n }\n\n function buildTable (headers, cells) {\n var tb = '\\n\\n\\n',\n tblLgn = headers.length;\n\n for (var i = 0; i < tblLgn; ++i) {\n tb += headers[i];\n }\n tb += '\\n\\n\\n';\n\n for (i = 0; i < cells.length; ++i) {\n tb += '\\n';\n for (var ii = 0; ii < tblLgn; ++ii) {\n tb += cells[i][ii];\n }\n tb += '\\n';\n }\n tb += '\\n
      \\n';\n return tb;\n }\n\n function parseTable (rawTable) {\n var i, tableLines = rawTable.split('\\n');\n\n for (i = 0; i < tableLines.length; ++i) {\n // strip wrong first and last column if wrapped tables are used\n if (/^ {0,3}\\|/.test(tableLines[i])) {\n tableLines[i] = tableLines[i].replace(/^ {0,3}\\|/, '');\n }\n if (/\\|[ \\t]*$/.test(tableLines[i])) {\n tableLines[i] = tableLines[i].replace(/\\|[ \\t]*$/, '');\n }\n // parse code spans first, but we only support one line code spans\n tableLines[i] = showdown.subParser('codeSpans')(tableLines[i], options, globals);\n }\n\n var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),\n rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),\n rawCells = [],\n headers = [],\n styles = [],\n cells = [];\n\n tableLines.shift();\n tableLines.shift();\n\n for (i = 0; i < tableLines.length; ++i) {\n if (tableLines[i].trim() === '') {\n continue;\n }\n rawCells.push(\n tableLines[i]\n .split('|')\n .map(function (s) {\n return s.trim();\n })\n );\n }\n\n if (rawHeaders.length < rawStyles.length) {\n return rawTable;\n }\n\n for (i = 0; i < rawStyles.length; ++i) {\n styles.push(parseStyles(rawStyles[i]));\n }\n\n for (i = 0; i < rawHeaders.length; ++i) {\n if (showdown.helper.isUndefined(styles[i])) {\n styles[i] = '';\n }\n headers.push(parseHeaders(rawHeaders[i], styles[i]));\n }\n\n for (i = 0; i < rawCells.length; ++i) {\n var row = [];\n for (var ii = 0; ii < headers.length; ++ii) {\n if (showdown.helper.isUndefined(rawCells[i][ii])) {\n\n }\n row.push(parseCells(rawCells[i][ii], styles[ii]));\n }\n cells.push(row);\n }\n\n return buildTable(headers, cells);\n }\n\n text = globals.converter._dispatch('tables.before', text, options, globals);\n\n // find escaped pipe characters\n text = text.replace(/\\\\(\\|)/g, showdown.helper.escapeCharactersCallback);\n\n // parse multi column tables\n text = text.replace(tableRgx, parseTable);\n\n // parse one column tables\n text = text.replace(singeColTblRgx, parseTable);\n\n text = globals.converter._dispatch('tables.after', text, options, globals);\n\n return text;\n});\n","showdown.subParser('underline', function (text, options, globals) {\n 'use strict';\n\n if (!options.underline) {\n return text;\n }\n\n text = globals.converter._dispatch('underline.before', text, options, globals);\n\n if (options.literalMidWordUnderscores) {\n text = text.replace(/\\b_?__(\\S[\\s\\S]*)___?\\b/g, function (wm, txt) {\n return '' + txt + '';\n });\n } else {\n text = text.replace(/_?__(\\S[\\s\\S]*?)___?/g, function (wm, m) {\n return (/\\S$/.test(m)) ? '' + m + '' : wm;\n });\n }\n\n // escape remaining underscores to prevent them being parsed by italic and bold\n text = text.replace(/(_)/g, showdown.helper.escapeCharactersCallback);\n\n text = globals.converter._dispatch('underline.after', text, options, globals);\n\n return text;\n});\n","/**\n * Swap back in all the special characters we've hidden.\n */\nshowdown.subParser('unescapeSpecialChars', function (text, options, globals) {\n 'use strict';\n text = globals.converter._dispatch('unescapeSpecialChars.before', text, options, globals);\n\n text = text.replace(/¨E(\\d+)E/g, function (wholeMatch, m1) {\n var charCodeToReplace = parseInt(m1);\n return String.fromCharCode(charCodeToReplace);\n });\n\n text = globals.converter._dispatch('unescapeSpecialChars.after', text, options, globals);\n return text;\n});\n","var root = this;\n\n// AMD Loader\nif (typeof define === 'function' && define.amd) {\n define(function () {\n 'use strict';\n return showdown;\n });\n\n// CommonJS/nodeJS Loader\n} else if (typeof module !== 'undefined' && module.exports) {\n module.exports = showdown;\n\n// Regular Browser loader\n} else {\n root.showdown = showdown;\n}\n"]} \ No newline at end of file diff --git a/cvat/apps/documentation/static/documentation/js/shortcuts.js b/cvat/apps/documentation/static/documentation/js/shortcuts.js new file mode 100644 index 000000000000..ca95a37ff660 --- /dev/null +++ b/cvat/apps/documentation/static/documentation/js/shortcuts.js @@ -0,0 +1,5 @@ +Mousetrap.bind(userConfig.shortkeys["open_help"].value, function() { + window.location.href = "/documentation/user_guide.html"; + + return false; +}); \ No newline at end of file diff --git a/cvat/apps/documentation/templates/documentation/base_page.html b/cvat/apps/documentation/templates/documentation/base_page.html new file mode 100644 index 000000000000..84f605643506 --- /dev/null +++ b/cvat/apps/documentation/templates/documentation/base_page.html @@ -0,0 +1,28 @@ + +{% load static compress %} + + + + {% block title %} + {% endblock %} + + {% compress js file thirdparty %} + + + {% endcompress %} + + + + + + diff --git a/cvat/apps/documentation/templates/documentation/user_guide.html b/cvat/apps/documentation/templates/documentation/user_guide.html new file mode 100644 index 000000000000..417ca771ffe4 --- /dev/null +++ b/cvat/apps/documentation/templates/documentation/user_guide.html @@ -0,0 +1,9 @@ +{% extends 'documentation/base_page.html' %} + +{% block title %} +CVAT User Guide +{% endblock %} + +{% block content %} +{{ user_guide }} +{% endblock %} diff --git a/cvat/apps/documentation/templates/documentation/xml_format.html b/cvat/apps/documentation/templates/documentation/xml_format.html new file mode 100644 index 000000000000..821b70d0711c --- /dev/null +++ b/cvat/apps/documentation/templates/documentation/xml_format.html @@ -0,0 +1,9 @@ +{% extends 'documentation/base_page.html' %} + +{% block title %} +CVAT XML format +{% endblock %} + +{% block content %} +{{ xml_format }} +{% endblock %} diff --git a/cvat/apps/documentation/tests.py b/cvat/apps/documentation/tests.py new file mode 100644 index 000000000000..7ce503c2dd97 --- /dev/null +++ b/cvat/apps/documentation/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cvat/apps/documentation/urls.py b/cvat/apps/documentation/urls.py new file mode 100644 index 000000000000..4c4af52c0ce3 --- /dev/null +++ b/cvat/apps/documentation/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('user_guide.html', views.UserGuideView), + path('xml_format.html', views.XmlFormatView), +] diff --git a/cvat/apps/documentation/user_guide.md b/cvat/apps/documentation/user_guide.md new file mode 100644 index 000000000000..7829e860eba2 --- /dev/null +++ b/cvat/apps/documentation/user_guide.md @@ -0,0 +1,485 @@ +# User's guide + +[toc] + +Computer Vision Annotation Tool (CVAT) is a web-based tool which helps to annotate video and images for Computer Vision algorithms. It was inspired by [Vatic](http://carlvondrick.com/vatic/) free, online, interactive video annotation tool. CVAT has many powerful features: __interpolation of bounding boxes between key frames, automatic annotation using TensorFlow OD API, shortcuts for most of critical actions, dashboard with a list of annotation tasks, LDAP and basic authorization, etc...__ It was created for and used by a professional data annotation team. UX and UI were optimized especially for computer vision tasks developed by our team. + +## Getting started + +### Authorization +- First of all you have to log in to CVAT tool. + + ![](/static/documentation/images/image001.jpg) + + ![](/static/documentation/images/image002.jpg) + +- If you don't have an account you have to create it using the link below the login page. + + ![](/static/documentation/images/image003.jpg) + +### Administration panel +Type ``/admin`` in URL to go to the administration panel. +There you can: + - Create / edit / delete users + - Control user's permission and access to the tool. + + +### Creating an annotation task + +1. Create an annotation task by pressing ``Create New Task`` button on the main page. + + ![](/static/documentation/images/image004.jpg) + +2. Specify mandatory parameters of the task. You have to fill ``Name``, ``Labels`` and ``Select Files`` at least. + + ![](/static/documentation/images/image005.jpg) + + __Labels__. Use the following schema to create labels: ``label_name input_type=attribute_name:attribute_value1,attribute_value2`` + + Example: ``vehicle @select=type:__undefined__,car,truck,bus,train ~radio=quality:good,bad ~checkbox=parked:false`` + + ``label_name``: for example *vehicle, person, face etc.* + + ````: + - Use ``@`` for unique attributes which cannot be changed from frame to frame *(e.g. age, gender, color, etc)* + - Use ``~`` for temporary attributes which can be changed on any frame *(e.g. quality, pose, truncated, etc)* + + ``input_type``: the following input types are available ``select``, ``checkbox``, ``radio``, ``number``, ``text``. + + ``attribute_name``: for example *age, quality, parked* + + ``attribute_value``: for example *middle-age, good, true* + + Default value for an attribute is the first value after "``:``". + + For ``select`` and ``radio`` input types the special value is available: ``__undefined__``. Specify this value first if an attribute should be annotated explicity. + + + __Bug Tracker__. Specify full URL your bug tracker if you have it. + + __Source__. To create huge tasks please use ``shared`` server directory (choose ``Share`` option in the dialog). + + __Overlap Size__. Use this option to make overlapped segments. The option makes tracks continuous from one segment into another. Use it for interpolation mode. + + __Segment size__. Use this option to divide huge dataset on several segments. + + __Image Quality__. Use this option to specify quality of uploaded images. The option makes it faster to load high-quality datasets. Use the value from ``1`` (completely compressed images) to ``95`` (almost not compressed images). + + Push ``Submit`` button and it will be added into the list of annotation tasks. Finally you should see something similar to the figure below: + + ![](/static/documentation/images/image006.jpg) + +3. Follow a link inside ``Jobs`` section to start annotation process. In some cases you can have several links. It depends on size of your task and ``Overlap Size`` and ``Segment Size`` parameters. To improve UX only several first frames will be loaded and you will be able to annotate first images. Other frames will be loaded in background. + + ![](/static/documentation/images/image007.jpg) + +### Basic navigation + +1. Use arrows below to move on next/previous frame. Mostly every button is covered by a shortcut. To get a hint about the shortcut just put your mouse pointer over an UI element. + + ![](/static/documentation/images/image008.jpg) + +2. An image can be zoom in/out using mouse's wheel. The image will be zoomed relatively your current cursor position. Thus if you point on an object it will be under your mouse during zooming process. + +3. An image can be moved/shifted by holding left mouse button inside some area without annotated objects. If ``Shift`` key is pressed then all annotated objects are ignored otherwise a highlighted bounding box will be moved instead of the image itself. Usually the functionality is used together with zoom to precisely locate an object of interest. + +### Annotation mode (basics) +Usage examples: + - Create new annotations for a set of images. + - Add/modify/delete objects for existing annotations. + +1. Before start need to be sure that ``Annotation`` is selected. + + ![](/static/documentation/images/image009.jpg) + +2. Create a new annotation: + - Choose an object's ``label``. When you created an annotation task you had to specify one or several labels with attributes. + + ![](/static/documentation/images/image010.jpg) + + - Create a bounding box by clicking on ``Create Track`` button or ``N`` shortcut. Choose left top and right bottom points. Your first bounding box is ready! It is possible to adjust boundaries and location of the bounding box using mouse. + + ![](/static/documentation/images/image011.jpg) + +3. In the list of objects you can see the labeled car. In the side panel you can perform basic operations under the object. + + ![](/static/documentation/images/image012.jpg) + +4. An example of fully annotated frame in ``Annotation`` mode can look like on the figure below. + + ![](/static/documentation/images/image013.jpg) + +### Interpolation mode (basics) +Usage examples: + - Create new annotations for a sequence of frames. + - Add/modify/delete objects for existing annotations. + - Edit tracks, merge many bounding boxes into one track. + +1. Before start need to be sure that ``Interpolation`` is selected. + + ![](/static/documentation/images/image014.jpg) + +2. Create a track for an object (look at the selected car as an example): + - Annotate a bounding box on first frame for the object. + + - In ``Interpolation`` mode the bounding box will be interpolated on next frames automatically. + + ![](/static/documentation/images/image015.jpg) + +3. If the object starts to change its position you need to modify bounding boxes where it happens. Changing of bounding boxes on each frame isn't necessary. It is enough to update several key frames and frames between them will be interpolated automatically. See an example below: + - The car starts moving on frame #70. Let's mark the frame as a key frame. + + ![](/static/documentation/images/image016.jpg) + + - Let's jump 30 frames forward and adjust boundaries of the object. + + ![](/static/documentation/images/image017.jpg) + + - After that bounding boxes of the object between 70 and 100 frames will be changed automatically. For example, frame #85 looks like on the figure below: + + ![](/static/documentation/images/image018.jpg) + +4. When the annotated object disappears or becomes too small, you need to finish the track. To do that you need to choose ``Outsided Property``. + + ![](/static/documentation/images/image019.jpg) + +5. If the object isn't visible on a couple of frames and after that it appears again it is possible to use ``Merge Tracks`` functionality to merge several separated tracks into one. + + ![](/static/documentation/images/image020.jpg) + + - Let's create a track for the bus. + + ![](/static/documentation/images/gif001.gif) + + - After that create a track when it appears again on the sequence of frames. + + ![](/static/documentation/images/gif002.gif) + + - Press ``Merge Tracks`` button and click on any bounding box of first track and on any bounding box of second track. + + ![](/static/documentation/images/image021.jpg) + + - Press ``Apply Merge`` button to apply changes. + + ![](/static/documentation/images/image022.jpg) + + - The final annotated sequence of frames in ``Interpolation`` mode can look like the clip below: + + ![](/static/documentation/images/gif003.gif) + +### Attribute Annotation mode (basics) +Usage examples: +- Edit attributes using keyboard with fast navigation between objects and frames. + +1. To enter into ``Attribute Annotation`` mode press ``Shift+Enter`` shortcut. After that it is possible to change attributes using keyboard. + + ![](/static/documentation/images/image023.jpg) + +2. The active attribute will be red. In this case it is ``Age``. + + ![](/static/documentation/images/image024.jpg) + +3. Look at the bottom side panel to see all possible shortcuts to change the attribute. Press ``4`` key on your keyboard to assign ``adult`` value for the attribute. + + ![](/static/documentation/images/image025.jpg) + +4. Press ``Up Arrow``/``Down Arrow`` keys on your keyboard to go to next attribute . + + ![](/static/documentation/images/image026.jpg) + +5. In this case after pressing ``Down Arrow`` you will be able to edit ``Gender`` attribute. + + ![](/static/documentation/images/image027.jpg) + +6. Use ``Right Arrow``/``Left Arrow`` keys to move on previous/next image. + +### Downloading annotations + +1. To download latest annotations save all changes first. Press ``Open Menu`` and then ``Save Work`` button. There is ``Ctrl+s`` shortcut to save annotations quickly. + +2. After that press ``Open Menu`` and then ``Dump Annotation`` button. + + ![](/static/documentation/images/image028.jpg) + +3. The annotation will be written into **.xml** file. To find the annotation file go to the directory where your browser saves downloaded files by default. For more information visit [XML annotation format](/documentation/xml_format.html) description. + + +### Vocabulary + +**Bounding box** is an area which defines boundaries of an object. To specify it you need to define top left and bottom right points. + +**Tight bounding box** is a bounding box where margin between the object inside and boundaries of the box is absent. By default the type of bounding box is used in most tasks but precision completely depends on an annotation task. + +| Bounding box |Tight bounding box| +| ------------ |:----------------:| +| ![](/static/documentation/images/image030.jpg) | ![](/static/documentation/images/image031.jpg)| + +--- +**Label** is a type of an annotated object (e.g. person, car, face, etc) + +![](/static/documentation/images/image032.jpg) + +--- + +**Attribute** is a property of an annotated object (e.g. color, model, quality, etc). There are two types of attributes: + +- __Unique__: immutable and isn't changed from frame to frame (e.g age, gender, color, etc) +- __Temporary__: mutable and can be changed on any frame (e.g. quality, pose, truncated, etc) + + ![](/static/documentation/images/image033.jpg) + +--- +**Track** is a set of bounding boxes on different frames which corresponds to one object. Tracks are created in ``Interpolation`` mode. + +![](/static/documentation/images/gif004.gif) + +--- +**Annotation** is a set of bounding boxes and tracks. There are several types of annotations: +- *Manual* which is created by a person +- *Semi-automatic* which is created automatically but modified by a person +- *Automatic* which is created automatically without a person in the loop + +## Interface of the annotation tool + +![](/static/documentation/images/image034.jpg) + +--- +### Navigation by frames/images + +![](/static/documentation/images/image035.jpg) + +--- +Go to the first and latest frames. + +![](/static/documentation/images/image036.jpg) + +--- +Go to the next/previous frame with a predefined step. Shortcuts: ``v`` — step backward, ``c`` — step forward. By default the step is ``10``. + +![](/static/documentation/images/image037.jpg) + +To change the predefined step go to settings (``Open Menu`` —> ``Settings``) and modify ``Player Step`` property. + +![](/static/documentation/images/image038.jpg) + +![](/static/documentation/images/image039.jpg) + +--- +Go to the next/previous frame with step equals to 1. Shortcuts: ``d`` — previous, ``f`` — next. + +![](/static/documentation/images/image040.jpg) + +--- +Play the sequence of frames or the set of images. Shortcut: ``Space``. + +![](/static/documentation/images/image041.jpg) + +To adjust player speed go to settings (``Open Menu`` —> ``Settings``) and modify a value of ``Player Speed`` property. + +![](/static/documentation/images/image042.jpg) + +Go to specified frame. + +![](/static/documentation/images/image060.jpg) + + +### Bottom side panel + +![](/static/documentation/images/image043.jpg) + +### Side panel (list of objects) + +In the side panel you can see the list of available objects on the current frame. An example how the list can look like below: + +|Annotation mode|Interpolation mode| +|--|--| +|![](/static/documentation/images/image044.jpg)|![](/static/documentation/images/image045.jpg)| + +--- + +A bounding box can be locked to prevent its modification or moving by an accident. Shortcut to lock an object: ``l``. + +![](/static/documentation/images/image046.jpg) + +--- +A bounding box can be removed. Shortcut: ``Delete``. A locked bounding box can be deleted using ``Shift+Delete`` shortcut. + +![](/static/documentation/images/image047.jpg) + +--- +A bounding box can be **Occluded**. Shortcut: ``q``. Such bounding boxes have dashed boundaries. + +![](/static/documentation/images/image048.jpg) + +![](/static/documentation/images/image049.jpg) + +--- +The type of a bounding box can be changed by selecting __Label__ property. For instance, it can look like on the figure below: + +![](/static/documentation/images/image050.jpg) + +To change a type of a bounding box using keyboard you need to press ``Shift+``. + +### Open Menu +It is the main menu for the annotation tool. It can be used to download, upload and remove annotations. As well it shows statistics about the current annotation task. + +![](/static/documentation/images/image051.jpg) + +### Settings + +The menu contains different parameters which can be adjust by the user needs. For example, ``Auto Saving Internal``, ``Player Step``, ``Player Speed``. + +![](/static/documentation/images/image052.jpg) + + - ``Brightness`` makes it appear that there is more or less light within the image. + - ``Contrast`` controls the difference between dark and light parts of the image + - ``Saturation`` takes away all color or enhance the color. + +## Annotation mode (advanced) + +Basic operations in the mode was described above. + +__occluded__ attribute is used if an object is occluded by another object or it isn't fully visible on the frame. Use ``q`` shortcut to set the property quickly. + +![](/static/documentation/images/image053.jpg) + +Example: both cars on the figure below should be labeled as __occluded__. + +![](/static/documentation/images/image054.jpg) + +If a frame contains too many objects and it is difficult to annotate them due to many bounding boxes are placed mostly in the same place when it makes sense to lock them. Bounding boxes for locked objects are transparent and it is easy to annotate new objects. Also it will not be possible to change previously annotated objects by an accident. Shortcut: ``l``. + +![](/static/documentation/images/image055.jpg) + +## Interpolation mode (advanced) + +Basic operations in the mode was described above. + +Bounding boxes created in the mode have extra navigation buttons. +- These buttons help to jump to previous/next key frame. + + ![](/static/documentation/images/image056.jpg) + +- The button helps to jump to initial frame for the object (first bounding box for the track). + + ![](/static/documentation/images/image057.jpg) + + +## Attribute Annotation mode (advanced) + +Basic operations in the mode was described above. + +It is possible to handle many objects on the same frame in the mode. + +![](/static/documentation/images/image058.jpg) + +It is more convenient to annotate objects of the same type. For the purpose it is possible to specify a corresponding filter. For example, the following filter will hide all objects except pedestrians: ``//pedestrian``. + +To navigate between objects (pedestrians in the case) use the following shortcuts: +- ``Tab`` - go to the next object +- ``Shift+Tab`` - go to the previous object. + +By default in the mode objects are zoomed. To disable the functionality uncheck the corresponding setting: ``Open Menu`` —> ``Settings`` —> ``Zoom boxes in Attribute Annotation Mode``. + +By default other objects are hidden. To change the behaviour uncheck the corresponding setting: ``Open Menu`` —> ``Setting`` —> ``Hide Other in Attribute Annotation Mode``. + +## Filter + +![](/static/documentation/images/image059.jpg) + +There are several reasons to use the feature: + +1. When use a filter objects which don't correspond to the filter will be hidden. Use ``Settings`` —> ``Hide Filtered Tracks`` or ``K`` shortcut if you want to change the behaviour. +2. Fast navigation between frames which have an object of interest. Use ``Left Arrow/Right Arrow`` keys for the purpose. If the filter is empty the mentioned arrows will go to previous/next frames. + +To use the functionality it is enough to specify a value inside ``Filter`` text box and defocus the text box (for example, click on the image). After that the filter will be applied. + +--- +In a trivial case a correct filter should correspond to the template: ``//label[prop operator "value"]`` + +``label`` is a type of an object (e.g _person, car, face_, etc). If the type isn't important you can use ``*``. + +``prop`` is a property which should be filtered. The following items are available: + + - ``id`` — identifier of an object. It helps to find a specific object easily in case of huge number of objects and images/frames. + - ``type`` — an annotation type. Possible values: + - ``annotation`` + - ``interpolation`` + - ``lock`` accepts ``true`` and ``false`` values. It can be used to hide all locked objects. + - ``occluded`` accepts ``true`` and ``false`` values. It can be used to hide all occluded objects. + - ``attr`` is a prefix to access attributes of an object. For example, it is possible to access _race_ attribute. For the purpose you should specify ``attr/race``. To access all attributes it is necessary to write ``attr/*``. + +``operator`` can be ``=`` (equal), ``!=`` (not equal), ``<`` (less), ``>`` (more), ``<=`` (less or equal), ``>=`` (more or equal). + +``"value"`` — value of an attribute or a property. It has to be specified in quotes. + +--- + +Example | Description +-------------------------------|------------- +``//face`` | all faces +``//*[id=4]`` | object with id #4 +``//*[type="annotation"]`` | *annotation* objects only +``//car[occluded="true"]`` | cars with *occluded* property +``//*[lock!="true"]`` | all unlocked objects +``//car[attr/parked="true"]`` | parked cars +``//*[attr/*="__undefined__"]``| any objects with ``__undefined__`` value of an attribute + +--- + +The functionality allows to create more complex conditions. Several filters can be combined by ``or``, ``and``, ``|`` operators. Operators ``or``, ``and`` can be applied inside square brackets. ``|`` operator (union) can be applied outside of square brackets. + +Example | Description +--------------------------------------------------------|------------- +``//person[attr/age>="25" and attr/age<="35"]`` | people with age between 25 and 35. +``//face[attr/glass="sunglass" or attr/glass="no"]`` | faces with sunglasses or without glasses at all. +```//person[attr/race="asian"] | //car[attr/model="bmw" or attr/model="mazda"]``` | asian persons or bmw or mazda cars. + + +## Shortcuts + +Many UI elements have shortcut hints. Put your pointer to an interesting element to see it. + +![](/static/documentation/images/image061.jpg) + +![](/static/documentation/images/image062.jpg) + +| Shortcut | Common | +-----------------------|------------------------------ +``L`` | lock/unlock a selected object +``L+T`` | lock/unlock all objects and tracks on the current frame +``Q`` or ``Num-`` | set occluded property for a selected object +``N`` | create a new annotated object +``Ctrl+`` | change type of new objects by default +``Shift+`` | change type of a selected object +``Enter`` | change color of bounding box for a selected object +``H`` | hide bounding boxes on every frame +``J`` | hide labels with attributes on every frame +``Delete`` | delete a selected object +``Shift+Delete`` | delete a selected object even if it is locked +``F`` | go to next frame +``D`` | go to previous frame +``V`` | go forward with a predefined step +``C`` | go backward with a predefined step +``Ctrl+C`` | copy a selected object +``Ctrl+V`` | insert a copied object +``F1`` | open help +``F1`` in dashboard | open page with documentation +``F2`` | open settings +``Ctrl+S`` | save job +| | __Interpolation__ | +``M`` | enter/apply merge mode +``Ctrl+M`` | leave merge mode without saving changes +``R`` | go to the next key frame of a selected object +``E`` | go to the previous key frame of a selected object +| | __Attribute annotation mode__ | +``Shift+Enter`` | enter/leave Attribute Annotation mode +``Up Arrow`` | go to the next attribute (up) +``Down Arrown`` | go to the next attribute (down) +``Tab`` | go to the next annotated object +``Shift+Tab`` | go to the previous annotated object +```` | assign a corresponding value to the current attribute +| | __Filter__ | +``Left Arrow`` | go to the previous frame which corresponds to the specified filter value +``Right Arrow`` | go to the next frame which corresponds to the specified filter value +``K`` | hide all objects which don't correspond to the specified filter value diff --git a/cvat/apps/documentation/views.py b/cvat/apps/documentation/views.py new file mode 100644 index 000000000000..831523db3178 --- /dev/null +++ b/cvat/apps/documentation/views.py @@ -0,0 +1,16 @@ +from django.shortcuts import render +import os + +def UserGuideView(request): + module_dir = os.path.dirname(__file__) + doc_path = os.path.join(module_dir, 'user_guide.md') + + return render(request, 'documentation/user_guide.html', + context={"user_guide": open(doc_path, "r").read()}) + +def XmlFormatView(request): + module_dir = os.path.dirname(__file__) + doc_path = os.path.join(module_dir, 'xml_format.md') + + return render(request, 'documentation/xml_format.html', + context={"xml_format": open(doc_path, "r").read()}) diff --git a/cvat/apps/documentation/xml_format.md b/cvat/apps/documentation/xml_format.md new file mode 100644 index 000000000000..a3506f07a9e9 --- /dev/null +++ b/cvat/apps/documentation/xml_format.md @@ -0,0 +1,210 @@ +# XML annotation format + +When you want to download annotations from Computer Vision Annotation Tool (CVAT) you can choose one of several data formats. The document describes XML annotation format. Each format has X.Y version (e.g. 1.0). In general the major version (X) is incremented then the data format has incompatible changes and the minor version (Y) is incremented then the data format is slightly modified (e.g. it has one or several extra fields inside meta information). The document will describe all changes for all versions of XML annotation format. + +## Version 1 + +There are two different formats for annotation and interpolation modes at the moment. Both formats has a common part which is described below: + +```xml + + + String: version of the format (e.g 1.0) + + + Number: id of the task + String: some task name + Number: count of frames/images in the task + String: interpolation or annotation + Number: number of overlaped frames between segments + String: URL on an page which describe the task + String: date when the task was created + String: date when the task was updated + + + + + + Number: id of the segment + Number: first frame + Number: last frame + String: URL (e.g. http://cvat.example.com/?id=213) + + + + String: the author of the task + String: email of the author + + + String: date when the annotation was dumped + + ... + +``` + +### Annotation +Below you can find description of the data format for annotation mode. In the mode images are annotated. On each image it is possible to have many different objects. Each object can have multiple attributes. +```xml + + + ... + + + String: the attribute value + ... + + ... + + ... + +``` + +Example: +```xml + + + 1.0 + + + 1063 + My annotation task + 75 + annotation + 0 + + 2018-06-06 11:57:54.807162+03:00 + 2018-06-06 12:42:29.375251+03:00 + + + + + + 3086 + 0 + 74 + http://cvat.examle.com:8080/?id=3086 + + + + admin + + + + 2018-06-06 15:47:04.386866+03:00 + + + + false + a + + + + + true + a + + + + + false + b + + + + + false + c + + + +``` + +### Interpolation +Below you can find description of the data format for interpolation mode. In the mode frames are annotated. The annotation contains tracks. Each track corresponds to an object which can be presented on multiple frames. The same object cannot be presented on the same frame in multiple locations. Each location of the object can have multiple attributes even if an attribute is immutable for the object it will be cloned for each location (a known redundancy). +```xml + + + ... + + + String: the attribute value + ... + + ... + + ... + +``` + +Example: +```xml + + + 1.0 + + + 1062 + My interpolation task + 30084 + interpolation + 20 + + 2018-05-31 14:13:36.483219+03:00 + 2018-06-06 13:56:32.113705+03:00 + + + + + + 3085 + 0 + 30083 + http://cvat.example.com:8080/?id=3085 + + + + admin + + + + 2018-06-06 15:52:11.138470+03:00 + + + + 1 + + + 1 + + + 1 + + + + + 3 + + + 3 + + + 3 + + + +``` \ No newline at end of file diff --git a/cvat/apps/engine/__init__.py b/cvat/apps/engine/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/engine/admin.py b/cvat/apps/engine/admin.py new file mode 100644 index 000000000000..8c38f3f3dad5 --- /dev/null +++ b/cvat/apps/engine/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cvat/apps/engine/annotation.py b/cvat/apps/engine/annotation.py new file mode 100644 index 000000000000..83fd7271908a --- /dev/null +++ b/cvat/apps/engine/annotation.py @@ -0,0 +1,1069 @@ +import os +import copy +from django.utils import timezone +from collections import OrderedDict +import numpy as np +from scipy.optimize import linear_sum_assignment +from collections import OrderedDict +from distutils.util import strtobool +from xml.dom import minidom +from xml.sax.saxutils import XMLGenerator +from abc import ABCMeta, abstractmethod + +import django_rq +from django.conf import settings +from django.db import transaction + +from . import models +from .task import get_frame_path +from .logging import task_logger, job_logger + +############################# Low Level server API + +FORMAT_XML = 1 +FORMAT_JSON = 2 + +def dump(tid, data_format, scheme, host): + """ + Dump annotation for the task in specified data format. + """ + queue = django_rq.get_queue('default') + queue.enqueue_call(func=_dump, args=(tid, data_format, scheme, host), + job_id="annotation.dump/{}".format(tid)) + +def check(tid): + """ + Check that potentialy long operation 'dump' is completed. + Return the status as json/dictionary object. + """ + queue = django_rq.get_queue('default') + job = queue.fetch_job("annotation.dump/{}".format(tid)) + if job is None: + response = {"state": "unknown"} + elif job.is_failed: + # FIXME: here we have potential race. In general job.exc_info is + # initialized inside handler but the method can be called before + # that. By a reason exc_info isn't initialized by RQ python. + response = { + "state": "error", + "stderr": job.exc_info} + elif job.is_finished: + response = {"state": "created"} + else: + response = {"state": "started"} + + return response + +@transaction.atomic +def get(jid): + """ + Get annotations for the job. + """ + db_job = models.Job.objects.select_for_update().get(id=jid) + annotation = _AnnotationForJob(db_job) + annotation.init_from_db() + + return annotation.to_client() + +@transaction.atomic +def save_job(jid, data): + """ + Save new annotations for the job. + """ + db_job = models.Job.objects.select_for_update().get(id=jid) + annotation = _AnnotationForJob(db_job) + annotation.init_from_client(data) + annotation.save_boxes_to_db() + annotation.save_paths_to_db() + db_job.segment.task.updated_date = timezone.now() + db_job.segment.task.save() + +# pylint: disable=unused-argument +def save_task(tid, data): + """ + Save new annotations for the task. + """ + db_task = models.Task.objects.get(id=tid) + db_segments = list(db_task.segment_set.prefetch_related('job_set').all()) + + splitted_data = {} + + for segment in db_segments: + jid = segment.job_set.first().id + start = segment.start_frame + stop = segment.stop_frame + splitted_data[jid] = { + "boxes": list(filter(lambda x: start <= x['frame'] <= stop, data['boxes'])), + "tracks": list(filter(lambda x: len(list(filter(lambda y: (start <= y['frame'] <= stop) and (not y['outside']), x['boxes']))), data['tracks'])) + } + + for jid, _data in splitted_data.items(): + save_job(jid, _data) + +# pylint: disable=unused-argument +def rq_handler(job, exc_type, exc_value, traceback): + tid = job.id.split('/')[1] + task_logger[tid].error("dump annotation error was occured", exc_info=True) + +################################################## + +class _Label: + def __init__(self, db_label): + self.id = db_label.id + self.name = db_label.name + +class _Attribute: + def __init__(self, db_attr, value): + self.id = db_attr.id + self.name = db_attr.get_name() + if db_attr.get_type() == 'checkbox': + self.value = str(value).lower() + else: + self.value = str(value) + +class _BoundingBox: + def __init__(self, x0, y0, x1, y1, frame, occluded, attributes=None): + self.xtl = x0 + self.ytl = y0 + self.xbr = x1 + self.ybr = y1 + self.occluded = occluded + self.frame = frame + self.attributes = attributes if attributes else [] + + def merge(self, box): + # The occluded property and attributes cannot be merged. Let's keep + # original attributes and occluded property of the self object. + assert self.frame == box.frame + self.xtl = (self.xtl + box.xtl) / 2 + self.ytl = (self.ytl + box.ytl) / 2 + self.xbr = (self.xbr + box.xbr) / 2 + self.ybr = (self.ybr + box.ybr) / 2 + + def add_attribute(self, attr): + self.attributes.append(attr) + +class _LabeledBox(_BoundingBox): + def __init__(self, label, x0, y0, x1, y1, frame, occluded, attributes=None): + super().__init__(x0, y0, x1, y1, frame, occluded, attributes) + self.label = label + +class _TrackedBox(_BoundingBox): + def __init__(self, x0, y0, x1, y1, frame, occluded, outside, attributes=None): + super().__init__(x0, y0, x1, y1, frame, occluded, attributes) + self.outside = outside + +class _InterpolatedBox(_TrackedBox): + def __init__(self, x0, y0, x1, y1, frame, occluded, outside, keyframe, attributes=None): + super().__init__(x0, y0, x1, y1, frame, occluded, outside, attributes) + self.keyframe = keyframe + +class _ObjectPath: + def __init__(self, label, start_frame, stop_frame, boxes=None, attributes=None): + self.label = label + self.frame = start_frame + self.stop_frame = stop_frame + self.boxes = boxes if boxes else [] + self.attributes = attributes if attributes else [] + self._interpolated_boxes = [] + assert not self.boxes or self.boxes[-1].frame <= self.stop_frame + + def add_box(self, box): + self.boxes.append(box) + + def get_interpolated_boxes(self): + if not self._interpolated_boxes: + self._init_interpolated_boxes() + + return self._interpolated_boxes + + def _init_interpolated_boxes(self): + assert self.boxes[-1].frame <= self.stop_frame + + boxes = [] + stop_box = copy.copy(self.boxes[-1]) + stop_box.frame = self.stop_frame + 1 + attributes = {} + for box0, box1 in zip(self.boxes, self.boxes[1:] + [stop_box]): + assert box0.frame < box1.frame + + distance = float(box1.frame - box0.frame) + delta_xtl = (box1.xtl - box0.xtl) / distance + delta_ytl = (box1.ytl - box0.ytl) / distance + delta_xbr = (box1.xbr - box0.xbr) / distance + delta_ybr = (box1.ybr - box0.ybr) / distance + + # New box doesn't have all attributes (only first one does). + # Thus it is necessary to propagate them. + for attr in box0.attributes: + attributes[attr.id] = attr + + for frame in range(box0.frame, box1.frame): + off = frame - box0.frame + xtl = box0.xtl + delta_xtl * off + ytl = box0.ytl + delta_ytl * off + xbr = box0.xbr + delta_xbr * off + ybr = box0.ybr + delta_ybr * off + + box = _InterpolatedBox(xtl, ytl, xbr, ybr, frame, box0.occluded, + box0.outside, box0.frame == frame, list(attributes.values())) + boxes.append(box) + + if box0.outside: + break + + self._interpolated_boxes = boxes + + def merge(self, path): + assert self.label.id == path.label.id + boxes = {box.frame:box for box in self.boxes} + for box in path.boxes: + if box.frame in boxes: + boxes[box.frame].merge(box) + else: + boxes[box.frame] = box + + self.frame = min(self.frame, path.frame) + self.stop_frame = max(self.stop_frame, path.stop_frame) + self.boxes = list(sorted(boxes.values(), key=lambda box: box.frame)) + self._interpolated_boxes = [] + + def add_attribute(self, attr): + self.attributes.append(attr) + +class _Annotation: + def __init__(self, start_frame, stop_frame): + self.boxes = [] + self.paths = [] + self.start_frame = start_frame + self.stop_frame = stop_frame + + def reset(self): + self.boxes = [] + self.paths = [] + + def to_boxes(self): + boxes = [] + for path in self.paths: + for box in path.get_interpolated_boxes(): + if not box.outside: + box = _LabeledBox(path.label, box.xtl, box.ytl, box.xbr, box.ybr, + box.frame, box.occluded, box.attributes + path.attributes) + boxes.append(box) + + return self.boxes + boxes + + def to_paths(self): + paths = [] + for box in self.boxes: + box0 = _InterpolatedBox(box.xtl, box.ytl, box.xbr, box.ybr, box.frame, + box.occluded, False, True) + box1 = copy.copy(box0) + box1.outside = True + box1.frame += 1 + path = _ObjectPath(box.label, box.frame, box.frame + 1, [box0, box1], box.attributes) + paths.append(path) + + return self.paths + paths + + +class _AnnotationForJob(_Annotation): + def __init__(self, db_job): + db_segment = db_job.segment + super().__init__(db_segment.start_frame, db_segment.stop_frame) + + # pylint: disable=bad-continuation + self.db_job = db_job + self.logger = job_logger[db_job.id] + self.db_labels = {db_label.id:db_label + for db_label in db_job.segment.task.label_set.all()} + self.db_attributes = {db_attr.id:db_attr + for db_attr in models.AttributeSpec.objects.filter( + label__task__id=db_job.segment.task.id)} + + def _merge_table_rows(self, rows, keys_for_merge, field_id): + """dot.notation access to dictionary attributes""" + class dotdict(OrderedDict): + __getattr__ = OrderedDict.get + __setattr__ = OrderedDict.__setitem__ + __delattr__ = OrderedDict.__delitem__ + __eq__ = lambda self, other: self.id == other.id + __hash__ = lambda self: self.id + + # It is necessary to keep a stable order of original rows + # (e.g. for tracked boxes). Otherwise prev_box.frame can be bigger + # than next_box.frame. + merged_rows = OrderedDict() + + # Group all rows by field_id. In grouped rows replace fields in + # accordance with keys_for_merge structure. + for row in rows: + row_id = row[field_id] + if not row_id in merged_rows: + merged_rows[row_id] = dotdict(row) + for key in keys_for_merge: + merged_rows[row_id][key] = [] + + for key in keys_for_merge: + item = dotdict({v.split('__', 1)[-1]:row[v] for v in keys_for_merge[key]}) + if item.id: + merged_rows[row_id][key].append(item) + + # Remove redundant keys from final objects + redundant_keys = [item for values in keys_for_merge.values() for item in values] + for i in merged_rows: + for j in redundant_keys: + del merged_rows[i][j] + + return list(merged_rows.values()) + + + def init_from_db(self): + self.reset() + + db_boxes = list(self.db_job.labeledbox_set.prefetch_related('labeledboxattributeval_set') \ + .values('id', 'frame', 'xtl', 'ytl', 'xbr', 'ybr', 'label_id', 'occluded', + 'labeledboxattributeval__value', 'labeledboxattributeval__spec_id', + 'labeledboxattributeval__id').order_by('frame')) + + keys_for_merge = { + 'attributes': [ + 'labeledboxattributeval__value', + 'labeledboxattributeval__spec_id', + 'labeledboxattributeval__id' + ] + } + db_boxes = self._merge_table_rows(db_boxes, keys_for_merge, 'id') + + for db_box in db_boxes: + label = _Label(self.db_labels[db_box.label_id]) + box = _LabeledBox(label, db_box.xtl, db_box.ytl, + db_box.xbr, db_box.ybr, db_box.frame, db_box.occluded) + for db_attr in db_box.attributes: + if db_attr.id != None: + spec = self.db_attributes[db_attr.spec_id] + attr = _Attribute(spec, db_attr.value) + box.add_attribute(attr) + self.boxes.append(box) + + db_paths = list(self.db_job.objectpath_set.prefetch_related('trackedbox_set') \ + .prefetch_related('objectpathattributeval_set') \ + .prefetch_related('trackedbox_set__trackedboxattributeval_set') \ + .values('id', 'frame', 'objectpathattributeval__spec_id', + 'objectpathattributeval__id', 'objectpathattributeval__value', + 'trackedbox__id', 'label_id', 'trackedbox__xtl', 'trackedbox__ytl', + 'trackedbox__xbr', 'trackedbox__ybr', 'trackedbox__frame', 'trackedbox__occluded', + 'trackedbox__outside', 'trackedbox__trackedboxattributeval__spec_id', + 'trackedbox__trackedboxattributeval__value', 'trackedbox__trackedboxattributeval__id') \ + .order_by('id', 'trackedbox__frame')) + + keys_for_merge = { + 'attributes': [ + 'objectpathattributeval__value', + 'objectpathattributeval__spec_id', + 'objectpathattributeval__id' + ], + 'boxes': [ + 'trackedbox__id', 'trackedbox__xtl', 'trackedbox__ytl', + 'trackedbox__xbr', 'trackedbox__ybr', 'trackedbox__frame', + 'trackedbox__occluded', 'trackedbox__outside', + 'trackedbox__trackedboxattributeval__value', + 'trackedbox__trackedboxattributeval__spec_id', + 'trackedbox__trackedboxattributeval__id' + ] + } + db_paths = self._merge_table_rows(db_paths, keys_for_merge, 'id') + + keys_for_merge = { + 'attributes': [ + 'trackedboxattributeval__value', + 'trackedboxattributeval__spec_id', + 'trackedboxattributeval__id' + ] + } + for db_path in db_paths: + db_path.boxes = self._merge_table_rows(db_path.boxes, keys_for_merge, 'id') + db_path.attributes = list(set(db_path.attributes)) + for db_box in db_path.boxes: + db_box.attributes = list(set(db_box.attributes)) + + for db_path in db_paths: + label = _Label(self.db_labels[db_path.label_id]) + path = _ObjectPath(label, db_path.frame, self.stop_frame) + for db_attr in db_path.attributes: + spec = self.db_attributes[db_attr.spec_id] + attr = _Attribute(spec, db_attr.value) + path.add_attribute(attr) + + frame = -1 + for db_box in db_path.boxes: + box = _TrackedBox(db_box.xtl, db_box.ytl, db_box.xbr, db_box.ybr, + db_box.frame, db_box.occluded, db_box.outside) + assert box.frame > frame + frame = box.frame + + for db_attr in db_box.attributes: + spec = self.db_attributes[db_attr.spec_id] + attr = _Attribute(spec, db_attr.value) + box.add_attribute(attr) + path.add_box(box) + + self.paths.append(path) + + def init_from_client(self, data): + # All fields inside data should be converted to correct type explicitly. + # We cannot trust that client will send 23 as integer. Here we also + # accept "23". + self.reset() + + for box in data['boxes']: + label = _Label(self.db_labels[int(box['label_id'])]) + + labeled_box = _LabeledBox(label, float(box['xtl']), float(box['ytl']), + float(box['xbr']), float(box['ybr']), int(box['frame']), + strtobool(str(box['occluded']))) + + for attr in box['attributes']: + spec = self.db_attributes[int(attr['id'])] + attr = _Attribute(spec, str(attr['value'])) + labeled_box.add_attribute(attr) + + self.boxes.append(labeled_box) + + for track in data['tracks']: + label = _Label(self.db_labels[int(track['label_id'])]) + boxes = [] + frame = -1 + for box in track['boxes']: + if int(box['frame']) <= self.stop_frame: + tracked_box = _TrackedBox(float(box['xtl']), float(box['ytl']), + float(box['xbr']), float(box['ybr']), int(box['frame']), + strtobool(str(box['occluded'])), strtobool(str(box['outside']))) + assert tracked_box.frame > frame + frame = tracked_box.frame + + for attr in box['attributes']: + spec = self.db_attributes[int(attr['id'])] + assert spec.is_mutable() + attr = _Attribute(spec, str(attr['value'])) + tracked_box.add_attribute(attr) + + boxes.append(tracked_box) + else: + self.logger.error("init_from_client: ignore frame #%d " + + "because stop_frame is %d", box['frame'], self.stop_frame) + + attributes = [] + for attr in track['attributes']: + spec = self.db_attributes[int(attr['id'])] + assert not spec.is_mutable() + attr = _Attribute(spec, str(attr['value'])) + attributes.append(attr) + + assert frame <= self.stop_frame + object_path = _ObjectPath(label, int(track['frame']), self.stop_frame, + boxes, attributes) + self.paths.append(object_path) + + def save_boxes_to_db(self): + self.db_job.labeledbox_set.all().delete() + db_boxes = [] + db_attrvals = [] + + for box in self.boxes: + db_box = models.LabeledBox() + db_box.job = self.db_job + db_box.label = self.db_labels[box.label.id] + db_box.frame = box.frame + db_box.xtl = box.xtl + db_box.ytl = box.ytl + db_box.xbr = box.xbr + db_box.ybr = box.ybr + db_box.occluded = box.occluded + + for attr in box.attributes: + db_attrval = models.LabeledBoxAttributeVal() + db_attrval.box_id = len(db_boxes) + db_attrval.spec = self.db_attributes[attr.id] + db_attrval.value = attr.value + db_attrvals.append(db_attrval) + + db_boxes.append(db_box) + + db_boxes = models.LabeledBox.objects.bulk_create(db_boxes) + if db_boxes and db_boxes[0].id == None: + # Try to get primary keys. Probably the code will work for sqlite + # but it definetely doesn't work for Postgres. Need to say that + # for Postgres bulk_create will return objects with ids even ids + # are auto incremented. Thus we will not be inside the 'if'. + db_boxes = list(self.db_job.labeledbox_set.all()) + for db_attrval in db_attrvals: + db_attrval.box_id = db_boxes[db_attrval.box_id].id + models.LabeledBoxAttributeVal.objects.bulk_create(db_attrvals) + + def save_paths_to_db(self): + self.db_job.objectpath_set.all().delete() + + db_paths = [] + db_path_attrvals = [] + db_boxes = [] + db_box_attrvals = [] + + for path in self.paths: + db_path = models.ObjectPath() + db_path.job = self.db_job + db_path.label = self.db_labels[path.label.id] + db_path.frame = path.frame + + for attr in path.attributes: + db_attrspec = self.db_attributes[attr.id] + + db_attrval = models.ObjectPathAttributeVal() + db_attrval.track_id = len(db_paths) + db_attrval.spec = db_attrspec + db_attrval.value = attr.value + + db_path_attrvals.append(db_attrval) + + for box in path.boxes: + db_box = models.TrackedBox() + db_box.track_id = len(db_paths) + db_box.xtl = box.xtl + db_box.ytl = box.ytl + db_box.xbr = box.xbr + db_box.ybr = box.ybr + db_box.frame = box.frame + db_box.occluded = box.occluded + db_box.outside = box.outside + + for attr in box.attributes: + db_attrspec = self.db_attributes[attr.id] + + db_attrval = models.TrackedBoxAttributeVal() + db_attrval.box_id = len(db_boxes) + db_attrval.spec = db_attrspec + db_attrval.value = attr.value + db_box_attrvals.append(db_attrval) + + db_boxes.append(db_box) + db_paths.append(db_path) + + db_paths = models.ObjectPath.objects.bulk_create(db_paths) + if db_paths and db_paths[0].id == None: + # Try to get primary keys. Probably the code will work for sqlite + # but it definetely doesn't work for Postgres. Need to say that + # for Postgres bulk_create will return objects with ids even ids + # are auto incremented. Thus we will not be inside the 'if'. + db_paths = list(self.db_job.objectpath_set.all()) + for db_attrval in db_path_attrvals: + db_attrval.track_id = db_paths[db_attrval.track_id].id + models.ObjectPathAttributeVal.objects.bulk_create(db_path_attrvals) + + for db_box in db_boxes: + db_box.track_id = db_paths[db_box.track_id].id + + db_boxes = models.TrackedBox.objects.bulk_create(db_boxes) + if db_boxes and db_boxes[0].id == None: + # Try to get primary keys. Probably the code will work for sqlite + # but it definetely doesn't work for Postgres. Need to say that + # for Postgres bulk_create will return objects with ids even ids + # are auto incremented. Thus we will not be inside the 'if'. + db_boxes = list(models.TrackedBox.objects.filter(track__job_id=self.db_job.id)) + + for db_attrval in db_box_attrvals: + db_attrval.box_id = db_boxes[db_attrval.box_id].id + models.TrackedBoxAttributeVal.objects.bulk_create(db_box_attrvals) + + def to_client(self): + data = {"boxes": [], "tracks": []} + for box in self.boxes: + labeled_box = { + "label_id": box.label.id, + "xtl": box.xtl, + "ytl": box.ytl, + "xbr": box.xbr, + "ybr": box.ybr, + "occluded": box.occluded, + "frame": box.frame, + "attributes": [{ + "id": attr.id, + "value": attr.value + } for attr in box.attributes], + } + data["boxes"].append(labeled_box) + + for path in self.paths: + boxes = [] + for box in path.boxes: + tracked_box = { + "frame": box.frame, + "xtl": box.xtl, + "ytl": box.ytl, + "xbr": box.xbr, + "ybr": box.ybr, + "occluded": box.occluded, + "outside": box.outside, + "attributes": [{ + "id": attr.id, + "value": attr.value + } for attr in box.attributes] + } + boxes.append(tracked_box) + + track = { + "label_id": path.label.id, + "frame": path.frame, + "attributes": [{ + "id": attr.id, + "value": attr.value + } for attr in path.attributes], + "boxes": boxes, + } + data["tracks"].append(track) + + return data + + +class _AnnotationForSegment(_Annotation): + def __init__(self, db_segment): + super().__init__(db_segment.start_frame, db_segment.stop_frame) + self.db_segment = db_segment + + def init_from_db(self): + # FIXME: at the moment a segment has only one job always. Thus + # the implementation makes sense. Need to implement a good one + # in the future. + self.reset() + + db_job0 = list(self.db_segment.job_set.all())[0] + annotation = _AnnotationForJob(db_job0) + annotation.init_from_db() + self.boxes = annotation.boxes + self.paths = annotation.paths + +@transaction.atomic +def _dump(tid, data_format, scheme, host): + db_task = models.Task.objects.select_for_update().get(id=tid) + annotation = _AnnotationForTask(db_task) + annotation.init_from_db() + annotation.dump(data_format, db_task, scheme, host) + +def _calc_box_area(box): + return (box.xbr - box.xtl) * (box.ybr - box.ytl) + +def _calc_overlap_box_area(box0, box1): + dx = min(box0.xbr, box1.xbr) - max(box0.xtl, box1.xtl) + dy = min(box0.ybr, box1.ybr) - max(box0.ytl, box1.ytl) + if dx > 0 and dy > 0: + return dx * dy + else: + return 0 + +def _calc_box_IoU(box0, box1): + overlap_area = _calc_overlap_box_area(box0, box1) + return overlap_area / (_calc_box_area(box0) + _calc_box_area(box1) - overlap_area) + +class _AnnotationWriter: + __metaclass__ = ABCMeta + + def __init__(self, file, version): + self.version = version + self.file = file + + @abstractmethod + def open_root(self): + raise NotImplementedError + + @abstractmethod + def add_meta(self, meta): + raise NotImplementedError + + @abstractmethod + def open_track(self, track): + raise NotImplementedError + + @abstractmethod + def open_image(self, image): + raise NotImplementedError + + @abstractmethod + def open_box(self, box): + raise NotImplementedError + + @abstractmethod + def add_attribute(self, attribute): + raise NotImplementedError + + @abstractmethod + def close_box(self): + raise NotImplementedError + + @abstractmethod + def close_image(self): + raise NotImplementedError + + @abstractmethod + def close_track(self): + raise NotImplementedError + + @abstractmethod + def close_root(self): + raise NotImplementedError + +class _XmlAnnotationWriter(_AnnotationWriter): + def __init__(self, file): + super().__init__(file, "1.0") + self.xmlgen = XMLGenerator(self.file, 'utf-8') + self._level = 0 + + def _indent(self, newline = True): + if newline: + self.xmlgen.ignorableWhitespace("\n") + self.xmlgen.ignorableWhitespace(" " * self._level) + + def _add_version(self): + self._indent() + self.xmlgen.startElement("version", {}) + self.xmlgen.characters(self.version) + self.xmlgen.endElement("version") + + def open_root(self): + self.xmlgen.startDocument() + self.xmlgen.startElement("annotations", {}) + self._level += 1 + self._add_version() + + def _add_meta(self, meta): + self._level += 1 + for k, v in meta.items(): + if isinstance(v, OrderedDict): + self._indent() + self.xmlgen.startElement(k, {}) + self._add_meta(v) + self._indent() + self.xmlgen.endElement(k) + else: + self._indent() + self.xmlgen.startElement(k, {}) + self.xmlgen.characters(v) + self.xmlgen.endElement(k) + self._level -= 1 + + def add_meta(self, meta): + self._indent() + self.xmlgen.startElement("meta", {}) + self._add_meta(meta) + self._indent() + self.xmlgen.endElement("meta") + + def open_track(self, track): + self._indent() + self.xmlgen.startElement("track", track) + self._level += 1 + + def open_image(self, image): + self._indent() + self.xmlgen.startElement("image", image) + self._level += 1 + + def open_box(self, box): + self._indent() + self.xmlgen.startElement("box", box) + self._level += 1 + + def add_attribute(self, attribute): + self._indent() + self.xmlgen.startElement("attribute", {"name": attribute["name"]}) + self.xmlgen.characters(attribute["value"]) + self.xmlgen.endElement("attribute") + + def close_box(self): + self._level -= 1 + self._indent() + self.xmlgen.endElement("box") + + def close_image(self): + self._level -= 1 + self._indent() + self.xmlgen.endElement("image") + + def close_track(self): + self._level -= 1 + self._indent() + self.xmlgen.endElement("track") + + def close_root(self): + self._level -= 1 + self._indent() + self.xmlgen.endElement("annotations") + self.xmlgen.endDocument() + +class _AnnotationForTask(_Annotation): + def __init__(self, db_task): + super().__init__(0, db_task.size) + self.db_task = db_task + + def init_from_db(self): + self.reset() + + for db_segment in self.db_task.segment_set.all(): + annotation = _AnnotationForSegment(db_segment) + annotation.init_from_db() + self._merge_boxes(annotation.boxes, db_segment.start_frame, + self.db_task.overlap) + self._merge_paths(annotation.paths, db_segment.start_frame, + self.db_task.overlap) + + def _merge_paths(self, paths, start_frame, overlap): + # 1. Split paths on two parts: new and which can be intersected + # with existing paths. + new_paths = [path for path in paths + if path.frame >= start_frame + overlap] + int_paths = [path for path in paths + if path.frame < start_frame + overlap] + assert len(new_paths) + len(int_paths) == len(paths) + + # 4. Find old paths which are intersected with int_paths + old_paths = [] + for path in self.paths: + box = path.get_interpolated_boxes()[-1] + if box.frame >= start_frame: + old_paths.append(path) + + # 3. Add new paths as is. It should be done only after old_paths + # variable is initialized. + self.paths.extend(new_paths) + + # Nothing to merge. Just add all int_paths if any. + if not old_paths or not int_paths: + self.paths.extend(int_paths) + return + + # 4. Build cost matrix for each path and find correspondence using + # Hungarian algorithm. + min_cost_thresh = 0.5 + cost_matrix = np.empty(shape=(len(int_paths), len(old_paths)), + dtype=float) + for i, int_path in enumerate(int_paths): + for j, old_path in enumerate(old_paths): + cost_matrix[i][j] = 1 + if int_path.label.id == old_path.label.id: + # Here start_frame is the start frame of next segment + # and stop_frame is the stop frame of current segment + stop_frame = start_frame + overlap - 1 + int_boxes = int_path.get_interpolated_boxes() + old_boxes = old_path.get_interpolated_boxes() + int_boxes = {box.frame:box for box in int_boxes if box.frame <= stop_frame} + old_boxes = {box.frame:box for box in old_boxes if box.frame >= start_frame} + assert int_boxes and old_boxes + + count, error = 0, 0 + for frame in range(start_frame, stop_frame + 1): + box0, box1 = int_boxes.get(frame), old_boxes.get(frame) + if box0 and box1: + if box0.outside != box1.outside: + error += 1 + else: + error += 1 - _calc_box_IoU(box0, box1) + count += 1 + elif box0 or box1: + error += 1 + count += 1 + + cost_matrix[i][j] = error / count + + # 6. Find optimal solution using Hungarian algorithm. + row_ind, col_ind = linear_sum_assignment(cost_matrix) + int_paths_indexes = list(range(0, len(int_paths))) + for i, j in zip(row_ind, col_ind): + # Reject the solution if the cost is too high. Remember + # inside int_boxes_indexes boxes which were handled. + if cost_matrix[i][j] <= min_cost_thresh: + old_paths[j].merge(int_paths[i]) + int_paths_indexes[i] = -1 + + # 7. Add all paths which were not processed. + for i in int_paths_indexes: + if i != -1: + self.paths.append(int_paths[i]) + + def _merge_boxes(self, boxes, start_frame, overlap): + # 1. Split boxes on two parts: new and which can be intersected + # with existing boxes. + new_boxes = [box for box in boxes + if box.frame >= start_frame + overlap] + int_boxes = [box for box in boxes + if box.frame < start_frame + overlap] + assert len(new_boxes) + len(int_boxes) == len(boxes) + + # 2. Convert to more convenient data structure (boxes by frame) + int_boxes_by_frame = {} + for box in int_boxes: + if box.frame in int_boxes_by_frame: + int_boxes_by_frame[box.frame].append(box) + else: + int_boxes_by_frame[box.frame] = [box] + + old_boxes_by_frame = {} + for box in self.boxes: + if box.frame >= start_frame: + if box.frame in old_boxes_by_frame: + old_boxes_by_frame[box.frame].append(box) + else: + old_boxes_by_frame[box.frame] = [box] + + # 3. Add new boxes as is. It should be done only after old_boxes_by_frame + # variable is initialized. + self.boxes.extend(new_boxes) + + # Nothing to merge here. Just add all int_boxes if any. + if not old_boxes_by_frame or not int_boxes_by_frame: + self.boxes.extend(int_boxes) + return + + # 4. Build cost matrix for each frame and find correspondence using + # Hungarian algorithm. In this case min_cost_thresh is stronger + # because we compare only on one frame. + min_cost_thresh = 0.25 + for frame in int_boxes_by_frame: + if frame in old_boxes_by_frame: + int_boxes = int_boxes_by_frame[frame] + old_boxes = old_boxes_by_frame[frame] + cost_matrix = np.empty(shape=(len(int_boxes), len(old_boxes)), + dtype=float) + # 5.1 Construct cost matrix for the frame. + for i, box0 in enumerate(int_boxes): + for j, box1 in enumerate(old_boxes): + if box0.label.id == box1.label.id: + cost_matrix[i][j] = 1 - _calc_box_IoU(box0, box1) + else: + cost_matrix[i][j] = 1 + + # 6. Find optimal solution using Hungarian algorithm. + row_ind, col_ind = linear_sum_assignment(cost_matrix) + int_boxes_indexes = list(range(0, len(int_boxes))) + for i, j in zip(row_ind, col_ind): + # Reject the solution if the cost is too high. Remember + # inside int_boxes_indexes boxes which were handled. + if cost_matrix[i][j] <= min_cost_thresh: + old_boxes[j].merge(int_boxes[i]) + int_boxes_indexes[i] = -1 + + # 7. Add all boxes which were not processed. + for i in int_boxes_indexes: + if i != -1: + self.boxes.append(int_boxes[i]) + else: + # We don't have old boxes on the frame. Let's add all new ones. + self.boxes.extend(int_boxes_by_frame[frame]) + + def dump(self, data_format, db_task, scheme, host): + db_segments = db_task.segment_set.all().prefetch_related('job_set') + db_labels = db_task.label_set.all().prefetch_related('attributespec_set') + + meta = OrderedDict([ + ("task", OrderedDict([ + ("id", str(db_task.id)), + ("name", db_task.name), + ("size", str(db_task.size)), + ("mode", db_task.mode), + ("overlap", str(db_task.overlap)), + ("bugtracker", db_task.bug_tracker), + ("created", str(timezone.localtime(db_task.created_date))), + ("updated", str(timezone.localtime(db_task.updated_date))), + + ("labels", OrderedDict( + [("label", OrderedDict([ + ("name", db_label.name), + ("attributes", OrderedDict([("attribute", db_attr.text) + for db_attr in db_label.attributespec_set.all()])) + ])) for db_label in db_labels] + )), + + ("segments", OrderedDict( + [("segment", OrderedDict([ + ("id", str(db_segment.id)), + ("start", str(db_segment.start_frame)), + ("stop", str(db_segment.stop_frame)), + ("url", "{0}://{1}/?id={2}".format( + scheme, host, db_segment.job_set.all()[0].id)) + ])) for db_segment in db_segments] + )), + + ("owner", OrderedDict([ + ("username", db_task.owner.username), + ("email", db_task.owner.email) + ])), + ])), + ("dumped", str(timezone.localtime(timezone.now()))) + ]) + + + dump_path = self.db_task.get_dump_path() + with open(dump_path, "w") as dump_file: + dumper = _XmlAnnotationWriter(dump_file) + dumper.open_root() + dumper.add_meta(meta) + + if self.db_task.mode == "annotation": + boxes = {} + for box in self.to_boxes(): + if box.frame in boxes: + boxes[box.frame].append(box) + else: + boxes[box.frame] = [box] + + for frame in sorted(boxes): + link = get_frame_path(self.db_task.id, frame) + path = os.readlink(link) + + rpath = path.split(os.path.sep) + rpath = os.path.sep.join(rpath[rpath.index(".upload")+1:]) + + dumper.open_image(OrderedDict([ + ("id", str(frame)), + ("name", rpath) + ])) + for box in boxes[frame]: + dumper.open_box(OrderedDict([ + ("label", box.label.name), + ("xtl", "{:.2f}".format(box.xtl)), + ("ytl", "{:.2f}".format(box.ytl)), + ("xbr", "{:.2f}".format(box.xbr)), + ("ybr", "{:.2f}".format(box.ybr)), + ("occluded", str(int(box.occluded))) + ])) + for attr in box.attributes: + dumper.add_attribute(OrderedDict([ + ("name", attr.name), + ("value", attr.value) + ])) + dumper.close_box() + dumper.close_image() + else: + paths = self.to_paths() + for idx, path in enumerate(paths): + dumper.open_track(OrderedDict([ + ("id", str(idx)), + ("label", path.label.name) + ])) + for box in path.get_interpolated_boxes(): + dumper.open_box(OrderedDict([ + ("frame", str(box.frame)), + ("xtl", "{:.2f}".format(box.xtl)), + ("ytl", "{:.2f}".format(box.ytl)), + ("xbr", "{:.2f}".format(box.xbr)), + ("ybr", "{:.2f}".format(box.ybr)), + ("outside", str(int(box.outside))), + ("occluded", str(int(box.occluded))), + ("keyframe", str(int(box.keyframe))) + ])) + for attr in path.attributes + box.attributes: + dumper.add_attribute(OrderedDict([ + ("name", attr.name), + ("value", attr.value) + ])) + dumper.close_box() + dumper.close_track() + + dumper.close_root() diff --git a/cvat/apps/engine/apps.py b/cvat/apps/engine/apps.py new file mode 100644 index 000000000000..a445bbe79ba0 --- /dev/null +++ b/cvat/apps/engine/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class EngineConfig(AppConfig): + name = 'engine' diff --git a/cvat/apps/engine/logging.py b/cvat/apps/engine/logging.py new file mode 100644 index 000000000000..7677fc382737 --- /dev/null +++ b/cvat/apps/engine/logging.py @@ -0,0 +1,70 @@ +import os +import inspect +import logging +from . import models +from cvat.settings.base import LOGGING + + +class TaskLoggerStorage: + def __init__(self): + self._storage = dict() + self._formatter = logging.getLogger('task') + + def __getitem__(self, tid): + if tid not in self._storage: + self._storage[tid] = self._create_task_logger(tid) + return self._storage[tid] + + def _create_task_logger(self, tid): + task = self._get_task(tid) + if task is not None: + configuration = LOGGING.copy() + handler_configuration = configuration['handlers']['file'] + handler_configuration['filename'] = task.get_log_path() + configuration['handlers'] = { + 'file_{}'.format(tid): handler_configuration + } + configuration['loggers'] = { + 'task_{}'.format(tid): { + 'handlers': ['file_{}'.format(tid)], + 'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'), + } + } + + logging.config.dictConfig(configuration) + logger = logging.getLogger('task_{}'.format(tid)) + return logger + else: + raise Exception('Key must be task indentificator') + + def _get_task(self, tid): + try: + return models.Task.objects.get(pk=tid) + except Exception: + return None + + +class JobLoggerStorage: + def __init__(self): + self._storage = dict() + + def __getitem__(self, jid): + if jid not in self._storage: + self._storage[jid] = self._get_task_logger(jid) + return self._storage[jid] + + def _get_task_logger(self, jid): + job = self._get_job(jid) + if job is not None: + return task_logger[job.segment.task.id] + else: + raise Exception('Key must be job identificator') + + def _get_job(self, jid): + try: + return models.Job.objects.select_related("segment__task").get(id=jid) + except Exception: + return None + +task_logger = TaskLoggerStorage() +job_logger = JobLoggerStorage() diff --git a/cvat/apps/engine/media.mimetypes b/cvat/apps/engine/media.mimetypes new file mode 100644 index 000000000000..289bffc4b6e1 --- /dev/null +++ b/cvat/apps/engine/media.mimetypes @@ -0,0 +1,198 @@ +# generated from /usr/share/mime/globs on my system + +# possible video mimetypes (including mts which isn't in /etc/mime.types) +video/mp2t mts +video/quicktime qtvr +video/x-msvideo divx +video/vnd.mpegurl mxu +video/mpeg mpeg +video/x-flic flc +video/x-flic fli +video/3gpp2 3gpp2 +video/x-flv flv +video/mpeg -9][0-9][0-9].vdr +video/x-sgi-movie movie +video/x-anim anim[1-9j] +video/3gpp2 3gp2 +video/mp2t mpls +video/x-ms-wmp wmp +video/x-ms-wmp wmp +video/mp2t m2ts +video/mp4 f4v +video/3gpp 3gpp +video/x-ms-wmv wmv +video/dv dv +video/vnd.vivo vivo +video/x-javafx fxm +video/webm webm +video/mp4 lrv +video/quicktime qt +video/vnd.rn-realvideo rv +video/mp2t ts +video/x-nsv nsv +video/mp2t cpi +video/x-matroska-3d mk3d +video/x-msvideo avf +video/x-msvideo avi +video/vnd.vivo viv +video/annodex axv +video/vnd.rn-realvideo rvx +video/mpeg vob +video/quicktime moov +video/3gpp2 3g2 +video/3gpp 3ga +video/3gpp 3gp +video/ogg ogg +video/x-theora+ogg ogg +video/x-ogm+ogg ogm +video/x-matroska mkv +video/ogg ogv +video/mp2t bdm +video/mp2t clpi +video/x-mng mng +video/mpeg mp2 +video/mp4 mp4 +video/vnd.mpegurl m1u +video/quicktime mov +video/mpeg mpe +video/mpeg mpg +video/mp2t mpl +video/mp2t m2t +video/mp2t bdmv +video/vnd.mpegurl m4u +video/mp4 m4v + +# possible image formats +image/x-minolta-mrw mrw +image/x-sgi sgi +image/vnd.wap.wbmp wbmp +image/bmp bmp +image/x-kde-raw bmq +image/x-kde-raw bmq +image/openraster ora +image/x-kde-raw fff +image/x-kde-raw fff +image/x-skencil sk1 +image/x-olympus-orf orf +image/vnd.djvu djv +image/x-hdr hdr +image/x-hdr hdr +image/x-xfig fig +image/svg+xml-compressed svgz +image/x-adobe-dng dng +image/x-sony-sr2 sr2 +image/x-macpaint pntg +image/x-sony-srf srf +image/x-ilbm lbm +image/x-applix-graphics ag +image/x-pict pict +image/x-compressed-xcf xcf.bz2 +image/x-bzeps epsi.bz2 +image/jpeg jpeg +image/x-sun-raster sun +image/x-wmf wmf +image/fits fits +image/svg+xml svg +image/vnd.dwg dwg +image/vnd.dxf dxf +image/x-pict pict1 +image/x-pict pict2 +image/fax-g3 g3 +image/x-nikon-nef nef +image/x-kde-raw hrd +image/x-kde-raw hrd +image/x-jng jng +image/jp2 jp2 +image/x-portable-bitmap pbm +image/x-eps epsf +image/x-photo-cd pcd +image/jpeg jpe +image/jp2 jpf +image/jpeg jpg +image/x-pict pct +image/vnd.zbrush.pcx pcx +image/jp2 jpx +image/x-eps epsi +image/x-pentax-pef pef +image/x-bzeps epsf.bz2 +image/x-fuji-raf raf +image/x-cmu-raster ras +image/x-panasonic-raw raw +image/x-gzeps epsi.gz +image/x-lwo lwob +image/x-portable-graymap pgm +image/x-kde-raw rdc +image/x-kde-raw rdc +image/x-ilbm ilbm +image/x-hdr pic +image/x-pic pic +image/x-hdr pic +image/x-pic pic +image/webp webp +image/webp webp +image/x-webp webp +image/cgm cgm +image/x-rgb rgb +image/vnd.rn-realpix rp +image/x-skencil sk +image/x-gzeps epsf.gz +image/png png +image/x-portable-anymap pnm +image/x-kde-raw pnx +image/x-kde-raw pnx +image/x-lwo lwo +image/x-lws lws +image/x-tga tga +image/x-tga tpic +image/rle rle +image/x-portable-pixmap ppm +image/x-tga vda +image/vnd.djvu djvu +image/x-bzeps eps.bz2 +image/tiff tif +image/x-sony-arw arw +image/vnd.adobe.photoshop psd +image/x-xbitmap xbm +image/x-tga icb +image/vnd.microsoft.icon ico +image/x-xcf xcf +image/x-canon-cr2 cr2 +image/x-compressed-xcf xcf.gz +image/x-emf emf +image/x-kde-raw cs1 +image/x-kde-raw cs1 +image/gif gif +image/x-kde-raw cs2 +image/x-kde-raw cs2 +image/ief ief +image/x-canon-crw crw +image/x-ilbm iff +image/x-eps eps +image/x-kodak-kdc kdc +image/x-win-bitmap cur +image/x-panasonic-raw2 rw2 +image/x-kde-raw erf +image/x-kde-raw erf +image/x-gzeps eps.gz +image/x-kde-raw mdc +image/x-kde-raw mdc +image/vnd.ms-modi mdi +image/tiff tiff +image/x-3ds 3ds +image/x-tga vst +image/x-exr exr +image/x-quicktime qtif +image/x-icns icns +image/x-xpixmap xpm +image/x-sigma-x3f x3f +image/x-kde-raw bay +image/x-kde-raw bay +image/x-kodak-k25 k25 +image/x-msod msod +image/x-xwindowdump xwd +image/x-kodak-dcr dcr +image/x-kde-raw mos +image/x-kde-raw mos +image/x-dds dds +image/x-quicktime qif + diff --git a/cvat/apps/engine/migrations/0001_release_v0_1_0.py b/cvat/apps/engine/migrations/0001_release_v0_1_0.py new file mode 100644 index 000000000000..74ab2647aac1 --- /dev/null +++ b/cvat/apps/engine/migrations/0001_release_v0_1_0.py @@ -0,0 +1,200 @@ +# Generated by Django 2.0.3 on 2018-05-23 11:51 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='AttributeSpec', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(max_length=1024)), + ], + ), + migrations.CreateModel( + name='Job', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + ), + migrations.CreateModel( + name='Label', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=64)), + ], + ), + migrations.CreateModel( + name='LabeledBox', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('frame', models.PositiveIntegerField()), + ('xtl', models.FloatField()), + ('ytl', models.FloatField()), + ('xbr', models.FloatField()), + ('ybr', models.FloatField()), + ('occluded', models.BooleanField(default=False)), + ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Job')), + ('label', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Label')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='LabeledBoxAttributeVal', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.CharField(max_length=64)), + ('box', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.LabeledBox')), + ('spec', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.AttributeSpec')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ObjectPath', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('frame', models.PositiveIntegerField()), + ('job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Job')), + ('label', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Label')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ObjectPathAttributeVal', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.CharField(max_length=64)), + ('spec', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.AttributeSpec')), + ('track', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.ObjectPath')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Segment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('start_frame', models.IntegerField()), + ('stop_frame', models.IntegerField()), + ], + ), + migrations.CreateModel( + name='Task', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=256)), + ('size', models.PositiveIntegerField()), + ('path', models.CharField(max_length=256)), + ('mode', models.CharField(max_length=32)), + ('created_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now_add=True)), + ('status', models.CharField(default='annotate', max_length=32)), + ('bug_tracker', models.CharField(default='', max_length=2000)), + ('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('overlap', models.PositiveIntegerField(default=0)), + ], + options={ + 'permissions': (('view_task', 'Can see available tasks'), ('view_annotation', 'Can see annotation for the task'), ('change_annotation', 'Can modify annotation for the task')), + }, + ), + migrations.CreateModel( + name='TrackedBox', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('xtl', models.FloatField()), + ('ytl', models.FloatField()), + ('xbr', models.FloatField()), + ('ybr', models.FloatField()), + ('occluded', models.BooleanField(default=False)), + ('frame', models.PositiveIntegerField()), + ('outside', models.BooleanField(default=False)), + ('track', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.ObjectPath')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='TrackedBoxAttributeVal', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('value', models.CharField(max_length=64)), + ('box', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.TrackedBox')), + ('spec', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.AttributeSpec')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='segment', + name='task', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Task'), + ), + migrations.AddField( + model_name='label', + name='task', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Task'), + ), + migrations.AddField( + model_name='job', + name='segment', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Segment'), + ), + migrations.AddField( + model_name='attributespec', + name='label', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engine.Label'), + ), + migrations.AlterField( + model_name='labeledbox', + name='id', + field=models.PositiveIntegerField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='objectpath', + name='id', + field=models.PositiveIntegerField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='trackedbox', + name='id', + field=models.PositiveIntegerField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='labeledbox', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='objectpath', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='trackedbox', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AddField( + model_name='job', + name='annotator', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/cvat/apps/engine/migrations/__init__.py b/cvat/apps/engine/migrations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/engine/models.py b/cvat/apps/engine/models.py new file mode 100644 index 000000000000..b8e86716d69b --- /dev/null +++ b/cvat/apps/engine/models.py @@ -0,0 +1,159 @@ +from django.db import models +from django.conf import settings + +from django.contrib.auth.models import User + +import shlex +import csv +from io import StringIO +import re +import os + + +class Task(models.Model): + name = models.CharField(max_length=256) + size = models.PositiveIntegerField() + path = models.CharField(max_length=256) + mode = models.CharField(max_length=32) + owner = models.ForeignKey(User, null=True, on_delete=models.CASCADE) + bug_tracker = models.CharField(max_length=2000, default="") + created_date = models.DateTimeField(auto_now_add=True) + updated_date = models.DateTimeField(auto_now_add=True) + status = models.CharField(max_length=32, default="annotate") + overlap = models.PositiveIntegerField(default=0) + + # Extend default permission model + class Meta: + permissions = ( + ("view_task", "Can see available tasks"), + ("view_annotation", "Can see annotation for the task"), + ("change_annotation", "Can modify annotation for the task"), + ) + + def get_upload_dirname(self): + return os.path.join(self.path, ".upload") + + def get_data_dirname(self): + return os.path.join(self.path, "data") + + def get_dump_path(self): + return os.path.join(self.path, "{}.dump".format(self.name)) + + def get_log_path(self): + return os.path.join(self.path, "task.log") + + def get_client_log_path(self): + return os.path.join(self.path, "client.log") + + def set_task_dirname(self, path): + self.path = path + self.save(update_fields=['path']) + + def get_task_dirname(self): + return self.path + + def __str__(self): + return self.name + +class Segment(models.Model): + task = models.ForeignKey(Task, on_delete=models.CASCADE) + start_frame = models.IntegerField() + stop_frame = models.IntegerField() + +class Job(models.Model): + segment = models.ForeignKey(Segment, on_delete=models.CASCADE) + annotator = models.ForeignKey(User, null=True, on_delete=models.SET_NULL) + # TODO: add sub-issue number for the task + +class Label(models.Model): + task = models.ForeignKey(Task, on_delete=models.CASCADE) + name = models.CharField(max_length=64) + + def __str__(self): + return self.name + +class AttributeSpec(models.Model): + label = models.ForeignKey(Label, on_delete=models.CASCADE) + text = models.CharField(max_length=1024) + + def get_attribute(self): + match = re.match(r'^([~@])(\w+)=(\w+):(.+)$', self.text) + prefix = match.group(1) + type = match.group(2) + name = match.group(3) + values = list(csv.reader(StringIO(match.group(4)), quotechar="'"))[0] + + return {'prefix':prefix, 'type':type, 'name':name, 'values':values} + + def is_mutable(self): + attr = self.get_attribute() + return attr['prefix'] == '~' + + def get_type(self): + attr = self.get_attribute() + return attr['type'] + + def get_name(self): + attr = self.get_attribute() + return attr['name'] + + def get_default_value(self): + attr = self.get_attribute() + return attr['values'][0] + + def get_values(self): + attr = self.get_attribute() + return attr['values'] + + + def __str__(self): + return self.get_attribute()['name'] + +class AttributeVal(models.Model): + # TODO: add a validator here to be sure that it corresponds to self.label + spec = models.ForeignKey(AttributeSpec, on_delete=models.CASCADE) + value = models.CharField(max_length=64) + class Meta: + abstract = True + +class Annotation(models.Model): + job = models.ForeignKey(Job, on_delete=models.CASCADE) + label = models.ForeignKey(Label, on_delete=models.CASCADE) + frame = models.PositiveIntegerField() + class Meta: + abstract = True + +class BoundingBox(models.Model): + xtl = models.FloatField() + ytl = models.FloatField() + xbr = models.FloatField() + ybr = models.FloatField() + # TODO: need to think where to define below properties + occluded = models.BooleanField(default=False) + class Meta: + abstract = True + +class LabeledBox(Annotation, BoundingBox): + pass + +class LabeledBoxAttributeVal(AttributeVal): + box = models.ForeignKey(LabeledBox, on_delete=models.CASCADE) + +class ObjectPath(Annotation): + pass + +class ObjectPathAttributeVal(AttributeVal): + track = models.ForeignKey(ObjectPath, on_delete=models.CASCADE) + +class TrackedObject(models.Model): + track = models.ForeignKey(ObjectPath, on_delete=models.CASCADE) + frame = models.PositiveIntegerField() + outside = models.BooleanField(default=False) + class Meta: + abstract = True + +class TrackedBox(TrackedObject, BoundingBox): + pass + +class TrackedBoxAttributeVal(AttributeVal): + box = models.ForeignKey(TrackedBox, on_delete=models.CASCADE) diff --git a/cvat/apps/engine/static/engine/base.css b/cvat/apps/engine/static/engine/base.css new file mode 100644 index 000000000000..404f7022ce37 --- /dev/null +++ b/cvat/apps/engine/static/engine/base.css @@ -0,0 +1,92 @@ +html { + background-color: #FFFFFF; + margin: 0px auto; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +@font-face { + font-family: BarlowSemiCondensed-Regular; + src: url(fonts/BarlowSemiCondensed-Regular.ttf); +} + +@font-face { + font-family: BarlowSemiCondensed-SemiBold; + src: url(fonts/BarlowSemiCondensed-SemiBold.ttf); +} + +@font-face { + font-family: BarlowSemiCondensed-Bold; + src: url(fonts/BarlowSemiCondensed-Bold.ttf); +} + +.regular { + font-family: BarlowSemiCondensed-Regular; +} + +.semiBold { + font-family: BarlowSemiCondensed-SemiBold; +} + +.bold { + font-family: BarlowSemiCondensed-Bold; +} + +.h2 { + font-size: 1.2em; +} + +.h1 { + font-size: 1.4em; +} + +.h3 { + font-size: 1.1em; +} + +.overlay { + position: fixed; + display: none; + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: white; + z-index: 100; +} + +.modal { + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.4); + overflow: hidden; +} + +.modal-content { + background-color: #FFFFFF; + margin: 15% auto; /* 15% from the top and centered */ + padding: 20px; + border: 1px solid #888; + width: 80%; /* Could be more or less, depending on screen size */ +} + +.hidden { + display: none; +} + +.selectable { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} \ No newline at end of file diff --git a/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-Bold.ttf b/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-Bold.ttf new file mode 100644 index 000000000000..35b5a372f108 Binary files /dev/null and b/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-Bold.ttf differ diff --git a/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-Regular.ttf b/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-Regular.ttf new file mode 100644 index 000000000000..ccdebedcd51e Binary files /dev/null and b/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-Regular.ttf differ diff --git a/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-SemiBold.ttf b/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-SemiBold.ttf new file mode 100644 index 000000000000..660b40256c7c Binary files /dev/null and b/cvat/apps/engine/static/engine/fonts/BarlowSemiCondensed-SemiBold.ttf differ diff --git a/cvat/apps/engine/static/engine/fonts/README.md b/cvat/apps/engine/static/engine/fonts/README.md new file mode 100644 index 000000000000..73a8fef315af --- /dev/null +++ b/cvat/apps/engine/static/engine/fonts/README.md @@ -0,0 +1,95 @@ +Fonts was downloaded from: https://fonts.google.com/specimen/Barlow+Semi+Condensed + +Copyright 2017 The Barlow Project Authors (https://github.com/jpt/barlow) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/cvat/apps/engine/static/engine/icons/README.md b/cvat/apps/engine/static/engine/icons/README.md new file mode 100644 index 000000000000..bad04298db46 --- /dev/null +++ b/cvat/apps/engine/static/engine/icons/README.md @@ -0,0 +1,5 @@ +Icons was downloaded from: https://icomoon.io/#preview-free [GitHub](https://github.com/Keyamoon/IcoMoon-Free) + +[License](https://github.com/Keyamoon/IcoMoon-Free/blob/master/License.txt): + +You can use this package under one of these two licenses: [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/) or [GPL](http://www.gnu.org/licenses/gpl.html). diff --git a/cvat/apps/engine/static/engine/icons/keyframe.png b/cvat/apps/engine/static/engine/icons/keyframe.png new file mode 100644 index 000000000000..252321a8f644 Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/keyframe.png differ diff --git a/cvat/apps/engine/static/engine/icons/lock.png b/cvat/apps/engine/static/engine/icons/lock.png new file mode 100644 index 000000000000..c8174e56b4f4 Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/lock.png differ diff --git a/cvat/apps/engine/static/engine/icons/non-keyframe.png b/cvat/apps/engine/static/engine/icons/non-keyframe.png new file mode 100644 index 000000000000..619dd5bdbac9 Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/non-keyframe.png differ diff --git a/cvat/apps/engine/static/engine/icons/non-occluded.png b/cvat/apps/engine/static/engine/icons/non-occluded.png new file mode 100644 index 000000000000..74ba467558bc Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/non-occluded.png differ diff --git a/cvat/apps/engine/static/engine/icons/non-outside.png b/cvat/apps/engine/static/engine/icons/non-outside.png new file mode 100644 index 000000000000..567710452b9e Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/non-outside.png differ diff --git a/cvat/apps/engine/static/engine/icons/occluded.png b/cvat/apps/engine/static/engine/icons/occluded.png new file mode 100644 index 000000000000..9b607ca9e94f Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/occluded.png differ diff --git a/cvat/apps/engine/static/engine/icons/outside.png b/cvat/apps/engine/static/engine/icons/outside.png new file mode 100644 index 000000000000..4f7cea67f025 Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/outside.png differ diff --git a/cvat/apps/engine/static/engine/icons/unlock.png b/cvat/apps/engine/static/engine/icons/unlock.png new file mode 100644 index 000000000000..5b736985c3d3 Binary files /dev/null and b/cvat/apps/engine/static/engine/icons/unlock.png differ diff --git a/cvat/apps/engine/static/engine/js/3rdparty/defiant.js b/cvat/apps/engine/static/engine/js/3rdparty/defiant.js new file mode 100644 index 000000000000..743f1bea88d7 --- /dev/null +++ b/cvat/apps/engine/static/engine/js/3rdparty/defiant.js @@ -0,0 +1,882 @@ +/* + * defiant.js.js [v1.4.5] + * http://www.defiantjs.com + * Copyright (c) 2013-2017, Hakan Bilgin + * Licensed under the MIT License + */ +/* + * x10.js v0.1.3 + * Web worker wrapper with simple interface + * + * Copyright (c) 2013-2015, Hakan Bilgin + * Licensed under the MIT License + */ + +(function(window, undefined) { + //'use strict'; + + var x10 = { + init: function() { + return this; + }, + work_handler: function(event) { + var args = Array.prototype.slice.call(event.data, 1), + func = event.data[0], + ret = tree[func].apply(tree, args); + + // return process finish + postMessage([func, ret]); + }, + setup: function(tree) { + var url = window.URL || window.webkitURL, + script = 'var tree = {'+ this.parse(tree).join(',') +'};', + blob = new Blob([script + 'self.addEventListener("message", '+ this.work_handler.toString() +', false);'], + {type: 'text/javascript'}), + worker = new Worker(url.createObjectURL(blob)); + + // thread pipe + worker.onmessage = function(event) { + var args = Array.prototype.slice.call(event.data, 1), + func = event.data[0]; + x10.observer.emit('x10:'+ func, args); + }; + + return worker; + }, + call_handler: function(func, worker) { + return function() { + var args = Array.prototype.slice.call(arguments, 0, -1), + callback = arguments[arguments.length-1]; + + // add method name + args.unshift(func); + + // listen for 'done' + x10.observer.on('x10:'+ func, function(event) { + callback(event.detail[0]); + }); + + // start worker + worker.postMessage(args); + }; + }, + compile: function(hash) { + var worker = this.setup(typeof(hash) === 'function' ? {func: hash} : hash), + obj = {}, + fn; + // create return object + if (typeof(hash) === 'function') { + obj.func = this.call_handler('func', worker); + return obj.func; + } else { + for (fn in hash) { + obj[fn] = this.call_handler(fn, worker); + } + return obj; + } + }, + parse: function(tree, isArray) { + var hash = [], + key, + val, + v; + + for (key in tree) { + v = tree[key]; + // handle null + if (v === null) { + hash.push(key +':null'); + continue; + } + // handle undefined + if (v === undefined) { + hash.push(key +':undefined'); + continue; + } + switch (v.constructor) { + case Date: val = 'new Date('+ v.valueOf() +')'; break; + case Object: val = '{'+ this.parse(v).join(',') +'}'; break; + case Array: val = '['+ this.parse(v, true).join(',') +']'; break; + case String: val = '"'+ v.replace(/"/g, '\\"') +'"'; break; + case RegExp: + case Function: val = v.toString(); break; + default: val = v; + } + if (isArray) hash.push(val); + else hash.push(key +':'+ val); + } + return hash; + }, + // simple event emitter + observer: (function() { + var stack = {}; + + return { + on: function(type, fn) { + if (!stack[type]) { + stack[type] = []; + } + stack[type].unshift(fn); + }, + off: function(type, fn) { + if (!stack[type]) return; + var i = stack[type].indexOf(fn); + stack[type].splice(i,1); + }, + emit: function(type, detail) { + if (!stack[type]) return; + var event = { + type : type, + detail : detail, + isCanceled : false, + cancelBubble : function() { + this.isCanceled = true; + } + }, + len = stack[type].length; + while(len--) { + if (event.isCanceled) return; + stack[type][len](event); + } + } + }; + })() + }; + + if (typeof module === "undefined") { + // publish x10 + window.x10 = x10.init(); + } else { + module.exports = x10.init(); + } + +})(this); + + +(function(window, module, undefined) { + 'use strict'; + + var Defiant = { + is_ie : /(msie|trident)/i.test(navigator.userAgent), + is_safari : /safari/i.test(navigator.userAgent), + env : 'production', + xml_decl : '', + namespace : 'xmlns:d="defiant-namespace"', + tabsize : 4, + render: function(template, data) { + var processor = new XSLTProcessor(), + span = document.createElement('span'), + opt = {match: '/'}, + tmpltXpath, + scripts, + temp, + sorter; + // handle arguments + switch (typeof(template)) { + case 'object': + this.extend(opt, template); + if (!opt.data) opt.data = data; + break; + case 'string': + opt.template = template; + opt.data = data; + break; + default: + throw 'error'; + } + opt.data = JSON.toXML(opt.data); + tmpltXpath = '//xsl:template[@name="'+ opt.template +'"]'; + + if (!this.xsl_template) this.gatherTemplates(); + + if (opt.sorter) { + sorter = this.node.selectSingleNode(this.xsl_template, tmpltXpath +'//xsl:for-each//xsl:sort'); + if (sorter) { + if (opt.sorter.order) sorter.setAttribute('order', opt.sorter.order); + if (opt.sorter.select) sorter.setAttribute('select', opt.sorter.select); + sorter.setAttribute('data-type', opt.sorter.type || 'text'); + } + } + + temp = this.node.selectSingleNode(this.xsl_template, tmpltXpath); + temp.setAttribute('match', opt.match); + processor.importStylesheet(this.xsl_template); + span.appendChild(processor.transformToFragment(opt.data, document)); + temp.removeAttribute('match'); + + if (this.is_safari) { + scripts = span.getElementsByTagName('script'); + for (var i=0, il=scripts.length; i'+ str.replace(/defiant:(\w+)/g, '$1') +''); + }, + getSnapshot: function(data, callback) { + return JSON.toXML(data, callback || true); + }, + xmlFromString: function(str) { + var parser, + doc; + str = str.replace(/>\s{1,}<'); + if (str.trim().match(/<\?xml/) === null) { + str = this.xml_decl + str; + } + if ( 'ActiveXObject' in window ) { + doc = new ActiveXObject('Msxml2.DOMDocument'); + doc.loadXML(str); + doc.setProperty('SelectionNamespaces', this.namespace); + if (str.indexOf('xsl:stylesheet') === -1) { + doc.setProperty('SelectionLanguage', 'XPath'); + } + } else { + parser = new DOMParser(); + doc = parser.parseFromString(str, 'text/xml'); + } + return doc; + }, + extend: function(src, dest) { + for (var content in dest) { + if (!src[content] || typeof(dest[content]) !== 'object') { + src[content] = dest[content]; + } else { + this.extend(src[content], dest[content]); + } + } + return src; + }, + node: {} + }; + + // Export + window.Defiant = module.exports = Defiant; + +})( + typeof window !== 'undefined' ? window : {}, + typeof module !== 'undefined' ? module : {} +); + + +if (typeof(XSLTProcessor) === 'undefined') { + + // emulating XSLT Processor (enough to be used in defiant) + var XSLTProcessor = function() {}; + XSLTProcessor.prototype = { + importStylesheet: function(xsldoc) { + this.xsldoc = xsldoc; + }, + transformToFragment: function(data, doc) { + var str = data.transformNode(this.xsldoc), + span = document.createElement('span'); + span.innerHTML = str; + return span; + } + }; + +} else if (typeof(XSLTProcessor) !== 'function' && !XSLTProcessor) { + + // throw error + throw 'XSLTProcessor transformNode not implemented'; + +} + + +// extending STRING +if (!String.prototype.fill) { + String.prototype.fill = function(i,c) { + var str = this; + c = c || ' '; + for (; str.length/, + rx_constructor : /<(.+?)( d:contr=".*?")>/, + rx_namespace : / xmlns\:d="defiant\-namespace"/, + rx_data : /(<.+?>)(.*?)(<\/d:data>)/i, + rx_function : /function (\w+)/i, + namespace : 'xmlns:d="defiant-namespace"', + to_xml_str: function(tree) { + return { + str: this.hash_to_xml(null, tree), + map: this.map + }; + }, + hash_to_xml: function(name, tree, array_child) { + var is_array = tree.constructor === Array, + self = this, + elem = [], + attr = [], + key, + val, + val_is_array, + type, + is_attr, + cname, + constr, + cnName, + i, + il, + fn = function(key, tree) { + val = tree[key]; + if (val === null || val === undefined || val.toString() === 'NaN') val = null; + + is_attr = key.slice(0,1) === '@'; + cname = array_child ? name : key; + if (cname == +cname && tree.constructor !== Object) cname = 'd:item'; + if (val === null) { + constr = null; + cnName = false; + } else { + constr = val.constructor; + cnName = constr.toString().match(self.rx_function)[1]; + } + + if (is_attr) { + attr.push( cname.slice(1) +'="'+ self.escape_xml(val) +'"' ); + if (cnName !== 'String') attr.push( 'd:'+ cname.slice(1) +'="'+ cnName +'"' ); + } else if (val === null) { + elem.push( self.scalar_to_xml( cname, val ) ); + } else { + switch (constr) { + case Function: + // if constructor is function, then it's not a JSON structure + throw 'JSON data should not contain functions. Please check your structure.'; + /* falls through */ + case Object: + elem.push( self.hash_to_xml( cname, val ) ); + break; + case Array: + if (key === cname) { + val_is_array = val.constructor === Array; + if (val_is_array) { + i = val.length; + while (i--) { + if (val[i] === null || !val[i] || val[i].constructor === Array) val_is_array = true; + if (!val_is_array && val[i].constructor === Object) val_is_array = true; + } + } + elem.push( self.scalar_to_xml( cname, val, val_is_array ) ); + break; + } + /* falls through */ + case String: + if (typeof(val) === 'string') { + val = val.toString().replace(/\&/g, '&') + .replace(/\r|\n/g, ' '); + } + if (cname === '#text') { + // prepare map + self.map.push(tree); + attr.push('d:mi="'+ self.map.length +'"'); + attr.push('d:constr="'+ cnName +'"'); + elem.push( self.escape_xml(val) ); + break; + } + /* falls through */ + case Number: + case Boolean: + if (cname === '#text' && cnName !== 'String') { + // prepare map + self.map.push(tree); + attr.push('d:mi="'+ self.map.length +'"'); + attr.push('d:constr="'+ cnName +'"'); + elem.push( self.escape_xml(val) ); + break; + } + elem.push( self.scalar_to_xml( cname, val ) ); + break; + } + } + }; + if (tree.constructor === Array) { + i = 0; + il = tree.length; + for (; i'+ elem.join('') +'' : '/>' ); + }, + scalar_to_xml: function(name, val, override) { + var attr = '', + text, + constr, + cnName; + + // check whether the nodename is valid + if (name.match(this.rx_validate_name) === null) { + attr += ' d:name="'+ name +'"'; + name = 'd:name'; + override = false; + } + if (val === null || val.toString() === 'NaN') val = null; + if (val === null) return '<'+ name +' d:constr="null"/>'; + if (val.length === 1 && val.constructor === Array && !val[0]) { + return '<'+ name +' d:constr="null" d:type="ArrayItem"/>'; + } + if (val.length === 1 && val[0].constructor === Object) { + + text = this.hash_to_xml(false, val[0]); + + var a1 = text.match(this.rx_node), + a2 = text.match(this.rx_constructor); + a1 = (a1 !== null)? a1[2] + .replace(this.rx_namespace, '') + .replace(/>/, '') + .replace(/"\/$/, '"') : ''; + a2 = (a2 !== null)? a2[2] : ''; + + text = text.match(this.rx_data); + text = (text !== null)? text[2] : ''; + + return '<'+ name + a1 +' '+ a2 +' d:type="ArrayItem">'+ text +''; + } else if (val.length === 0 && val.constructor === Array) { + return '<'+ name +' d:constr="Array"/>'; + } + // else + if (override) { + return this.hash_to_xml( name, val, true ); + } + + constr = val.constructor; + cnName = constr.toString().match(this.rx_function)[1]; + text = (constr === Array) ? this.hash_to_xml( 'd:item', val, true ) + : this.escape_xml(val); + + attr += ' d:constr="'+ cnName +'"'; + // prepare map + this.map.push(val); + attr += ' d:mi="'+ this.map.length +'"'; + + return (name === '#text') ? this.escape_xml(val) : '<'+ name + attr +'>'+ text +''; + }, + escape_xml: function(text) { + return String(text) .replace(//g, '>') + .replace(/"/g, '"') + .replace(/ /g, ' '); + } + }, + processed, + doc, + task; + // depending on request + switch (typeof callback) { + case 'function': + // compile interpreter with 'x10.js' + task = x10.compile(interpreter); + + // parse in a dedicated thread + task.to_xml_str(tree, function(processed) { + // snapshot distinctly improves performance + callback({ + doc: Defiant.xmlFromString(processed.str), + src: tree, + map: processed.map + }); + }); + return; + case 'boolean': + processed = interpreter.to_xml_str.call(interpreter, tree); + // return snapshot + return { + doc: Defiant.xmlFromString(processed.str), + src: tree, + map: processed.map + }; + default: + processed = interpreter.to_xml_str.call(interpreter, tree); + doc = Defiant.xmlFromString(processed.str); + + this.search.map = processed.map; + return doc; + } + }; +} + + +if (!JSON.search) { + JSON.search = function(tree, xpath, single) { + 'use strict'; + + var isSnapshot = tree.doc && tree.doc.nodeType, + doc = isSnapshot ? tree.doc : JSON.toXML(tree), + map = isSnapshot ? tree.map : this.search.map, + src = isSnapshot ? tree.src : tree, + xres = Defiant.node[ single ? 'selectSingleNode' : 'selectNodes' ](doc, xpath.xTransform()), + ret = [], + mapIndex, + i; + + if (single) xres = [xres]; + i = xres.length; + + while (i--) { + switch(xres[i].nodeType) { + case 2: + case 3: + ret.unshift( xres[i].nodeValue ); + break; + default: + mapIndex = +xres[i].getAttribute('d:mi'); + //if (map[mapIndex-1] !== false) { + ret.unshift( map[mapIndex-1] ); + //} + } + } + + // if environment = development, add search tracing + if (Defiant.env === 'development') { + this.trace = JSON.mtrace(src, ret, xres); + } + + return ret; + }; +} + +if (!JSON.mtrace) { + JSON.mtrace = function(root, hits, xres) { + 'use strict'; + + var win = window, + stringify = JSON.stringify, + sroot = stringify( root, null, '\t' ).replace(/\t/g, ''), + trace = [], + i = 0, + il = xres.length, + od = il ? xres[i].ownerDocument.documentElement : false, + map = this.search.map, + hstr, + cConstr, + fIndex = 0, + mIndex, + lStart, + lEnd; + + for (; i 0)? xI[0] : null; + } else { + return XNode.selectSingleNode(XPath); + } +}; + + +Defiant.node.prettyPrint = function(node) { + var root = Defiant, + tabs = root.tabsize, + decl = root.xml_decl.toLowerCase(), + ser, + xstr; + if (root.is_ie) { + xstr = node.xml; + } else { + ser = new XMLSerializer(); + xstr = ser.serializeToString(node); + } + if (root.env !== 'development') { + // if environment is not development, remove defiant related info + xstr = xstr.replace(/ \w+\:d=".*?"| d\:\w+=".*?"/g, ''); + } + var str = xstr.trim().replace(/(>)\s*(<)(\/*)/g, '$1\n$2$3'), + lines = str.split('\n'), + indent = -1, + i = 0, + il = lines.length, + start, + end; + for (; i/g) !== null; + //start = lines[i].match(/<[^\/]+>/g) !== null; + end = lines[i].match(/<\/[\w\:]+>/g) !== null; + if (lines[i].match(/<.*?\/>/g) !== null) start = end = true; + if (start) indent++; + lines[i] = String().fill(indent, '\t') + lines[i]; + if (start && end) indent--; + if (!start && end) indent--; + } + return lines.join('\n').replace(/\t/g, String().fill(tabs, ' ')); +}; + + +Defiant.node.toJSON = function(xnode, stringify) { + 'use strict'; + + var interpret = function(leaf) { + var obj = {}, + win = window, + attr, + type, + item, + cname, + cConstr, + cval, + text, + i, il, a; + + switch (leaf.nodeType) { + case 1: + cConstr = leaf.getAttribute('d:constr'); + if (cConstr === 'Array') obj = []; + else if (cConstr === 'String' && leaf.textContent === '') obj = ''; + + attr = leaf.attributes; + i = 0; + il = attr.length; + for (; i + * Released under the MIT License. + * https://raw.github.com/taye/interact.js/master/LICENSE + */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.interact = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 6 && arguments[6] !== undefined ? arguments[6] : false; + + _classCallCheck(this, InteractEvent); + + var target = interaction.target; + var deltaSource = (target && target.options || defaults).deltaSource; + var origin = getOriginXY(target, element, action); + var starting = phase === 'start'; + var ending = phase === 'end'; + var coords = starting ? interaction.startCoords : interaction.curCoords; + var prevEvent = interaction.prevEvent; + + element = element || interaction.element; + + var page = extend({}, coords.page); + var client = extend({}, coords.client); + + page.x -= origin.x; + page.y -= origin.y; + + client.x -= origin.x; + client.y -= origin.y; + + this.ctrlKey = event.ctrlKey; + this.altKey = event.altKey; + this.shiftKey = event.shiftKey; + this.metaKey = event.metaKey; + this.button = event.button; + this.buttons = event.buttons; + this.target = element; + this.currentTarget = element; + this.relatedTarget = related || null; + this.preEnd = preEnd; + this.type = action + (phase || ''); + this.interaction = interaction; + this.interactable = target; + + this.t0 = starting ? interaction.downTimes[interaction.downTimes.length - 1] : prevEvent.t0; + + var signalArg = { + interaction: interaction, + event: event, + action: action, + phase: phase, + element: element, + related: related, + page: page, + client: client, + coords: coords, + starting: starting, + ending: ending, + deltaSource: deltaSource, + iEvent: this + }; + + signals.fire('set-xy', signalArg); + + if (ending) { + // use previous coords when ending + this.pageX = prevEvent.pageX; + this.pageY = prevEvent.pageY; + this.clientX = prevEvent.clientX; + this.clientY = prevEvent.clientY; + } else { + this.pageX = page.x; + this.pageY = page.y; + this.clientX = client.x; + this.clientY = client.y; + } + + this.x0 = interaction.startCoords.page.x - origin.x; + this.y0 = interaction.startCoords.page.y - origin.y; + this.clientX0 = interaction.startCoords.client.x - origin.x; + this.clientY0 = interaction.startCoords.client.y - origin.y; + + signals.fire('set-delta', signalArg); + + this.timeStamp = coords.timeStamp; + this.dt = interaction.pointerDelta.timeStamp; + this.duration = this.timeStamp - this.t0; + + // speed and velocity in pixels per second + this.speed = interaction.pointerDelta[deltaSource].speed; + this.velocityX = interaction.pointerDelta[deltaSource].vx; + this.velocityY = interaction.pointerDelta[deltaSource].vy; + + this.swipe = ending || phase === 'inertiastart' ? this.getSwipe() : null; + + signals.fire('new', signalArg); + } + + InteractEvent.prototype.getSwipe = function getSwipe() { + var interaction = this.interaction; + + if (interaction.prevEvent.speed < 600 || this.timeStamp - interaction.prevEvent.timeStamp > 150) { + return null; + } + + var angle = 180 * Math.atan2(interaction.prevEvent.velocityY, interaction.prevEvent.velocityX) / Math.PI; + var overlap = 22.5; + + if (angle < 0) { + angle += 360; + } + + var left = 135 - overlap <= angle && angle < 225 + overlap; + var up = 225 - overlap <= angle && angle < 315 + overlap; + + var right = !left && (315 - overlap <= angle || angle < 45 + overlap); + var down = !up && 45 - overlap <= angle && angle < 135 + overlap; + + return { + up: up, + down: down, + left: left, + right: right, + angle: angle, + speed: interaction.prevEvent.speed, + velocity: { + x: interaction.prevEvent.velocityX, + y: interaction.prevEvent.velocityY + } + }; + }; + + InteractEvent.prototype.preventDefault = function preventDefault() {}; + + /** */ + + + InteractEvent.prototype.stopImmediatePropagation = function stopImmediatePropagation() { + this.immediatePropagationStopped = this.propagationStopped = true; + }; + + /** */ + + + InteractEvent.prototype.stopPropagation = function stopPropagation() { + this.propagationStopped = true; + }; + + return InteractEvent; +}(); + +signals.on('set-delta', function (_ref) { + var iEvent = _ref.iEvent, + interaction = _ref.interaction, + starting = _ref.starting, + deltaSource = _ref.deltaSource; + + var prevEvent = starting ? iEvent : interaction.prevEvent; + + if (deltaSource === 'client') { + iEvent.dx = iEvent.clientX - prevEvent.clientX; + iEvent.dy = iEvent.clientY - prevEvent.clientY; + } else { + iEvent.dx = iEvent.pageX - prevEvent.pageX; + iEvent.dy = iEvent.pageY - prevEvent.pageY; + } +}); + +InteractEvent.signals = signals; + +module.exports = InteractEvent; + +},{"./defaultOptions":18,"./utils/Signals":34,"./utils/extend":41,"./utils/getOriginXY":42}],4:[function(require,module,exports){ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var clone = require('./utils/clone'); +var is = require('./utils/is'); +var events = require('./utils/events'); +var extend = require('./utils/extend'); +var actions = require('./actions/base'); +var scope = require('./scope'); +var Eventable = require('./Eventable'); +var defaults = require('./defaultOptions'); +var signals = require('./utils/Signals').new(); + +var _require = require('./utils/domUtils'), + getElementRect = _require.getElementRect, + nodeContains = _require.nodeContains, + trySelector = _require.trySelector, + matchesSelector = _require.matchesSelector; + +var _require2 = require('./utils/window'), + getWindow = _require2.getWindow; + +var _require3 = require('./utils/arr'), + contains = _require3.contains; + +var _require4 = require('./utils/browser'), + wheelEvent = _require4.wheelEvent; + +// all set interactables + + +scope.interactables = []; + +var Interactable = function () { + /** */ + function Interactable(target, options) { + _classCallCheck(this, Interactable); + + options = options || {}; + + this.target = target; + this.events = new Eventable(); + this._context = options.context || scope.document; + this._win = getWindow(trySelector(target) ? this._context : target); + this._doc = this._win.document; + + signals.fire('new', { + target: target, + options: options, + interactable: this, + win: this._win + }); + + scope.addDocument(this._doc, this._win); + + scope.interactables.push(this); + + this.set(options); + } + + Interactable.prototype.setOnEvents = function setOnEvents(action, phases) { + var onAction = 'on' + action; + + if (is.function(phases.onstart)) { + this.events[onAction + 'start'] = phases.onstart; + } + if (is.function(phases.onmove)) { + this.events[onAction + 'move'] = phases.onmove; + } + if (is.function(phases.onend)) { + this.events[onAction + 'end'] = phases.onend; + } + if (is.function(phases.oninertiastart)) { + this.events[onAction + 'inertiastart'] = phases.oninertiastart; + } + + return this; + }; + + Interactable.prototype.setPerAction = function setPerAction(action, options) { + // for all the default per-action options + for (var option in options) { + // if this option exists for this action + if (option in defaults[action]) { + // if the option in the options arg is an object value + if (is.object(options[option])) { + // duplicate the object and merge + this.options[action][option] = clone(this.options[action][option] || {}); + extend(this.options[action][option], options[option]); + + if (is.object(defaults.perAction[option]) && 'enabled' in defaults.perAction[option]) { + this.options[action][option].enabled = options[option].enabled === false ? false : true; + } + } else if (is.bool(options[option]) && is.object(defaults.perAction[option])) { + this.options[action][option].enabled = options[option]; + } else if (options[option] !== undefined) { + // or if it's not undefined, do a plain assignment + this.options[action][option] = options[option]; + } + } + } + }; + + /** + * The default function to get an Interactables bounding rect. Can be + * overridden using {@link Interactable.rectChecker}. + * + * @param {Element} [element] The element to measure. + * @return {object} The object's bounding rectangle. + */ + + + Interactable.prototype.getRect = function getRect(element) { + element = element || this.target; + + if (is.string(this.target) && !is.element(element)) { + element = this._context.querySelector(this.target); + } + + return getElementRect(element); + }; + + /** + * Returns or sets the function used to calculate the interactable's + * element's rectangle + * + * @param {function} [checker] A function which returns this Interactable's + * bounding rectangle. See {@link Interactable.getRect} + * @return {function | object} The checker function or this Interactable + */ + + + Interactable.prototype.rectChecker = function rectChecker(checker) { + if (is.function(checker)) { + this.getRect = checker; + + return this; + } + + if (checker === null) { + delete this.options.getRect; + + return this; + } + + return this.getRect; + }; + + Interactable.prototype._backCompatOption = function _backCompatOption(optionName, newValue) { + if (trySelector(newValue) || is.object(newValue)) { + this.options[optionName] = newValue; + + for (var _i = 0; _i < actions.names.length; _i++) { + var _ref; + + _ref = actions.names[_i]; + var action = _ref; + + this.options[action][optionName] = newValue; + } + + return this; + } + + return this.options[optionName]; + }; + + /** + * Gets or sets the origin of the Interactable's element. The x and y + * of the origin will be subtracted from action event coordinates. + * + * @param {Element | object | string} [origin] An HTML or SVG Element whose + * rect will be used, an object eg. { x: 0, y: 0 } or string 'parent', 'self' + * or any CSS selector + * + * @return {object} The current origin or this Interactable + */ + + + Interactable.prototype.origin = function origin(newValue) { + return this._backCompatOption('origin', newValue); + }; + + /** + * Returns or sets the mouse coordinate types used to calculate the + * movement of the pointer. + * + * @param {string} [newValue] Use 'client' if you will be scrolling while + * interacting; Use 'page' if you want autoScroll to work + * @return {string | object} The current deltaSource or this Interactable + */ + + + Interactable.prototype.deltaSource = function deltaSource(newValue) { + if (newValue === 'page' || newValue === 'client') { + this.options.deltaSource = newValue; + + return this; + } + + return this.options.deltaSource; + }; + + /** + * Gets the selector context Node of the Interactable. The default is + * `window.document`. + * + * @return {Node} The context Node of this Interactable + */ + + + Interactable.prototype.context = function context() { + return this._context; + }; + + Interactable.prototype.inContext = function inContext(element) { + return this._context === element.ownerDocument || nodeContains(this._context, element); + }; + + /** + * Calls listeners for the given InteractEvent type bound globally + * and directly to this Interactable + * + * @param {InteractEvent} iEvent The InteractEvent object to be fired on this + * Interactable + * @return {Interactable} this Interactable + */ + + + Interactable.prototype.fire = function fire(iEvent) { + this.events.fire(iEvent); + + return this; + }; + + Interactable.prototype._onOffMultiple = function _onOffMultiple(method, eventType, listener, options) { + if (is.string(eventType) && eventType.search(' ') !== -1) { + eventType = eventType.trim().split(/ +/); + } + + if (is.array(eventType)) { + for (var _i2 = 0; _i2 < eventType.length; _i2++) { + var _ref2; + + _ref2 = eventType[_i2]; + var type = _ref2; + + this[method](type, listener, options); + } + + return true; + } + + if (is.object(eventType)) { + for (var prop in eventType) { + this[method](prop, eventType[prop], listener); + } + + return true; + } + }; + + /** + * Binds a listener for an InteractEvent, pointerEvent or DOM event. + * + * @param {string | array | object} eventType The types of events to listen + * for + * @param {function} listener The function event (s) + * @param {object | boolean} [options] options object or useCapture flag + * for addEventListener + * @return {object} This Interactable + */ + + + Interactable.prototype.on = function on(eventType, listener, options) { + if (this._onOffMultiple('on', eventType, listener, options)) { + return this; + } + + if (eventType === 'wheel') { + eventType = wheelEvent; + } + + if (contains(Interactable.eventTypes, eventType)) { + this.events.on(eventType, listener); + } + // delegated event for selector + else if (is.string(this.target)) { + events.addDelegate(this.target, this._context, eventType, listener, options); + } else { + events.add(this.target, eventType, listener, options); + } + + return this; + }; + + /** + * Removes an InteractEvent, pointerEvent or DOM event listener + * + * @param {string | array | object} eventType The types of events that were + * listened for + * @param {function} listener The listener function to be removed + * @param {object | boolean} [options] options object or useCapture flag for + * removeEventListener + * @return {object} This Interactable + */ + + + Interactable.prototype.off = function off(eventType, listener, options) { + if (this._onOffMultiple('off', eventType, listener, options)) { + return this; + } + + if (eventType === 'wheel') { + eventType = wheelEvent; + } + + // if it is an action event type + if (contains(Interactable.eventTypes, eventType)) { + this.events.off(eventType, listener); + } + // delegated event + else if (is.string(this.target)) { + events.removeDelegate(this.target, this._context, eventType, listener, options); + } + // remove listener from this Interatable's element + else { + events.remove(this.target, eventType, listener, options); + } + + return this; + }; + + /** + * Reset the options of this Interactable + * + * @param {object} options The new settings to apply + * @return {object} This Interactable + */ + + + Interactable.prototype.set = function set(options) { + if (!is.object(options)) { + options = {}; + } + + this.options = clone(defaults.base); + + var perActions = clone(defaults.perAction); + + for (var actionName in actions.methodDict) { + var methodName = actions.methodDict[actionName]; + + this.options[actionName] = clone(defaults[actionName]); + + this.setPerAction(actionName, perActions); + + this[methodName](options[actionName]); + } + + for (var _i3 = 0; _i3 < Interactable.settingsMethods.length; _i3++) { + var _ref3; + + _ref3 = Interactable.settingsMethods[_i3]; + var setting = _ref3; + + this.options[setting] = defaults.base[setting]; + + if (setting in options) { + this[setting](options[setting]); + } + } + + signals.fire('set', { + options: options, + interactable: this + }); + + return this; + }; + + /** + * Remove this interactable from the list of interactables and remove it's + * action capabilities and event listeners + * + * @return {interact} + */ + + + Interactable.prototype.unset = function unset() { + events.remove(this.target, 'all'); + + if (is.string(this.target)) { + // remove delegated events + for (var type in events.delegatedEvents) { + var delegated = events.delegatedEvents[type]; + + if (delegated.selectors[0] === this.target && delegated.contexts[0] === this._context) { + + delegated.selectors.splice(0, 1); + delegated.contexts.splice(0, 1); + delegated.listeners.splice(0, 1); + + // remove the arrays if they are empty + if (!delegated.selectors.length) { + delegated[type] = null; + } + } + + events.remove(this._context, type, events.delegateListener); + events.remove(this._context, type, events.delegateUseCapture, true); + } + } else { + events.remove(this, 'all'); + } + + signals.fire('unset', { interactable: this }); + + scope.interactables.splice(scope.interactables.indexOf(this), 1); + + // Stop related interactions when an Interactable is unset + for (var _i4 = 0; _i4 < (scope.interactions || []).length; _i4++) { + var _ref4; + + _ref4 = (scope.interactions || [])[_i4]; + var interaction = _ref4; + + if (interaction.target === this && interaction.interacting() && !interaction._ending) { + interaction.stop(); + } + } + + return scope.interact; + }; + + return Interactable; +}(); + +scope.interactables.indexOfElement = function indexOfElement(target, context) { + context = context || scope.document; + + for (var i = 0; i < this.length; i++) { + var interactable = this[i]; + + if (interactable.target === target && interactable._context === context) { + return i; + } + } + return -1; +}; + +scope.interactables.get = function interactableGet(element, options, dontCheckInContext) { + var ret = this[this.indexOfElement(element, options && options.context)]; + + return ret && (is.string(element) || dontCheckInContext || ret.inContext(element)) ? ret : null; +}; + +scope.interactables.forEachMatch = function (element, callback) { + for (var _i5 = 0; _i5 < this.length; _i5++) { + var _ref5; + + _ref5 = this[_i5]; + var interactable = _ref5; + + var ret = void 0; + + if ((is.string(interactable.target) + // target is a selector and the element matches + ? is.element(element) && matchesSelector(element, interactable.target) : + // target is the element + element === interactable.target) && + // the element is in context + interactable.inContext(element)) { + ret = callback(interactable); + } + + if (ret !== undefined) { + return ret; + } + } +}; + +// all interact.js eventTypes +Interactable.eventTypes = scope.eventTypes = []; + +Interactable.signals = signals; + +Interactable.settingsMethods = ['deltaSource', 'origin', 'preventDefault', 'rectChecker']; + +module.exports = Interactable; + +},{"./Eventable":2,"./actions/base":6,"./defaultOptions":18,"./scope":33,"./utils/Signals":34,"./utils/arr":35,"./utils/browser":36,"./utils/clone":37,"./utils/domUtils":39,"./utils/events":40,"./utils/extend":41,"./utils/is":46,"./utils/window":52}],5:[function(require,module,exports){ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var scope = require('./scope'); +var utils = require('./utils'); +var events = require('./utils/events'); +var browser = require('./utils/browser'); +var domObjects = require('./utils/domObjects'); +var finder = require('./utils/interactionFinder'); +var signals = require('./utils/Signals').new(); + +var listeners = {}; +var methodNames = ['pointerDown', 'pointerMove', 'pointerUp', 'updatePointer', 'removePointer']; + +// for ignoring browser's simulated mouse events +var prevTouchTime = 0; + +// all active and idle interactions +scope.interactions = []; + +var Interaction = function () { + /** */ + function Interaction(_ref) { + var pointerType = _ref.pointerType; + + _classCallCheck(this, Interaction); + + this.target = null; // current interactable being interacted with + this.element = null; // the target element of the interactable + + this.prepared = { // action that's ready to be fired on next move event + name: null, + axis: null, + edges: null + }; + + // keep track of added pointers + this.pointers = []; + this.pointerIds = []; + this.downTargets = []; + this.downTimes = []; + + // Previous native pointer move event coordinates + this.prevCoords = { + page: { x: 0, y: 0 }, + client: { x: 0, y: 0 }, + timeStamp: 0 + }; + // current native pointer move event coordinates + this.curCoords = { + page: { x: 0, y: 0 }, + client: { x: 0, y: 0 }, + timeStamp: 0 + }; + + // Starting InteractEvent pointer coordinates + this.startCoords = { + page: { x: 0, y: 0 }, + client: { x: 0, y: 0 }, + timeStamp: 0 + }; + + // Change in coordinates and time of the pointer + this.pointerDelta = { + page: { x: 0, y: 0, vx: 0, vy: 0, speed: 0 }, + client: { x: 0, y: 0, vx: 0, vy: 0, speed: 0 }, + timeStamp: 0 + }; + + this.downEvent = null; // pointerdown/mousedown/touchstart event + this.downPointer = {}; + + this._eventTarget = null; + this._curEventTarget = null; + + this.prevEvent = null; // previous action event + + this.pointerIsDown = false; + this.pointerWasMoved = false; + this._interacting = false; + this._ending = false; + + this.pointerType = pointerType; + + signals.fire('new', this); + + scope.interactions.push(this); + } + + Interaction.prototype.pointerDown = function pointerDown(pointer, event, eventTarget) { + var pointerIndex = this.updatePointer(pointer, event, true); + + signals.fire('down', { + pointer: pointer, + event: event, + eventTarget: eventTarget, + pointerIndex: pointerIndex, + interaction: this + }); + }; + + /** + * ```js + * interact(target) + * .draggable({ + * // disable the default drag start by down->move + * manualStart: true + * }) + * // start dragging after the user holds the pointer down + * .on('hold', function (event) { + * var interaction = event.interaction; + * + * if (!interaction.interacting()) { + * interaction.start({ name: 'drag' }, + * event.interactable, + * event.currentTarget); + * } + * }); + * ``` + * + * Start an action with the given Interactable and Element as tartgets. The + * action must be enabled for the target Interactable and an appropriate + * number of pointers must be held down - 1 for drag/resize, 2 for gesture. + * + * Use it with `interactable.able({ manualStart: false })` to always + * [start actions manually](https://github.com/taye/interact.js/issues/114) + * + * @param {object} action The action to be performed - drag, resize, etc. + * @param {Interactable} target The Interactable to target + * @param {Element} element The DOM Element to target + * @return {object} interact + */ + + + Interaction.prototype.start = function start(action, target, element) { + if (this.interacting() || !this.pointerIsDown || this.pointerIds.length < (action.name === 'gesture' ? 2 : 1)) { + return; + } + + // if this interaction had been removed after stopping + // add it back + if (scope.interactions.indexOf(this) === -1) { + scope.interactions.push(this); + } + + utils.copyAction(this.prepared, action); + this.target = target; + this.element = element; + + signals.fire('action-start', { + interaction: this, + event: this.downEvent + }); + }; + + Interaction.prototype.pointerMove = function pointerMove(pointer, event, eventTarget) { + if (!this.simulation) { + this.updatePointer(pointer); + utils.setCoords(this.curCoords, this.pointers); + } + + var duplicateMove = this.curCoords.page.x === this.prevCoords.page.x && this.curCoords.page.y === this.prevCoords.page.y && this.curCoords.client.x === this.prevCoords.client.x && this.curCoords.client.y === this.prevCoords.client.y; + + var dx = void 0; + var dy = void 0; + + // register movement greater than pointerMoveTolerance + if (this.pointerIsDown && !this.pointerWasMoved) { + dx = this.curCoords.client.x - this.startCoords.client.x; + dy = this.curCoords.client.y - this.startCoords.client.y; + + this.pointerWasMoved = utils.hypot(dx, dy) > Interaction.pointerMoveTolerance; + } + + var signalArg = { + pointer: pointer, + pointerIndex: this.getPointerIndex(pointer), + event: event, + eventTarget: eventTarget, + dx: dx, + dy: dy, + duplicate: duplicateMove, + interaction: this, + interactingBeforeMove: this.interacting() + }; + + if (!duplicateMove) { + // set pointer coordinate, time changes and speeds + utils.setCoordDeltas(this.pointerDelta, this.prevCoords, this.curCoords); + } + + signals.fire('move', signalArg); + + if (!duplicateMove) { + // if interacting, fire an 'action-move' signal etc + if (this.interacting()) { + this.doMove(signalArg); + } + + if (this.pointerWasMoved) { + utils.copyCoords(this.prevCoords, this.curCoords); + } + } + }; + + /** + * ```js + * interact(target) + * .draggable(true) + * .on('dragmove', function (event) { + * if (someCondition) { + * // change the snap settings + * event.interactable.draggable({ snap: { targets: [] }}); + * // fire another move event with re-calculated snap + * event.interaction.doMove(); + * } + * }); + * ``` + * + * Force a move of the current action at the same coordinates. Useful if + * snap/restrict has been changed and you want a movement with the new + * settings. + */ + + + Interaction.prototype.doMove = function doMove(signalArg) { + signalArg = utils.extend({ + pointer: this.pointers[0], + event: this.prevEvent, + eventTarget: this._eventTarget, + interaction: this + }, signalArg || {}); + + signals.fire('before-action-move', signalArg); + + if (!this._dontFireMove) { + signals.fire('action-move', signalArg); + } + + this._dontFireMove = false; + }; + + // End interact move events and stop auto-scroll unless simulation is running + + + Interaction.prototype.pointerUp = function pointerUp(pointer, event, eventTarget, curEventTarget) { + var pointerIndex = this.getPointerIndex(pointer); + + signals.fire(/cancel$/i.test(event.type) ? 'cancel' : 'up', { + pointer: pointer, + pointerIndex: pointerIndex, + event: event, + eventTarget: eventTarget, + curEventTarget: curEventTarget, + interaction: this + }); + + if (!this.simulation) { + this.end(event); + } + + this.pointerIsDown = false; + this.removePointer(pointer, event); + }; + + /** + * ```js + * interact(target) + * .draggable(true) + * .on('move', function (event) { + * if (event.pageX > 1000) { + * // end the current action + * event.interaction.end(); + * // stop all further listeners from being called + * event.stopImmediatePropagation(); + * } + * }); + * ``` + * + * Stop the current action and fire an end event. Inertial movement does + * not happen. + * + * @param {PointerEvent} [event] + */ + + + Interaction.prototype.end = function end(event) { + this._ending = true; + + event = event || this.prevEvent; + + if (this.interacting()) { + signals.fire('action-end', { + event: event, + interaction: this + }); + } + + this.stop(); + this._ending = false; + }; + + Interaction.prototype.currentAction = function currentAction() { + return this._interacting ? this.prepared.name : null; + }; + + Interaction.prototype.interacting = function interacting() { + return this._interacting; + }; + + /** */ + + + Interaction.prototype.stop = function stop() { + signals.fire('stop', { interaction: this }); + + if (this._interacting) { + signals.fire('stop-active', { interaction: this }); + signals.fire('stop-' + this.prepared.name, { interaction: this }); + } + + this.target = this.element = null; + + this._interacting = false; + this.prepared.name = this.prevEvent = null; + }; + + Interaction.prototype.getPointerIndex = function getPointerIndex(pointer) { + // mouse and pen interactions may have only one pointer + if (this.pointerType === 'mouse' || this.pointerType === 'pen') { + return 0; + } + + return this.pointerIds.indexOf(utils.getPointerId(pointer)); + }; + + Interaction.prototype.updatePointer = function updatePointer(pointer, event) { + var down = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : event && /(down|start)$/i.test(event.type); + + var id = utils.getPointerId(pointer); + var index = this.getPointerIndex(pointer); + + if (index === -1) { + index = this.pointerIds.length; + this.pointerIds[index] = id; + } + + if (down) { + signals.fire('update-pointer-down', { + pointer: pointer, + event: event, + down: down, + pointerId: id, + pointerIndex: index, + interaction: this + }); + } + + this.pointers[index] = pointer; + + return index; + }; + + Interaction.prototype.removePointer = function removePointer(pointer, event) { + var index = this.getPointerIndex(pointer); + + if (index === -1) { + return; + } + + signals.fire('remove-pointer', { + pointer: pointer, + event: event, + pointerIndex: index, + interaction: this + }); + + this.pointers.splice(index, 1); + this.pointerIds.splice(index, 1); + this.downTargets.splice(index, 1); + this.downTimes.splice(index, 1); + }; + + Interaction.prototype._updateEventTargets = function _updateEventTargets(target, currentTarget) { + this._eventTarget = target; + this._curEventTarget = currentTarget; + }; + + return Interaction; +}(); + +for (var _i = 0; _i < methodNames.length; _i++) { + var method = methodNames[_i]; + listeners[method] = doOnInteractions(method); +} + +function doOnInteractions(method) { + return function (event) { + var pointerType = utils.getPointerType(event); + + var _utils$getEventTarget = utils.getEventTargets(event), + eventTarget = _utils$getEventTarget[0], + curEventTarget = _utils$getEventTarget[1]; + + var matches = []; // [ [pointer, interaction], ...] + + if (browser.supportsTouch && /touch/.test(event.type)) { + prevTouchTime = new Date().getTime(); + + for (var _i2 = 0; _i2 < event.changedTouches.length; _i2++) { + var _ref2; + + _ref2 = event.changedTouches[_i2]; + var changedTouch = _ref2; + + var pointer = changedTouch; + var interaction = finder.search(pointer, event.type, eventTarget); + + matches.push([pointer, interaction || new Interaction({ pointerType: pointerType })]); + } + } else { + var invalidPointer = false; + + if (!browser.supportsPointerEvent && /mouse/.test(event.type)) { + // ignore mouse events while touch interactions are active + for (var i = 0; i < scope.interactions.length && !invalidPointer; i++) { + invalidPointer = scope.interactions[i].pointerType !== 'mouse' && scope.interactions[i].pointerIsDown; + } + + // try to ignore mouse events that are simulated by the browser + // after a touch event + invalidPointer = invalidPointer || new Date().getTime() - prevTouchTime < 500 + // on iOS and Firefox Mobile, MouseEvent.timeStamp is zero if simulated + || event.timeStamp === 0; + } + + if (!invalidPointer) { + var _interaction = finder.search(event, event.type, eventTarget); + + if (!_interaction) { + _interaction = new Interaction({ pointerType: pointerType }); + } + + matches.push([event, _interaction]); + } + } + + for (var _i3 = 0; _i3 < matches.length; _i3++) { + var _ref3 = matches[_i3]; + var _pointer = _ref3[0]; + var _interaction2 = _ref3[1]; + + _interaction2._updateEventTargets(eventTarget, curEventTarget); + _interaction2[method](_pointer, event, eventTarget, curEventTarget); + } + }; +} + +function endAll(event) { + for (var _i4 = 0; _i4 < scope.interactions.length; _i4++) { + var _ref4; + + _ref4 = scope.interactions[_i4]; + var interaction = _ref4; + + interaction.end(event); + signals.fire('endall', { event: event, interaction: interaction }); + } +} + +var docEvents = {/* 'eventType': listenerFunc */}; +var pEventTypes = browser.pEventTypes; + +if (domObjects.PointerEvent) { + docEvents[pEventTypes.down] = listeners.pointerDown; + docEvents[pEventTypes.move] = listeners.pointerMove; + docEvents[pEventTypes.up] = listeners.pointerUp; + docEvents[pEventTypes.cancel] = listeners.pointerUp; +} else { + docEvents.mousedown = listeners.pointerDown; + docEvents.mousemove = listeners.pointerMove; + docEvents.mouseup = listeners.pointerUp; + + docEvents.touchstart = listeners.pointerDown; + docEvents.touchmove = listeners.pointerMove; + docEvents.touchend = listeners.pointerUp; + docEvents.touchcancel = listeners.pointerUp; +} + +docEvents.blur = endAll; + +function onDocSignal(_ref5, signalName) { + var doc = _ref5.doc; + + var eventMethod = signalName.indexOf('add') === 0 ? events.add : events.remove; + + // delegate event listener + for (var eventType in scope.delegatedEvents) { + eventMethod(doc, eventType, events.delegateListener); + eventMethod(doc, eventType, events.delegateUseCapture, true); + } + + for (var _eventType in docEvents) { + eventMethod(doc, _eventType, docEvents[_eventType]); + } +} + +signals.on('update-pointer-down', function (_ref6) { + var interaction = _ref6.interaction, + pointer = _ref6.pointer, + pointerId = _ref6.pointerId, + pointerIndex = _ref6.pointerIndex, + event = _ref6.event, + eventTarget = _ref6.eventTarget, + down = _ref6.down; + + interaction.pointerIds[pointerIndex] = pointerId; + interaction.pointers[pointerIndex] = pointer; + + if (down) { + interaction.pointerIsDown = true; + } + + if (!interaction.interacting()) { + utils.setCoords(interaction.startCoords, interaction.pointers); + + utils.copyCoords(interaction.curCoords, interaction.startCoords); + utils.copyCoords(interaction.prevCoords, interaction.startCoords); + + interaction.downEvent = event; + interaction.downTimes[pointerIndex] = interaction.curCoords.timeStamp; + interaction.downTargets[pointerIndex] = eventTarget || event && utils.getEventTargets(event)[0]; + interaction.pointerWasMoved = false; + + utils.pointerExtend(interaction.downPointer, pointer); + } +}); + +scope.signals.on('add-document', onDocSignal); +scope.signals.on('remove-document', onDocSignal); + +Interaction.pointerMoveTolerance = 1; +Interaction.doOnInteractions = doOnInteractions; +Interaction.endAll = endAll; +Interaction.signals = signals; +Interaction.docEvents = docEvents; + +scope.endAllInteractions = endAll; + +module.exports = Interaction; + +},{"./scope":33,"./utils":44,"./utils/Signals":34,"./utils/browser":36,"./utils/domObjects":38,"./utils/events":40,"./utils/interactionFinder":45}],6:[function(require,module,exports){ +'use strict'; + +var Interaction = require('../Interaction'); +var InteractEvent = require('../InteractEvent'); + +var actions = { + firePrepared: firePrepared, + names: [], + methodDict: {} +}; + +Interaction.signals.on('action-start', function (_ref) { + var interaction = _ref.interaction, + event = _ref.event; + + interaction._interacting = true; + firePrepared(interaction, event, 'start'); +}); + +Interaction.signals.on('action-move', function (_ref2) { + var interaction = _ref2.interaction, + event = _ref2.event, + preEnd = _ref2.preEnd; + + firePrepared(interaction, event, 'move', preEnd); + + // if the action was ended in a listener + if (!interaction.interacting()) { + return false; + } +}); + +Interaction.signals.on('action-end', function (_ref3) { + var interaction = _ref3.interaction, + event = _ref3.event; + + firePrepared(interaction, event, 'end'); +}); + +function firePrepared(interaction, event, phase, preEnd) { + var actionName = interaction.prepared.name; + + var newEvent = new InteractEvent(interaction, event, actionName, phase, interaction.element, null, preEnd); + + interaction.target.fire(newEvent); + interaction.prevEvent = newEvent; +} + +module.exports = actions; + +},{"../InteractEvent":3,"../Interaction":5}],7:[function(require,module,exports){ +'use strict'; + +var actions = require('./base'); +var utils = require('../utils'); +var InteractEvent = require('../InteractEvent'); +/** @lends Interactable */ +var Interactable = require('../Interactable'); +var Interaction = require('../Interaction'); +var defaultOptions = require('../defaultOptions'); + +var drag = { + defaults: { + enabled: false, + mouseButtons: null, + + origin: null, + snap: null, + restrict: null, + inertia: null, + autoScroll: null, + + startAxis: 'xy', + lockAxis: 'xy' + }, + + checker: function checker(pointer, event, interactable) { + var dragOptions = interactable.options.drag; + + return dragOptions.enabled ? { name: 'drag', axis: dragOptions.lockAxis === 'start' ? dragOptions.startAxis : dragOptions.lockAxis } : null; + }, + + getCursor: function getCursor() { + return 'move'; + } +}; + +Interaction.signals.on('before-action-move', function (_ref) { + var interaction = _ref.interaction; + + if (interaction.prepared.name !== 'drag') { + return; + } + + var axis = interaction.prepared.axis; + + if (axis === 'x') { + interaction.curCoords.page.y = interaction.startCoords.page.y; + interaction.curCoords.client.y = interaction.startCoords.client.y; + + interaction.pointerDelta.page.speed = Math.abs(interaction.pointerDelta.page.vx); + interaction.pointerDelta.client.speed = Math.abs(interaction.pointerDelta.client.vx); + interaction.pointerDelta.client.vy = 0; + interaction.pointerDelta.page.vy = 0; + } else if (axis === 'y') { + interaction.curCoords.page.x = interaction.startCoords.page.x; + interaction.curCoords.client.x = interaction.startCoords.client.x; + + interaction.pointerDelta.page.speed = Math.abs(interaction.pointerDelta.page.vy); + interaction.pointerDelta.client.speed = Math.abs(interaction.pointerDelta.client.vy); + interaction.pointerDelta.client.vx = 0; + interaction.pointerDelta.page.vx = 0; + } +}); + +// dragmove +InteractEvent.signals.on('new', function (_ref2) { + var iEvent = _ref2.iEvent, + interaction = _ref2.interaction; + + if (iEvent.type !== 'dragmove') { + return; + } + + var axis = interaction.prepared.axis; + + if (axis === 'x') { + iEvent.pageY = interaction.startCoords.page.y; + iEvent.clientY = interaction.startCoords.client.y; + iEvent.dy = 0; + } else if (axis === 'y') { + iEvent.pageX = interaction.startCoords.page.x; + iEvent.clientX = interaction.startCoords.client.x; + iEvent.dx = 0; + } +}); + +/** + * ```js + * interact(element).draggable({ + * onstart: function (event) {}, + * onmove : function (event) {}, + * onend : function (event) {}, + * + * // the axis in which the first movement must be + * // for the drag sequence to start + * // 'xy' by default - any direction + * startAxis: 'x' || 'y' || 'xy', + * + * // 'xy' by default - don't restrict to one axis (move in any direction) + * // 'x' or 'y' to restrict movement to either axis + * // 'start' to restrict movement to the axis the drag started in + * lockAxis: 'x' || 'y' || 'xy' || 'start', + * + * // max number of drags that can happen concurrently + * // with elements of this Interactable. Infinity by default + * max: Infinity, + * + * // max number of drags that can target the same element+Interactable + * // 1 by default + * maxPerElement: 2 + * }); + * + * var isDraggable = interact('element').draggable(); // true + * ``` + * + * Get or set whether drag actions can be performed on the target + * + * @param {boolean | object} [options] true/false or An object with event + * listeners to be fired on drag events (object makes the Interactable + * draggable) + * @return {boolean | Interactable} boolean indicating if this can be the + * target of drag events, or this Interctable + */ +Interactable.prototype.draggable = function (options) { + if (utils.is.object(options)) { + this.options.drag.enabled = options.enabled === false ? false : true; + this.setPerAction('drag', options); + this.setOnEvents('drag', options); + + if (/^(xy|x|y|start)$/.test(options.lockAxis)) { + this.options.drag.lockAxis = options.lockAxis; + } + if (/^(xy|x|y)$/.test(options.startAxis)) { + this.options.drag.startAxis = options.startAxis; + } + + return this; + } + + if (utils.is.bool(options)) { + this.options.drag.enabled = options; + + if (!options) { + this.ondragstart = this.ondragstart = this.ondragend = null; + } + + return this; + } + + return this.options.drag; +}; + +actions.drag = drag; +actions.names.push('drag'); +utils.merge(Interactable.eventTypes, ['dragstart', 'dragmove', 'draginertiastart', 'draginertiaresume', 'dragend']); +actions.methodDict.drag = 'draggable'; + +defaultOptions.drag = drag.defaults; + +module.exports = drag; + +},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../utils":44,"./base":6}],8:[function(require,module,exports){ +'use strict'; + +var actions = require('./base'); +var utils = require('../utils'); +var scope = require('../scope'); +/** @lends module:interact */ +var interact = require('../interact'); +var InteractEvent = require('../InteractEvent'); +/** @lends Interactable */ +var Interactable = require('../Interactable'); +var Interaction = require('../Interaction'); +var defaultOptions = require('../defaultOptions'); + +var drop = { + defaults: { + enabled: false, + accept: null, + overlap: 'pointer' + } +}; + +var dynamicDrop = false; + +Interaction.signals.on('action-start', function (_ref) { + var interaction = _ref.interaction, + event = _ref.event; + + if (interaction.prepared.name !== 'drag') { + return; + } + + // reset active dropzones + interaction.activeDrops.dropzones = []; + interaction.activeDrops.elements = []; + interaction.activeDrops.rects = []; + + interaction.dropEvents = null; + + if (!interaction.dynamicDrop) { + setActiveDrops(interaction.activeDrops, interaction.element); + } + + var dragEvent = interaction.prevEvent; + var dropEvents = getDropEvents(interaction, event, dragEvent); + + if (dropEvents.activate) { + fireActiveDrops(interaction.activeDrops, dropEvents.activate); + } +}); + +InteractEvent.signals.on('new', function (_ref2) { + var interaction = _ref2.interaction, + iEvent = _ref2.iEvent, + event = _ref2.event; + + if (iEvent.type !== 'dragmove' && iEvent.type !== 'dragend') { + return; + } + + var draggableElement = interaction.element; + var dragEvent = iEvent; + var dropResult = getDrop(dragEvent, event, draggableElement); + + interaction.dropTarget = dropResult.dropzone; + interaction.dropElement = dropResult.element; + + interaction.dropEvents = getDropEvents(interaction, event, dragEvent); +}); + +Interaction.signals.on('action-move', function (_ref3) { + var interaction = _ref3.interaction; + + if (interaction.prepared.name !== 'drag') { + return; + } + + fireDropEvents(interaction, interaction.dropEvents); +}); + +Interaction.signals.on('action-end', function (_ref4) { + var interaction = _ref4.interaction; + + if (interaction.prepared.name === 'drag') { + fireDropEvents(interaction, interaction.dropEvents); + } +}); + +Interaction.signals.on('stop-drag', function (_ref5) { + var interaction = _ref5.interaction; + + interaction.activeDrops = { + dropzones: null, + elements: null, + rects: null + }; + + interaction.dropEvents = null; +}); + +function collectDrops(activeDrops, element) { + var drops = []; + var elements = []; + + // collect all dropzones and their elements which qualify for a drop + for (var _i = 0; _i < scope.interactables.length; _i++) { + var _ref6; + + _ref6 = scope.interactables[_i]; + var current = _ref6; + + if (!current.options.drop.enabled) { + continue; + } + + var accept = current.options.drop.accept; + + // test the draggable element against the dropzone's accept setting + if (utils.is.element(accept) && accept !== element || utils.is.string(accept) && !utils.matchesSelector(element, accept)) { + + continue; + } + + // query for new elements if necessary + var dropElements = utils.is.string(current.target) ? current._context.querySelectorAll(current.target) : [current.target]; + + for (var _i2 = 0; _i2 < dropElements.length; _i2++) { + var _ref7; + + _ref7 = dropElements[_i2]; + var currentElement = _ref7; + + if (currentElement !== element) { + drops.push(current); + elements.push(currentElement); + } + } + } + + return { + elements: elements, + dropzones: drops + }; +} + +function fireActiveDrops(activeDrops, event) { + var prevElement = void 0; + + // loop through all active dropzones and trigger event + for (var i = 0; i < activeDrops.dropzones.length; i++) { + var current = activeDrops.dropzones[i]; + var currentElement = activeDrops.elements[i]; + + // prevent trigger of duplicate events on same element + if (currentElement !== prevElement) { + // set current element as event target + event.target = currentElement; + current.fire(event); + } + prevElement = currentElement; + } +} + +// Collect a new set of possible drops and save them in activeDrops. +// setActiveDrops should always be called when a drag has just started or a +// drag event happens while dynamicDrop is true +function setActiveDrops(activeDrops, dragElement) { + // get dropzones and their elements that could receive the draggable + var possibleDrops = collectDrops(activeDrops, dragElement); + + activeDrops.dropzones = possibleDrops.dropzones; + activeDrops.elements = possibleDrops.elements; + activeDrops.rects = []; + + for (var i = 0; i < activeDrops.dropzones.length; i++) { + activeDrops.rects[i] = activeDrops.dropzones[i].getRect(activeDrops.elements[i]); + } +} + +function getDrop(dragEvent, event, dragElement) { + var interaction = dragEvent.interaction; + var validDrops = []; + + if (dynamicDrop) { + setActiveDrops(interaction.activeDrops, dragElement); + } + + // collect all dropzones and their elements which qualify for a drop + for (var j = 0; j < interaction.activeDrops.dropzones.length; j++) { + var current = interaction.activeDrops.dropzones[j]; + var currentElement = interaction.activeDrops.elements[j]; + var rect = interaction.activeDrops.rects[j]; + + validDrops.push(current.dropCheck(dragEvent, event, interaction.target, dragElement, currentElement, rect) ? currentElement : null); + } + + // get the most appropriate dropzone based on DOM depth and order + var dropIndex = utils.indexOfDeepestElement(validDrops); + + return { + dropzone: interaction.activeDrops.dropzones[dropIndex] || null, + element: interaction.activeDrops.elements[dropIndex] || null + }; +} + +function getDropEvents(interaction, pointerEvent, dragEvent) { + var dropEvents = { + enter: null, + leave: null, + activate: null, + deactivate: null, + move: null, + drop: null + }; + + var tmpl = { + dragEvent: dragEvent, + interaction: interaction, + target: interaction.dropElement, + dropzone: interaction.dropTarget, + relatedTarget: dragEvent.target, + draggable: dragEvent.interactable, + timeStamp: dragEvent.timeStamp + }; + + if (interaction.dropElement !== interaction.prevDropElement) { + // if there was a prevDropTarget, create a dragleave event + if (interaction.prevDropTarget) { + dropEvents.leave = utils.extend({ type: 'dragleave' }, tmpl); + + dragEvent.dragLeave = dropEvents.leave.target = interaction.prevDropElement; + dragEvent.prevDropzone = dropEvents.leave.dropzone = interaction.prevDropTarget; + } + // if the dropTarget is not null, create a dragenter event + if (interaction.dropTarget) { + dropEvents.enter = { + dragEvent: dragEvent, + interaction: interaction, + target: interaction.dropElement, + dropzone: interaction.dropTarget, + relatedTarget: dragEvent.target, + draggable: dragEvent.interactable, + timeStamp: dragEvent.timeStamp, + type: 'dragenter' + }; + + dragEvent.dragEnter = interaction.dropElement; + dragEvent.dropzone = interaction.dropTarget; + } + } + + if (dragEvent.type === 'dragend' && interaction.dropTarget) { + dropEvents.drop = utils.extend({ type: 'drop' }, tmpl); + + dragEvent.dropzone = interaction.dropTarget; + dragEvent.relatedTarget = interaction.dropElement; + } + if (dragEvent.type === 'dragstart') { + dropEvents.activate = utils.extend({ type: 'dropactivate' }, tmpl); + + dropEvents.activate.target = null; + dropEvents.activate.dropzone = null; + } + if (dragEvent.type === 'dragend') { + dropEvents.deactivate = utils.extend({ type: 'dropdeactivate' }, tmpl); + + dropEvents.deactivate.target = null; + dropEvents.deactivate.dropzone = null; + } + if (dragEvent.type === 'dragmove' && interaction.dropTarget) { + dropEvents.move = utils.extend({ + dragmove: dragEvent, + type: 'dropmove' + }, tmpl); + + dragEvent.dropzone = interaction.dropTarget; + } + + return dropEvents; +} + +function fireDropEvents(interaction, dropEvents) { + var activeDrops = interaction.activeDrops, + prevDropTarget = interaction.prevDropTarget, + dropTarget = interaction.dropTarget, + dropElement = interaction.dropElement; + + + if (dropEvents.leave) { + prevDropTarget.fire(dropEvents.leave); + } + if (dropEvents.move) { + dropTarget.fire(dropEvents.move); + } + if (dropEvents.enter) { + dropTarget.fire(dropEvents.enter); + } + if (dropEvents.drop) { + dropTarget.fire(dropEvents.drop); + } + if (dropEvents.deactivate) { + fireActiveDrops(activeDrops, dropEvents.deactivate); + } + + interaction.prevDropTarget = dropTarget; + interaction.prevDropElement = dropElement; +} + +/** + * ```js + * interact(target) + * .dropChecker(function(dragEvent, // related dragmove or dragend event + * event, // TouchEvent/PointerEvent/MouseEvent + * dropped, // bool result of the default checker + * dropzone, // dropzone Interactable + * dropElement, // dropzone elemnt + * draggable, // draggable Interactable + * draggableElement) {// draggable element + * + * return dropped && event.target.hasAttribute('allow-drop'); + * } + * ``` + * + * ```js + * interact('.drop').dropzone({ + * accept: '.can-drop' || document.getElementById('single-drop'), + * overlap: 'pointer' || 'center' || zeroToOne + * } + * ``` + * + * Returns or sets whether draggables can be dropped onto this target to + * trigger drop events + * + * Dropzones can receive the following events: + * - `dropactivate` and `dropdeactivate` when an acceptable drag starts and ends + * - `dragenter` and `dragleave` when a draggable enters and leaves the dropzone + * - `dragmove` when a draggable that has entered the dropzone is moved + * - `drop` when a draggable is dropped into this dropzone + * + * Use the `accept` option to allow only elements that match the given CSS + * selector or element. The value can be: + * + * - **an Element** - only that element can be dropped into this dropzone. + * - **a string**, - the element being dragged must match it as a CSS selector. + * - **`null`** - accept options is cleared - it accepts any element. + * + * Use the `overlap` option to set how drops are checked for. The allowed + * values are: + * + * - `'pointer'`, the pointer must be over the dropzone (default) + * - `'center'`, the draggable element's center must be over the dropzone + * - a number from 0-1 which is the `(intersection area) / (draggable area)`. + * e.g. `0.5` for drop to happen when half of the area of the draggable is + * over the dropzone + * + * Use the `checker` option to specify a function to check if a dragged element + * is over this Interactable. + * + * @param {boolean | object | null} [options] The new options to be set. + * @return {boolean | Interactable} The current setting or this Interactable + */ +Interactable.prototype.dropzone = function (options) { + if (utils.is.object(options)) { + this.options.drop.enabled = options.enabled === false ? false : true; + + if (utils.is.function(options.ondrop)) { + this.events.ondrop = options.ondrop; + } + if (utils.is.function(options.ondropactivate)) { + this.events.ondropactivate = options.ondropactivate; + } + if (utils.is.function(options.ondropdeactivate)) { + this.events.ondropdeactivate = options.ondropdeactivate; + } + if (utils.is.function(options.ondragenter)) { + this.events.ondragenter = options.ondragenter; + } + if (utils.is.function(options.ondragleave)) { + this.events.ondragleave = options.ondragleave; + } + if (utils.is.function(options.ondropmove)) { + this.events.ondropmove = options.ondropmove; + } + + if (/^(pointer|center)$/.test(options.overlap)) { + this.options.drop.overlap = options.overlap; + } else if (utils.is.number(options.overlap)) { + this.options.drop.overlap = Math.max(Math.min(1, options.overlap), 0); + } + if ('accept' in options) { + this.options.drop.accept = options.accept; + } + if ('checker' in options) { + this.options.drop.checker = options.checker; + } + + return this; + } + + if (utils.is.bool(options)) { + this.options.drop.enabled = options; + + if (!options) { + this.ondragenter = this.ondragleave = this.ondrop = this.ondropactivate = this.ondropdeactivate = null; + } + + return this; + } + + return this.options.drop; +}; + +Interactable.prototype.dropCheck = function (dragEvent, event, draggable, draggableElement, dropElement, rect) { + var dropped = false; + + // if the dropzone has no rect (eg. display: none) + // call the custom dropChecker or just return false + if (!(rect = rect || this.getRect(dropElement))) { + return this.options.drop.checker ? this.options.drop.checker(dragEvent, event, dropped, this, dropElement, draggable, draggableElement) : false; + } + + var dropOverlap = this.options.drop.overlap; + + if (dropOverlap === 'pointer') { + var origin = utils.getOriginXY(draggable, draggableElement, 'drag'); + var page = utils.getPageXY(dragEvent); + + page.x += origin.x; + page.y += origin.y; + + var horizontal = page.x > rect.left && page.x < rect.right; + var vertical = page.y > rect.top && page.y < rect.bottom; + + dropped = horizontal && vertical; + } + + var dragRect = draggable.getRect(draggableElement); + + if (dragRect && dropOverlap === 'center') { + var cx = dragRect.left + dragRect.width / 2; + var cy = dragRect.top + dragRect.height / 2; + + dropped = cx >= rect.left && cx <= rect.right && cy >= rect.top && cy <= rect.bottom; + } + + if (dragRect && utils.is.number(dropOverlap)) { + var overlapArea = Math.max(0, Math.min(rect.right, dragRect.right) - Math.max(rect.left, dragRect.left)) * Math.max(0, Math.min(rect.bottom, dragRect.bottom) - Math.max(rect.top, dragRect.top)); + + var overlapRatio = overlapArea / (dragRect.width * dragRect.height); + + dropped = overlapRatio >= dropOverlap; + } + + if (this.options.drop.checker) { + dropped = this.options.drop.checker(dragEvent, event, dropped, this, dropElement, draggable, draggableElement); + } + + return dropped; +}; + +Interactable.signals.on('unset', function (_ref8) { + var interactable = _ref8.interactable; + + interactable.dropzone(false); +}); + +Interactable.settingsMethods.push('dropChecker'); + +Interaction.signals.on('new', function (interaction) { + interaction.dropTarget = null; // the dropzone a drag target might be dropped into + interaction.dropElement = null; // the element at the time of checking + interaction.prevDropTarget = null; // the dropzone that was recently dragged away from + interaction.prevDropElement = null; // the element at the time of checking + interaction.dropEvents = null; // the dropEvents related to the current drag event + + interaction.activeDrops = { + dropzones: [], // the dropzones that are mentioned below + elements: [], // elements of dropzones that accept the target draggable + rects: [] // the rects of the elements mentioned above + }; +}); + +Interaction.signals.on('stop', function (_ref9) { + var interaction = _ref9.interaction; + + interaction.dropTarget = interaction.dropElement = interaction.prevDropTarget = interaction.prevDropElement = null; +}); + +/** + * Returns or sets whether the dimensions of dropzone elements are calculated + * on every dragmove or only on dragstart for the default dropChecker + * + * @param {boolean} [newValue] True to check on each move. False to check only + * before start + * @return {boolean | interact} The current setting or interact + */ +interact.dynamicDrop = function (newValue) { + if (utils.is.bool(newValue)) { + //if (dragging && dynamicDrop !== newValue && !newValue) { + //calcRects(dropzones); + //} + + dynamicDrop = newValue; + + return interact; + } + return dynamicDrop; +}; + +utils.merge(Interactable.eventTypes, ['dragenter', 'dragleave', 'dropactivate', 'dropdeactivate', 'dropmove', 'drop']); +actions.methodDict.drop = 'dropzone'; + +defaultOptions.drop = drop.defaults; + +module.exports = drop; + +},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../interact":21,"../scope":33,"../utils":44,"./base":6}],9:[function(require,module,exports){ +'use strict'; + +var actions = require('./base'); +var utils = require('../utils'); +var InteractEvent = require('../InteractEvent'); +var Interactable = require('../Interactable'); +var Interaction = require('../Interaction'); +var defaultOptions = require('../defaultOptions'); + +var gesture = { + defaults: { + enabled: false, + origin: null, + restrict: null + }, + + checker: function checker(pointer, event, interactable, element, interaction) { + if (interaction.pointerIds.length >= 2) { + return { name: 'gesture' }; + } + + return null; + }, + + getCursor: function getCursor() { + return ''; + } +}; + +InteractEvent.signals.on('new', function (_ref) { + var iEvent = _ref.iEvent, + interaction = _ref.interaction; + + if (iEvent.type !== 'gesturestart') { + return; + } + iEvent.ds = 0; + + interaction.gesture.startDistance = interaction.gesture.prevDistance = iEvent.distance; + interaction.gesture.startAngle = interaction.gesture.prevAngle = iEvent.angle; + interaction.gesture.scale = 1; +}); + +InteractEvent.signals.on('new', function (_ref2) { + var iEvent = _ref2.iEvent, + interaction = _ref2.interaction; + + if (iEvent.type !== 'gesturemove') { + return; + } + + iEvent.ds = iEvent.scale - interaction.gesture.scale; + + interaction.target.fire(iEvent); + + interaction.gesture.prevAngle = iEvent.angle; + interaction.gesture.prevDistance = iEvent.distance; + + if (iEvent.scale !== Infinity && iEvent.scale !== null && iEvent.scale !== undefined && !isNaN(iEvent.scale)) { + + interaction.gesture.scale = iEvent.scale; + } +}); + +/** + * ```js + * interact(element).gesturable({ + * onstart: function (event) {}, + * onmove : function (event) {}, + * onend : function (event) {}, + * + * // limit multiple gestures. + * // See the explanation in {@link Interactable.draggable} example + * max: Infinity, + * maxPerElement: 1, + * }); + * + * var isGestureable = interact(element).gesturable(); + * ``` + * + * Gets or sets whether multitouch gestures can be performed on the target + * + * @param {boolean | object} [options] true/false or An object with event + * listeners to be fired on gesture events (makes the Interactable gesturable) + * @return {boolean | Interactable} A boolean indicating if this can be the + * target of gesture events, or this Interactable + */ +Interactable.prototype.gesturable = function (options) { + if (utils.is.object(options)) { + this.options.gesture.enabled = options.enabled === false ? false : true; + this.setPerAction('gesture', options); + this.setOnEvents('gesture', options); + + return this; + } + + if (utils.is.bool(options)) { + this.options.gesture.enabled = options; + + if (!options) { + this.ongesturestart = this.ongesturestart = this.ongestureend = null; + } + + return this; + } + + return this.options.gesture; +}; + +InteractEvent.signals.on('set-delta', function (_ref3) { + var interaction = _ref3.interaction, + iEvent = _ref3.iEvent, + action = _ref3.action, + event = _ref3.event, + starting = _ref3.starting, + ending = _ref3.ending, + deltaSource = _ref3.deltaSource; + + if (action !== 'gesture') { + return; + } + + var pointers = interaction.pointers; + + iEvent.touches = [pointers[0], pointers[1]]; + + if (starting) { + iEvent.distance = utils.touchDistance(pointers, deltaSource); + iEvent.box = utils.touchBBox(pointers); + iEvent.scale = 1; + iEvent.ds = 0; + iEvent.angle = utils.touchAngle(pointers, undefined, deltaSource); + iEvent.da = 0; + } else if (ending || event instanceof InteractEvent) { + iEvent.distance = interaction.prevEvent.distance; + iEvent.box = interaction.prevEvent.box; + iEvent.scale = interaction.prevEvent.scale; + iEvent.ds = iEvent.scale - 1; + iEvent.angle = interaction.prevEvent.angle; + iEvent.da = iEvent.angle - interaction.gesture.startAngle; + } else { + iEvent.distance = utils.touchDistance(pointers, deltaSource); + iEvent.box = utils.touchBBox(pointers); + iEvent.scale = iEvent.distance / interaction.gesture.startDistance; + iEvent.angle = utils.touchAngle(pointers, interaction.gesture.prevAngle, deltaSource); + + iEvent.ds = iEvent.scale - interaction.gesture.prevScale; + iEvent.da = iEvent.angle - interaction.gesture.prevAngle; + } +}); + +Interaction.signals.on('new', function (interaction) { + interaction.gesture = { + start: { x: 0, y: 0 }, + + startDistance: 0, // distance between two touches of touchStart + prevDistance: 0, + distance: 0, + + scale: 1, // gesture.distance / gesture.startDistance + + startAngle: 0, // angle of line joining two touches + prevAngle: 0 // angle of the previous gesture event + }; +}); + +actions.gesture = gesture; +actions.names.push('gesture'); +utils.merge(Interactable.eventTypes, ['gesturestart', 'gesturemove', 'gestureend']); +actions.methodDict.gesture = 'gesturable'; + +defaultOptions.gesture = gesture.defaults; + +module.exports = gesture; + +},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../utils":44,"./base":6}],10:[function(require,module,exports){ +'use strict'; + +var actions = require('./base'); +var utils = require('../utils'); +var browser = require('../utils/browser'); +var InteractEvent = require('../InteractEvent'); +/** @lends Interactable */ +var Interactable = require('../Interactable'); +var Interaction = require('../Interaction'); +var defaultOptions = require('../defaultOptions'); + +// Less Precision with touch input +var defaultMargin = browser.supportsTouch || browser.supportsPointerEvent ? 20 : 10; + +var resize = { + defaults: { + enabled: false, + mouseButtons: null, + + origin: null, + snap: null, + restrict: null, + inertia: null, + autoScroll: null, + + square: false, + preserveAspectRatio: false, + axis: 'xy', + + // use default margin + margin: NaN, + + // object with props left, right, top, bottom which are + // true/false values to resize when the pointer is over that edge, + // CSS selectors to match the handles for each direction + // or the Elements for each handle + edges: null, + + // a value of 'none' will limit the resize rect to a minimum of 0x0 + // 'negate' will alow the rect to have negative width/height + // 'reposition' will keep the width/height positive by swapping + // the top and bottom edges and/or swapping the left and right edges + invert: 'none' + }, + + checker: function checker(pointer, event, interactable, element, interaction, rect) { + if (!rect) { + return null; + } + + var page = utils.extend({}, interaction.curCoords.page); + var options = interactable.options; + + if (options.resize.enabled) { + var resizeOptions = options.resize; + var resizeEdges = { left: false, right: false, top: false, bottom: false }; + + // if using resize.edges + if (utils.is.object(resizeOptions.edges)) { + for (var edge in resizeEdges) { + resizeEdges[edge] = checkResizeEdge(edge, resizeOptions.edges[edge], page, interaction._eventTarget, element, rect, resizeOptions.margin || defaultMargin); + } + + resizeEdges.left = resizeEdges.left && !resizeEdges.right; + resizeEdges.top = resizeEdges.top && !resizeEdges.bottom; + + if (resizeEdges.left || resizeEdges.right || resizeEdges.top || resizeEdges.bottom) { + return { + name: 'resize', + edges: resizeEdges + }; + } + } else { + var right = options.resize.axis !== 'y' && page.x > rect.right - defaultMargin; + var bottom = options.resize.axis !== 'x' && page.y > rect.bottom - defaultMargin; + + if (right || bottom) { + return { + name: 'resize', + axes: (right ? 'x' : '') + (bottom ? 'y' : '') + }; + } + } + } + + return null; + }, + + cursors: browser.isIe9 ? { + x: 'e-resize', + y: 's-resize', + xy: 'se-resize', + + top: 'n-resize', + left: 'w-resize', + bottom: 's-resize', + right: 'e-resize', + topleft: 'se-resize', + bottomright: 'se-resize', + topright: 'ne-resize', + bottomleft: 'ne-resize' + } : { + x: 'ew-resize', + y: 'ns-resize', + xy: 'nwse-resize', + + top: 'ns-resize', + left: 'ew-resize', + bottom: 'ns-resize', + right: 'ew-resize', + topleft: 'nwse-resize', + bottomright: 'nwse-resize', + topright: 'nesw-resize', + bottomleft: 'nesw-resize' + }, + + getCursor: function getCursor(action) { + if (action.axis) { + return resize.cursors[action.name + action.axis]; + } else if (action.edges) { + var cursorKey = ''; + var edgeNames = ['top', 'bottom', 'left', 'right']; + + for (var i = 0; i < 4; i++) { + if (action.edges[edgeNames[i]]) { + cursorKey += edgeNames[i]; + } + } + + return resize.cursors[cursorKey]; + } + } +}; + +// resizestart +InteractEvent.signals.on('new', function (_ref) { + var iEvent = _ref.iEvent, + interaction = _ref.interaction; + + if (iEvent.type !== 'resizestart' || !interaction.prepared.edges) { + return; + } + + var startRect = interaction.target.getRect(interaction.element); + var resizeOptions = interaction.target.options.resize; + + /* + * When using the `resizable.square` or `resizable.preserveAspectRatio` options, resizing from one edge + * will affect another. E.g. with `resizable.square`, resizing to make the right edge larger will make + * the bottom edge larger by the same amount. We call these 'linked' edges. Any linked edges will depend + * on the active edges and the edge being interacted with. + */ + if (resizeOptions.square || resizeOptions.preserveAspectRatio) { + var linkedEdges = utils.extend({}, interaction.prepared.edges); + + linkedEdges.top = linkedEdges.top || linkedEdges.left && !linkedEdges.bottom; + linkedEdges.left = linkedEdges.left || linkedEdges.top && !linkedEdges.right; + linkedEdges.bottom = linkedEdges.bottom || linkedEdges.right && !linkedEdges.top; + linkedEdges.right = linkedEdges.right || linkedEdges.bottom && !linkedEdges.left; + + interaction.prepared._linkedEdges = linkedEdges; + } else { + interaction.prepared._linkedEdges = null; + } + + // if using `resizable.preserveAspectRatio` option, record aspect ratio at the start of the resize + if (resizeOptions.preserveAspectRatio) { + interaction.resizeStartAspectRatio = startRect.width / startRect.height; + } + + interaction.resizeRects = { + start: startRect, + current: utils.extend({}, startRect), + inverted: utils.extend({}, startRect), + previous: utils.extend({}, startRect), + delta: { + left: 0, right: 0, width: 0, + top: 0, bottom: 0, height: 0 + } + }; + + iEvent.rect = interaction.resizeRects.inverted; + iEvent.deltaRect = interaction.resizeRects.delta; +}); + +// resizemove +InteractEvent.signals.on('new', function (_ref2) { + var iEvent = _ref2.iEvent, + phase = _ref2.phase, + interaction = _ref2.interaction; + + if (phase !== 'move' || !interaction.prepared.edges) { + return; + } + + var resizeOptions = interaction.target.options.resize; + var invert = resizeOptions.invert; + var invertible = invert === 'reposition' || invert === 'negate'; + + var edges = interaction.prepared.edges; + + var start = interaction.resizeRects.start; + var current = interaction.resizeRects.current; + var inverted = interaction.resizeRects.inverted; + var delta = interaction.resizeRects.delta; + var previous = utils.extend(interaction.resizeRects.previous, inverted); + var originalEdges = edges; + + var dx = iEvent.dx; + var dy = iEvent.dy; + + if (resizeOptions.preserveAspectRatio || resizeOptions.square) { + // `resize.preserveAspectRatio` takes precedence over `resize.square` + var startAspectRatio = resizeOptions.preserveAspectRatio ? interaction.resizeStartAspectRatio : 1; + + edges = interaction.prepared._linkedEdges; + + if (originalEdges.left && originalEdges.bottom || originalEdges.right && originalEdges.top) { + dy = -dx / startAspectRatio; + } else if (originalEdges.left || originalEdges.right) { + dy = dx / startAspectRatio; + } else if (originalEdges.top || originalEdges.bottom) { + dx = dy * startAspectRatio; + } + } + + // update the 'current' rect without modifications + if (edges.top) { + current.top += dy; + } + if (edges.bottom) { + current.bottom += dy; + } + if (edges.left) { + current.left += dx; + } + if (edges.right) { + current.right += dx; + } + + if (invertible) { + // if invertible, copy the current rect + utils.extend(inverted, current); + + if (invert === 'reposition') { + // swap edge values if necessary to keep width/height positive + var swap = void 0; + + if (inverted.top > inverted.bottom) { + swap = inverted.top; + + inverted.top = inverted.bottom; + inverted.bottom = swap; + } + if (inverted.left > inverted.right) { + swap = inverted.left; + + inverted.left = inverted.right; + inverted.right = swap; + } + } + } else { + // if not invertible, restrict to minimum of 0x0 rect + inverted.top = Math.min(current.top, start.bottom); + inverted.bottom = Math.max(current.bottom, start.top); + inverted.left = Math.min(current.left, start.right); + inverted.right = Math.max(current.right, start.left); + } + + inverted.width = inverted.right - inverted.left; + inverted.height = inverted.bottom - inverted.top; + + for (var edge in inverted) { + delta[edge] = inverted[edge] - previous[edge]; + } + + iEvent.edges = interaction.prepared.edges; + iEvent.rect = inverted; + iEvent.deltaRect = delta; +}); + +/** + * ```js + * interact(element).resizable({ + * onstart: function (event) {}, + * onmove : function (event) {}, + * onend : function (event) {}, + * + * edges: { + * top : true, // Use pointer coords to check for resize. + * left : false, // Disable resizing from left edge. + * bottom: '.resize-s',// Resize if pointer target matches selector + * right : handleEl // Resize if pointer target is the given Element + * }, + * + * // Width and height can be adjusted independently. When `true`, width and + * // height are adjusted at a 1:1 ratio. + * square: false, + * + * // Width and height can be adjusted independently. When `true`, width and + * // height maintain the aspect ratio they had when resizing started. + * preserveAspectRatio: false, + * + * // a value of 'none' will limit the resize rect to a minimum of 0x0 + * // 'negate' will allow the rect to have negative width/height + * // 'reposition' will keep the width/height positive by swapping + * // the top and bottom edges and/or swapping the left and right edges + * invert: 'none' || 'negate' || 'reposition' + * + * // limit multiple resizes. + * // See the explanation in the {@link Interactable.draggable} example + * max: Infinity, + * maxPerElement: 1, + * }); + * + * var isResizeable = interact(element).resizable(); + * ``` + * + * Gets or sets whether resize actions can be performed on the target + * + * @param {boolean | object} [options] true/false or An object with event + * listeners to be fired on resize events (object makes the Interactable + * resizable) + * @return {boolean | Interactable} A boolean indicating if this can be the + * target of resize elements, or this Interactable + */ +Interactable.prototype.resizable = function (options) { + if (utils.is.object(options)) { + this.options.resize.enabled = options.enabled === false ? false : true; + this.setPerAction('resize', options); + this.setOnEvents('resize', options); + + if (/^x$|^y$|^xy$/.test(options.axis)) { + this.options.resize.axis = options.axis; + } else if (options.axis === null) { + this.options.resize.axis = defaultOptions.resize.axis; + } + + if (utils.is.bool(options.preserveAspectRatio)) { + this.options.resize.preserveAspectRatio = options.preserveAspectRatio; + } else if (utils.is.bool(options.square)) { + this.options.resize.square = options.square; + } + + return this; + } + if (utils.is.bool(options)) { + this.options.resize.enabled = options; + + if (!options) { + this.onresizestart = this.onresizestart = this.onresizeend = null; + } + + return this; + } + return this.options.resize; +}; + +function checkResizeEdge(name, value, page, element, interactableElement, rect, margin) { + // false, '', undefined, null + if (!value) { + return false; + } + + // true value, use pointer coords and element rect + if (value === true) { + // if dimensions are negative, "switch" edges + var width = utils.is.number(rect.width) ? rect.width : rect.right - rect.left; + var height = utils.is.number(rect.height) ? rect.height : rect.bottom - rect.top; + + if (width < 0) { + if (name === 'left') { + name = 'right'; + } else if (name === 'right') { + name = 'left'; + } + } + if (height < 0) { + if (name === 'top') { + name = 'bottom'; + } else if (name === 'bottom') { + name = 'top'; + } + } + + if (name === 'left') { + return page.x < (width >= 0 ? rect.left : rect.right) + margin; + } + if (name === 'top') { + return page.y < (height >= 0 ? rect.top : rect.bottom) + margin; + } + + if (name === 'right') { + return page.x > (width >= 0 ? rect.right : rect.left) - margin; + } + if (name === 'bottom') { + return page.y > (height >= 0 ? rect.bottom : rect.top) - margin; + } + } + + // the remaining checks require an element + if (!utils.is.element(element)) { + return false; + } + + return utils.is.element(value) + // the value is an element to use as a resize handle + ? value === element + // otherwise check if element matches value as selector + : utils.matchesUpTo(element, value, interactableElement); +} + +Interaction.signals.on('new', function (interaction) { + interaction.resizeAxes = 'xy'; +}); + +InteractEvent.signals.on('set-delta', function (_ref3) { + var interaction = _ref3.interaction, + iEvent = _ref3.iEvent, + action = _ref3.action; + + if (action !== 'resize' || !interaction.resizeAxes) { + return; + } + + var options = interaction.target.options; + + if (options.resize.square) { + if (interaction.resizeAxes === 'y') { + iEvent.dx = iEvent.dy; + } else { + iEvent.dy = iEvent.dx; + } + iEvent.axes = 'xy'; + } else { + iEvent.axes = interaction.resizeAxes; + + if (interaction.resizeAxes === 'x') { + iEvent.dy = 0; + } else if (interaction.resizeAxes === 'y') { + iEvent.dx = 0; + } + } +}); + +actions.resize = resize; +actions.names.push('resize'); +utils.merge(Interactable.eventTypes, ['resizestart', 'resizemove', 'resizeinertiastart', 'resizeinertiaresume', 'resizeend']); +actions.methodDict.resize = 'resizable'; + +defaultOptions.resize = resize.defaults; + +module.exports = resize; + +},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../utils":44,"../utils/browser":36,"./base":6}],11:[function(require,module,exports){ +'use strict'; + +var raf = require('./utils/raf'); +var getWindow = require('./utils/window').getWindow; +var is = require('./utils/is'); +var domUtils = require('./utils/domUtils'); +var Interaction = require('./Interaction'); +var defaultOptions = require('./defaultOptions'); + +var autoScroll = { + defaults: { + enabled: false, + container: null, // the item that is scrolled (Window or HTMLElement) + margin: 60, + speed: 300 // the scroll speed in pixels per second + }, + + interaction: null, + i: null, // the handle returned by window.setInterval + x: 0, y: 0, // Direction each pulse is to scroll in + + isScrolling: false, + prevTime: 0, + + start: function start(interaction) { + autoScroll.isScrolling = true; + raf.cancel(autoScroll.i); + + autoScroll.interaction = interaction; + autoScroll.prevTime = new Date().getTime(); + autoScroll.i = raf.request(autoScroll.scroll); + }, + + stop: function stop() { + autoScroll.isScrolling = false; + raf.cancel(autoScroll.i); + }, + + // scroll the window by the values in scroll.x/y + scroll: function scroll() { + var options = autoScroll.interaction.target.options[autoScroll.interaction.prepared.name].autoScroll; + var container = options.container || getWindow(autoScroll.interaction.element); + var now = new Date().getTime(); + // change in time in seconds + var dt = (now - autoScroll.prevTime) / 1000; + // displacement + var s = options.speed * dt; + + if (s >= 1) { + if (is.window(container)) { + container.scrollBy(autoScroll.x * s, autoScroll.y * s); + } else if (container) { + container.scrollLeft += autoScroll.x * s; + container.scrollTop += autoScroll.y * s; + } + + autoScroll.prevTime = now; + } + + if (autoScroll.isScrolling) { + raf.cancel(autoScroll.i); + autoScroll.i = raf.request(autoScroll.scroll); + } + }, + check: function check(interactable, actionName) { + var options = interactable.options; + + return options[actionName].autoScroll && options[actionName].autoScroll.enabled; + }, + onInteractionMove: function onInteractionMove(_ref) { + var interaction = _ref.interaction, + pointer = _ref.pointer; + + if (!(interaction.interacting() && autoScroll.check(interaction.target, interaction.prepared.name))) { + return; + } + + if (interaction.simulation) { + autoScroll.x = autoScroll.y = 0; + return; + } + + var top = void 0; + var right = void 0; + var bottom = void 0; + var left = void 0; + + var options = interaction.target.options[interaction.prepared.name].autoScroll; + var container = options.container || getWindow(interaction.element); + + if (is.window(container)) { + left = pointer.clientX < autoScroll.margin; + top = pointer.clientY < autoScroll.margin; + right = pointer.clientX > container.innerWidth - autoScroll.margin; + bottom = pointer.clientY > container.innerHeight - autoScroll.margin; + } else { + var rect = domUtils.getElementClientRect(container); + + left = pointer.clientX < rect.left + autoScroll.margin; + top = pointer.clientY < rect.top + autoScroll.margin; + right = pointer.clientX > rect.right - autoScroll.margin; + bottom = pointer.clientY > rect.bottom - autoScroll.margin; + } + + autoScroll.x = right ? 1 : left ? -1 : 0; + autoScroll.y = bottom ? 1 : top ? -1 : 0; + + if (!autoScroll.isScrolling) { + // set the autoScroll properties to those of the target + autoScroll.margin = options.margin; + autoScroll.speed = options.speed; + + autoScroll.start(interaction); + } + } +}; + +Interaction.signals.on('stop-active', function () { + autoScroll.stop(); +}); + +Interaction.signals.on('action-move', autoScroll.onInteractionMove); + +defaultOptions.perAction.autoScroll = autoScroll.defaults; + +module.exports = autoScroll; + +},{"./Interaction":5,"./defaultOptions":18,"./utils/domUtils":39,"./utils/is":46,"./utils/raf":50,"./utils/window":52}],12:[function(require,module,exports){ +'use strict'; + +/** @lends Interactable */ +var Interactable = require('../Interactable'); +var actions = require('../actions/base'); +var is = require('../utils/is'); +var domUtils = require('../utils/domUtils'); + +var _require = require('../utils'), + warnOnce = _require.warnOnce; + +Interactable.prototype.getAction = function (pointer, event, interaction, element) { + var action = this.defaultActionChecker(pointer, event, interaction, element); + + if (this.options.actionChecker) { + return this.options.actionChecker(pointer, event, action, this, element, interaction); + } + + return action; +}; + +/** + * ```js + * interact(element, { ignoreFrom: document.getElementById('no-action') }); + * // or + * interact(element).ignoreFrom('input, textarea, a'); + * ``` + * @deprecated + * If the target of the `mousedown`, `pointerdown` or `touchstart` event or any + * of it's parents match the given CSS selector or Element, no + * drag/resize/gesture is started. + * + * Don't use this method. Instead set the `ignoreFrom` option for each action + * or for `pointerEvents` + * + * @example + * interact(targett) + * .draggable({ + * ignoreFrom: 'input, textarea, a[href]'', + * }) + * .pointerEvents({ + * ignoreFrom: '[no-pointer]', + * }); + * + * @param {string | Element | null} [newValue] a CSS selector string, an + * Element or `null` to not ignore any elements + * @return {string | Element | object} The current ignoreFrom value or this + * Interactable + */ +Interactable.prototype.ignoreFrom = warnOnce(function (newValue) { + return this._backCompatOption('ignoreFrom', newValue); +}, 'Interactable.ignoreForm() has been deprecated. Use Interactble.draggable({ignoreFrom: newValue}).'); + +/** + * ```js + * + * @deprecated + * A drag/resize/gesture is started only If the target of the `mousedown`, + * `pointerdown` or `touchstart` event or any of it's parents match the given + * CSS selector or Element. + * + * Don't use this method. Instead set the `allowFrom` option for each action + * or for `pointerEvents` + * + * @example + * interact(targett) + * .resizable({ + * allowFrom: '.resize-handle', + * .pointerEvents({ + * allowFrom: '.handle',, + * }); + * + * @param {string | Element | null} [newValue] a CSS selector string, an + * Element or `null` to allow from any element + * @return {string | Element | object} The current allowFrom value or this + * Interactable + */ +Interactable.prototype.allowFrom = warnOnce(function (newValue) { + return this._backCompatOption('allowFrom', newValue); +}, 'Interactable.allowForm() has been deprecated. Use Interactble.draggable({allowFrom: newValue}).'); + +Interactable.prototype.testIgnore = function (ignoreFrom, interactableElement, element) { + if (!ignoreFrom || !is.element(element)) { + return false; + } + + if (is.string(ignoreFrom)) { + return domUtils.matchesUpTo(element, ignoreFrom, interactableElement); + } else if (is.element(ignoreFrom)) { + return domUtils.nodeContains(ignoreFrom, element); + } + + return false; +}; + +Interactable.prototype.testAllow = function (allowFrom, interactableElement, element) { + if (!allowFrom) { + return true; + } + + if (!is.element(element)) { + return false; + } + + if (is.string(allowFrom)) { + return domUtils.matchesUpTo(element, allowFrom, interactableElement); + } else if (is.element(allowFrom)) { + return domUtils.nodeContains(allowFrom, element); + } + + return false; +}; + +Interactable.prototype.testIgnoreAllow = function (options, interactableElement, eventTarget) { + return !this.testIgnore(options.ignoreFrom, interactableElement, eventTarget) && this.testAllow(options.allowFrom, interactableElement, eventTarget); +}; + +/** + * ```js + * interact('.resize-drag') + * .resizable(true) + * .draggable(true) + * .actionChecker(function (pointer, event, action, interactable, element, interaction) { + * + * if (interact.matchesSelector(event.target, '.drag-handle') { + * // force drag with handle target + * action.name = drag; + * } + * else { + * // resize from the top and right edges + * action.name = 'resize'; + * action.edges = { top: true, right: true }; + * } + * + * return action; + * }); + * ``` + * + * Gets or sets the function used to check action to be performed on + * pointerDown + * + * @param {function | null} [checker] A function which takes a pointer event, + * defaultAction string, interactable, element and interaction as parameters + * and returns an object with name property 'drag' 'resize' or 'gesture' and + * optionally an `edges` object with boolean 'top', 'left', 'bottom' and right + * props. + * @return {Function | Interactable} The checker function or this Interactable + */ +Interactable.prototype.actionChecker = function (checker) { + if (is.function(checker)) { + this.options.actionChecker = checker; + + return this; + } + + if (checker === null) { + delete this.options.actionChecker; + + return this; + } + + return this.options.actionChecker; +}; + +/** + * Returns or sets whether the the cursor should be changed depending on the + * action that would be performed if the mouse were pressed and dragged. + * + * @param {boolean} [newValue] + * @return {boolean | Interactable} The current setting or this Interactable + */ +Interactable.prototype.styleCursor = function (newValue) { + if (is.bool(newValue)) { + this.options.styleCursor = newValue; + + return this; + } + + if (newValue === null) { + delete this.options.styleCursor; + + return this; + } + + return this.options.styleCursor; +}; + +Interactable.prototype.defaultActionChecker = function (pointer, event, interaction, element) { + var rect = this.getRect(element); + var buttons = event.buttons || { + 0: 1, + 1: 4, + 3: 8, + 4: 16 + }[event.button]; + var action = null; + + for (var _i = 0; _i < actions.names.length; _i++) { + var _ref; + + _ref = actions.names[_i]; + var actionName = _ref; + + // check mouseButton setting if the pointer is down + if (interaction.pointerIsDown && /mouse|pointer/.test(interaction.pointerType) && (buttons & this.options[actionName].mouseButtons) === 0) { + continue; + } + + action = actions[actionName].checker(pointer, event, this, element, interaction, rect); + + if (action) { + return action; + } + } +}; + +},{"../Interactable":4,"../actions/base":6,"../utils":44,"../utils/domUtils":39,"../utils/is":46}],13:[function(require,module,exports){ +'use strict'; + +var interact = require('../interact'); +var Interactable = require('../Interactable'); +var Interaction = require('../Interaction'); +var actions = require('../actions/base'); +var defaultOptions = require('../defaultOptions'); +var scope = require('../scope'); +var utils = require('../utils'); +var signals = require('../utils/Signals').new(); + +require('./InteractableMethods'); + +var autoStart = { + signals: signals, + withinInteractionLimit: withinInteractionLimit, + // Allow this many interactions to happen simultaneously + maxInteractions: Infinity, + defaults: { + perAction: { + manualStart: false, + max: Infinity, + maxPerElement: 1, + allowFrom: null, + ignoreFrom: null, + + // only allow left button by default + // see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons#Return_value + mouseButtons: 1 + } + }, + setActionDefaults: function setActionDefaults(action) { + utils.extend(action.defaults, autoStart.defaults.perAction); + }, + validateAction: validateAction +}; + +// set cursor style on mousedown +Interaction.signals.on('down', function (_ref) { + var interaction = _ref.interaction, + pointer = _ref.pointer, + event = _ref.event, + eventTarget = _ref.eventTarget; + + if (interaction.interacting()) { + return; + } + + var actionInfo = getActionInfo(interaction, pointer, event, eventTarget); + prepare(interaction, actionInfo); +}); + +// set cursor style on mousemove +Interaction.signals.on('move', function (_ref2) { + var interaction = _ref2.interaction, + pointer = _ref2.pointer, + event = _ref2.event, + eventTarget = _ref2.eventTarget; + + if (interaction.pointerType !== 'mouse' || interaction.pointerIsDown || interaction.interacting()) { + return; + } + + var actionInfo = getActionInfo(interaction, pointer, event, eventTarget); + prepare(interaction, actionInfo); +}); + +Interaction.signals.on('move', function (arg) { + var interaction = arg.interaction, + event = arg.event; + + + if (!interaction.pointerIsDown || interaction.interacting() || !interaction.pointerWasMoved || !interaction.prepared.name) { + return; + } + + signals.fire('before-start', arg); + + var target = interaction.target; + + if (interaction.prepared.name && target) { + // check manualStart and interaction limit + if (target.options[interaction.prepared.name].manualStart || !withinInteractionLimit(target, interaction.element, interaction.prepared)) { + interaction.stop(event); + } else { + interaction.start(interaction.prepared, target, interaction.element); + } + } +}); + +// Check if the current target supports the action. +// If so, return the validated action. Otherwise, return null +function validateAction(action, interactable, element, eventTarget) { + if (utils.is.object(action) && interactable.testIgnoreAllow(interactable.options[action.name], element, eventTarget) && interactable.options[action.name].enabled && withinInteractionLimit(interactable, element, action)) { + return action; + } + + return null; +} + +function validateSelector(interaction, pointer, event, matches, matchElements, eventTarget) { + for (var i = 0, len = matches.length; i < len; i++) { + var match = matches[i]; + var matchElement = matchElements[i]; + var action = validateAction(match.getAction(pointer, event, interaction, matchElement), match, matchElement, eventTarget); + + if (action) { + return { + action: action, + target: match, + element: matchElement + }; + } + } + + return {}; +} + +function getActionInfo(interaction, pointer, event, eventTarget) { + var matches = []; + var matchElements = []; + + var element = eventTarget; + + function pushMatches(interactable) { + matches.push(interactable); + matchElements.push(element); + } + + while (utils.is.element(element)) { + matches = []; + matchElements = []; + + scope.interactables.forEachMatch(element, pushMatches); + + var actionInfo = validateSelector(interaction, pointer, event, matches, matchElements, eventTarget); + + if (actionInfo.action && !actionInfo.target.options[actionInfo.action.name].manualStart) { + return actionInfo; + } + + element = utils.parentNode(element); + } + + return {}; +} + +function prepare(interaction, _ref3) { + var action = _ref3.action, + target = _ref3.target, + element = _ref3.element; + + action = action || {}; + + if (interaction.target && interaction.target.options.styleCursor) { + interaction.target._doc.documentElement.style.cursor = ''; + } + + interaction.target = target; + interaction.element = element; + utils.copyAction(interaction.prepared, action); + + if (target && target.options.styleCursor) { + var cursor = action ? actions[action.name].getCursor(action) : ''; + interaction.target._doc.documentElement.style.cursor = cursor; + } + + signals.fire('prepared', { interaction: interaction }); +} + +Interaction.signals.on('stop', function (_ref4) { + var interaction = _ref4.interaction; + + var target = interaction.target; + + if (target && target.options.styleCursor) { + target._doc.documentElement.style.cursor = ''; + } +}); + +function withinInteractionLimit(interactable, element, action) { + var options = interactable.options; + var maxActions = options[action.name].max; + var maxPerElement = options[action.name].maxPerElement; + var activeInteractions = 0; + var targetCount = 0; + var targetElementCount = 0; + + // no actions if any of these values == 0 + if (!(maxActions && maxPerElement && autoStart.maxInteractions)) { + return; + } + + for (var _i = 0; _i < scope.interactions.length; _i++) { + var _ref5; + + _ref5 = scope.interactions[_i]; + var interaction = _ref5; + + var otherAction = interaction.prepared.name; + + if (!interaction.interacting()) { + continue; + } + + activeInteractions++; + + if (activeInteractions >= autoStart.maxInteractions) { + return false; + } + + if (interaction.target !== interactable) { + continue; + } + + targetCount += otherAction === action.name | 0; + + if (targetCount >= maxActions) { + return false; + } + + if (interaction.element === element) { + targetElementCount++; + + if (otherAction !== action.name || targetElementCount >= maxPerElement) { + return false; + } + } + } + + return autoStart.maxInteractions > 0; +} + +/** + * Returns or sets the maximum number of concurrent interactions allowed. By + * default only 1 interaction is allowed at a time (for backwards + * compatibility). To allow multiple interactions on the same Interactables and + * elements, you need to enable it in the draggable, resizable and gesturable + * `'max'` and `'maxPerElement'` options. + * + * @alias module:interact.maxInteractions + * + * @param {number} [newValue] Any number. newValue <= 0 means no interactions. + */ +interact.maxInteractions = function (newValue) { + if (utils.is.number(newValue)) { + autoStart.maxInteractions = newValue; + + return interact; + } + + return autoStart.maxInteractions; +}; + +Interactable.settingsMethods.push('styleCursor'); +Interactable.settingsMethods.push('actionChecker'); +Interactable.settingsMethods.push('ignoreFrom'); +Interactable.settingsMethods.push('allowFrom'); + +defaultOptions.base.actionChecker = null; +defaultOptions.base.styleCursor = true; + +utils.extend(defaultOptions.perAction, autoStart.defaults.perAction); + +module.exports = autoStart; + +},{"../Interactable":4,"../Interaction":5,"../actions/base":6,"../defaultOptions":18,"../interact":21,"../scope":33,"../utils":44,"../utils/Signals":34,"./InteractableMethods":12}],14:[function(require,module,exports){ +'use strict'; + +var autoStart = require('./base'); +var scope = require('../scope'); +var is = require('../utils/is'); + +var _require = require('../utils/domUtils'), + parentNode = _require.parentNode; + +autoStart.setActionDefaults(require('../actions/drag')); + +autoStart.signals.on('before-start', function (_ref) { + var interaction = _ref.interaction, + eventTarget = _ref.eventTarget, + dx = _ref.dx, + dy = _ref.dy; + + if (interaction.prepared.name !== 'drag') { + return; + } + + // check if a drag is in the correct axis + var absX = Math.abs(dx); + var absY = Math.abs(dy); + var targetOptions = interaction.target.options.drag; + var startAxis = targetOptions.startAxis; + var currentAxis = absX > absY ? 'x' : absX < absY ? 'y' : 'xy'; + + interaction.prepared.axis = targetOptions.lockAxis === 'start' ? currentAxis[0] // always lock to one axis even if currentAxis === 'xy' + : targetOptions.lockAxis; + + // if the movement isn't in the startAxis of the interactable + if (currentAxis !== 'xy' && startAxis !== 'xy' && startAxis !== currentAxis) { + // cancel the prepared action + interaction.prepared.name = null; + + // then try to get a drag from another ineractable + var element = eventTarget; + + var getDraggable = function getDraggable(interactable) { + if (interactable === interaction.target) { + return; + } + + var options = interaction.target.options.drag; + + if (!options.manualStart && interactable.testIgnoreAllow(options, element, eventTarget)) { + + var action = interactable.getAction(interaction.downPointer, interaction.downEvent, interaction, element); + + if (action && action.name === 'drag' && checkStartAxis(currentAxis, interactable) && autoStart.validateAction(action, interactable, element, eventTarget)) { + + return interactable; + } + } + }; + + // check all interactables + while (is.element(element)) { + var interactable = scope.interactables.forEachMatch(element, getDraggable); + + if (interactable) { + interaction.prepared.name = 'drag'; + interaction.target = interactable; + interaction.element = element; + break; + } + + element = parentNode(element); + } + } +}); + +function checkStartAxis(startAxis, interactable) { + if (!interactable) { + return false; + } + + var thisAxis = interactable.options.drag.startAxis; + + return startAxis === 'xy' || thisAxis === 'xy' || thisAxis === startAxis; +} + +},{"../actions/drag":7,"../scope":33,"../utils/domUtils":39,"../utils/is":46,"./base":13}],15:[function(require,module,exports){ +'use strict'; + +require('./base').setActionDefaults(require('../actions/gesture')); + +},{"../actions/gesture":9,"./base":13}],16:[function(require,module,exports){ +'use strict'; + +var autoStart = require('./base'); +var Interaction = require('../Interaction'); + +autoStart.defaults.perAction.hold = 0; +autoStart.defaults.perAction.delay = 0; + +Interaction.signals.on('new', function (interaction) { + interaction.autoStartHoldTimer = null; +}); + +autoStart.signals.on('prepared', function (_ref) { + var interaction = _ref.interaction; + + var hold = getHoldDuration(interaction); + + if (hold > 0) { + interaction.autoStartHoldTimer = setTimeout(function () { + interaction.start(interaction.prepared, interaction.target, interaction.element); + }, hold); + } +}); + +Interaction.signals.on('move', function (_ref2) { + var interaction = _ref2.interaction, + duplicate = _ref2.duplicate; + + if (interaction.pointerWasMoved && !duplicate) { + clearTimeout(interaction.autoStartHoldTimer); + } +}); + +// prevent regular down->move autoStart +autoStart.signals.on('before-start', function (_ref3) { + var interaction = _ref3.interaction; + + var hold = getHoldDuration(interaction); + + if (hold > 0) { + interaction.prepared.name = null; + } +}); + +function getHoldDuration(interaction) { + var actionName = interaction.prepared && interaction.prepared.name; + + if (!actionName) { + return null; + } + + var options = interaction.target.options; + + return options[actionName].hold || options[actionName].delay; +} + +module.exports = { + getHoldDuration: getHoldDuration +}; + +},{"../Interaction":5,"./base":13}],17:[function(require,module,exports){ +'use strict'; + +require('./base').setActionDefaults(require('../actions/resize')); + +},{"../actions/resize":10,"./base":13}],18:[function(require,module,exports){ +'use strict'; + +module.exports = { + base: { + accept: null, + preventDefault: 'auto', + deltaSource: 'page' + }, + + perAction: { + origin: { x: 0, y: 0 }, + + inertia: { + enabled: false, + resistance: 10, // the lambda in exponential decay + minSpeed: 100, // target speed must be above this for inertia to start + endSpeed: 10, // the speed at which inertia is slow enough to stop + allowResume: true, // allow resuming an action in inertia phase + smoothEndDuration: 300 // animate to snap/restrict endOnly if there's no inertia + } + } +}; + +},{}],19:[function(require,module,exports){ +'use strict'; + +/* browser entry point */ + +// inertia +require('./inertia'); + +// modifiers +require('./modifiers/snap'); +require('./modifiers/restrict'); + +// pointerEvents +require('./pointerEvents/base'); +require('./pointerEvents/holdRepeat'); +require('./pointerEvents/interactableTargets'); + +// autoStart hold +require('./autoStart/hold'); + +// actions +require('./actions/gesture'); +require('./actions/resize'); +require('./actions/drag'); +require('./actions/drop'); + +// load these modifiers after resize is loaded +require('./modifiers/snapSize'); +require('./modifiers/restrictEdges'); +require('./modifiers/restrictSize'); + +// autoStart actions +require('./autoStart/gesture'); +require('./autoStart/resize'); +require('./autoStart/drag'); + +// Interactable preventDefault setting +require('./interactablePreventDefault.js'); + +// autoScroll +require('./autoScroll'); + +// export interact +module.exports = require('./interact'); + +},{"./actions/drag":7,"./actions/drop":8,"./actions/gesture":9,"./actions/resize":10,"./autoScroll":11,"./autoStart/drag":14,"./autoStart/gesture":15,"./autoStart/hold":16,"./autoStart/resize":17,"./inertia":20,"./interact":21,"./interactablePreventDefault.js":22,"./modifiers/restrict":24,"./modifiers/restrictEdges":25,"./modifiers/restrictSize":26,"./modifiers/snap":27,"./modifiers/snapSize":28,"./pointerEvents/base":30,"./pointerEvents/holdRepeat":31,"./pointerEvents/interactableTargets":32}],20:[function(require,module,exports){ +'use strict'; + +var InteractEvent = require('./InteractEvent'); +var Interaction = require('./Interaction'); +var modifiers = require('./modifiers/base'); +var utils = require('./utils'); +var animationFrame = require('./utils/raf'); + +Interaction.signals.on('new', function (interaction) { + interaction.inertiaStatus = { + active: false, + smoothEnd: false, + allowResume: false, + + startEvent: null, + upCoords: {}, + + xe: 0, ye: 0, + sx: 0, sy: 0, + + t0: 0, + vx0: 0, vys: 0, + duration: 0, + + lambda_v0: 0, + one_ve_v0: 0, + i: null + }; + + interaction.boundInertiaFrame = function () { + return inertiaFrame.apply(interaction); + }; + interaction.boundSmoothEndFrame = function () { + return smoothEndFrame.apply(interaction); + }; +}); + +Interaction.signals.on('down', function (_ref) { + var interaction = _ref.interaction, + event = _ref.event, + pointer = _ref.pointer, + eventTarget = _ref.eventTarget; + + var status = interaction.inertiaStatus; + + // Check if the down event hits the current inertia target + if (status.active) { + var element = eventTarget; + + // climb up the DOM tree from the event target + while (utils.is.element(element)) { + + // if interaction element is the current inertia target element + if (element === interaction.element) { + // stop inertia + animationFrame.cancel(status.i); + status.active = false; + interaction.simulation = null; + + // update pointers to the down event's coordinates + interaction.updatePointer(pointer); + utils.setCoords(interaction.curCoords, interaction.pointers); + + // fire appropriate signals + var signalArg = { interaction: interaction }; + Interaction.signals.fire('before-action-move', signalArg); + Interaction.signals.fire('action-resume', signalArg); + + // fire a reume event + var resumeEvent = new InteractEvent(interaction, event, interaction.prepared.name, 'inertiaresume', interaction.element); + + interaction.target.fire(resumeEvent); + interaction.prevEvent = resumeEvent; + modifiers.resetStatuses(interaction.modifierStatuses); + + utils.copyCoords(interaction.prevCoords, interaction.curCoords); + break; + } + + element = utils.parentNode(element); + } + } +}); + +Interaction.signals.on('up', function (_ref2) { + var interaction = _ref2.interaction, + event = _ref2.event; + + var status = interaction.inertiaStatus; + + if (!interaction.interacting() || status.active) { + return; + } + + var target = interaction.target; + var options = target && target.options; + var inertiaOptions = options && interaction.prepared.name && options[interaction.prepared.name].inertia; + + var now = new Date().getTime(); + var statuses = {}; + var page = utils.extend({}, interaction.curCoords.page); + var pointerSpeed = interaction.pointerDelta.client.speed; + + var smoothEnd = false; + var modifierResult = void 0; + + // check if inertia should be started + var inertiaPossible = inertiaOptions && inertiaOptions.enabled && interaction.prepared.name !== 'gesture' && event !== status.startEvent; + + var inertia = inertiaPossible && now - interaction.curCoords.timeStamp < 50 && pointerSpeed > inertiaOptions.minSpeed && pointerSpeed > inertiaOptions.endSpeed; + + var modifierArg = { + interaction: interaction, + pageCoords: page, + statuses: statuses, + preEnd: true, + requireEndOnly: true + }; + + // smoothEnd + if (inertiaPossible && !inertia) { + modifiers.resetStatuses(statuses); + + modifierResult = modifiers.setAll(modifierArg); + + if (modifierResult.shouldMove && modifierResult.locked) { + smoothEnd = true; + } + } + + if (!(inertia || smoothEnd)) { + return; + } + + utils.copyCoords(status.upCoords, interaction.curCoords); + + interaction.pointers[0] = status.startEvent = new InteractEvent(interaction, event, interaction.prepared.name, 'inertiastart', interaction.element); + + status.t0 = now; + + status.active = true; + status.allowResume = inertiaOptions.allowResume; + interaction.simulation = status; + + target.fire(status.startEvent); + + if (inertia) { + status.vx0 = interaction.pointerDelta.client.vx; + status.vy0 = interaction.pointerDelta.client.vy; + status.v0 = pointerSpeed; + + calcInertia(interaction, status); + + utils.extend(page, interaction.curCoords.page); + + page.x += status.xe; + page.y += status.ye; + + modifiers.resetStatuses(statuses); + + modifierResult = modifiers.setAll(modifierArg); + + status.modifiedXe += modifierResult.dx; + status.modifiedYe += modifierResult.dy; + + status.i = animationFrame.request(interaction.boundInertiaFrame); + } else { + status.smoothEnd = true; + status.xe = modifierResult.dx; + status.ye = modifierResult.dy; + + status.sx = status.sy = 0; + + status.i = animationFrame.request(interaction.boundSmoothEndFrame); + } +}); + +Interaction.signals.on('stop-active', function (_ref3) { + var interaction = _ref3.interaction; + + var status = interaction.inertiaStatus; + + if (status.active) { + animationFrame.cancel(status.i); + status.active = false; + interaction.simulation = null; + } +}); + +function calcInertia(interaction, status) { + var inertiaOptions = interaction.target.options[interaction.prepared.name].inertia; + var lambda = inertiaOptions.resistance; + var inertiaDur = -Math.log(inertiaOptions.endSpeed / status.v0) / lambda; + + status.x0 = interaction.prevEvent.pageX; + status.y0 = interaction.prevEvent.pageY; + status.t0 = status.startEvent.timeStamp / 1000; + status.sx = status.sy = 0; + + status.modifiedXe = status.xe = (status.vx0 - inertiaDur) / lambda; + status.modifiedYe = status.ye = (status.vy0 - inertiaDur) / lambda; + status.te = inertiaDur; + + status.lambda_v0 = lambda / status.v0; + status.one_ve_v0 = 1 - inertiaOptions.endSpeed / status.v0; +} + +function inertiaFrame() { + updateInertiaCoords(this); + utils.setCoordDeltas(this.pointerDelta, this.prevCoords, this.curCoords); + + var status = this.inertiaStatus; + var options = this.target.options[this.prepared.name].inertia; + var lambda = options.resistance; + var t = new Date().getTime() / 1000 - status.t0; + + if (t < status.te) { + + var progress = 1 - (Math.exp(-lambda * t) - status.lambda_v0) / status.one_ve_v0; + + if (status.modifiedXe === status.xe && status.modifiedYe === status.ye) { + status.sx = status.xe * progress; + status.sy = status.ye * progress; + } else { + var quadPoint = utils.getQuadraticCurvePoint(0, 0, status.xe, status.ye, status.modifiedXe, status.modifiedYe, progress); + + status.sx = quadPoint.x; + status.sy = quadPoint.y; + } + + this.doMove(); + + status.i = animationFrame.request(this.boundInertiaFrame); + } else { + status.sx = status.modifiedXe; + status.sy = status.modifiedYe; + + this.doMove(); + this.end(status.startEvent); + status.active = false; + this.simulation = null; + } + + utils.copyCoords(this.prevCoords, this.curCoords); +} + +function smoothEndFrame() { + updateInertiaCoords(this); + + var status = this.inertiaStatus; + var t = new Date().getTime() - status.t0; + var duration = this.target.options[this.prepared.name].inertia.smoothEndDuration; + + if (t < duration) { + status.sx = utils.easeOutQuad(t, 0, status.xe, duration); + status.sy = utils.easeOutQuad(t, 0, status.ye, duration); + + this.pointerMove(status.startEvent, status.startEvent); + + status.i = animationFrame.request(this.boundSmoothEndFrame); + } else { + status.sx = status.xe; + status.sy = status.ye; + + this.pointerMove(status.startEvent, status.startEvent); + this.end(status.startEvent); + + status.smoothEnd = status.active = false; + this.simulation = null; + } +} + +function updateInertiaCoords(interaction) { + var status = interaction.inertiaStatus; + + // return if inertia isn't running + if (!status.active) { + return; + } + + var pageUp = status.upCoords.page; + var clientUp = status.upCoords.client; + + utils.setCoords(interaction.curCoords, [{ + pageX: pageUp.x + status.sx, + pageY: pageUp.y + status.sy, + clientX: clientUp.x + status.sx, + clientY: clientUp.y + status.sy + }]); +} + +},{"./InteractEvent":3,"./Interaction":5,"./modifiers/base":23,"./utils":44,"./utils/raf":50}],21:[function(require,module,exports){ +'use strict'; + +/** @module interact */ + +var browser = require('./utils/browser'); +var events = require('./utils/events'); +var utils = require('./utils'); +var scope = require('./scope'); +var Interactable = require('./Interactable'); +var Interaction = require('./Interaction'); + +var globalEvents = {}; + +/** + * ```js + * interact('#draggable').draggable(true); + * + * var rectables = interact('rect'); + * rectables + * .gesturable(true) + * .on('gesturemove', function (event) { + * // ... + * }); + * ``` + * + * The methods of this variable can be used to set elements as interactables + * and also to change various default settings. + * + * Calling it as a function and passing an element or a valid CSS selector + * string returns an Interactable object which has various methods to configure + * it. + * + * @global + * + * @param {Element | string} element The HTML or SVG Element to interact with + * or CSS selector + * @return {Interactable} + */ +function interact(element, options) { + var interactable = scope.interactables.get(element, options); + + if (!interactable) { + interactable = new Interactable(element, options); + interactable.events.global = globalEvents; + } + + return interactable; +} + +/** + * Check if an element or selector has been set with the {@link interact} + * function + * + * @alias module:interact.isSet + * + * @param {Element} element The Element being searched for + * @return {boolean} Indicates if the element or CSS selector was previously + * passed to interact +*/ +interact.isSet = function (element, options) { + return scope.interactables.indexOfElement(element, options && options.context) !== -1; +}; + +/** + * Add a global listener for an InteractEvent or adds a DOM event to `document` + * + * @alias module:interact.on + * + * @param {string | array | object} type The types of events to listen for + * @param {function} listener The function event (s) + * @param {object | boolean} [options] object or useCapture flag for + * addEventListener + * @return {object} interact + */ +interact.on = function (type, listener, options) { + if (utils.is.string(type) && type.search(' ') !== -1) { + type = type.trim().split(/ +/); + } + + if (utils.is.array(type)) { + for (var _i = 0; _i < type.length; _i++) { + var _ref; + + _ref = type[_i]; + var eventType = _ref; + + interact.on(eventType, listener, options); + } + + return interact; + } + + if (utils.is.object(type)) { + for (var prop in type) { + interact.on(prop, type[prop], listener); + } + + return interact; + } + + // if it is an InteractEvent type, add listener to globalEvents + if (utils.contains(Interactable.eventTypes, type)) { + // if this type of event was never bound + if (!globalEvents[type]) { + globalEvents[type] = [listener]; + } else { + globalEvents[type].push(listener); + } + } + // If non InteractEvent type, addEventListener to document + else { + events.add(scope.document, type, listener, { options: options }); + } + + return interact; +}; + +/** + * Removes a global InteractEvent listener or DOM event from `document` + * + * @alias module:interact.off + * + * @param {string | array | object} type The types of events that were listened + * for + * @param {function} listener The listener function to be removed + * @param {object | boolean} options [options] object or useCapture flag for + * removeEventListener + * @return {object} interact + */ +interact.off = function (type, listener, options) { + if (utils.is.string(type) && type.search(' ') !== -1) { + type = type.trim().split(/ +/); + } + + if (utils.is.array(type)) { + for (var _i2 = 0; _i2 < type.length; _i2++) { + var _ref2; + + _ref2 = type[_i2]; + var eventType = _ref2; + + interact.off(eventType, listener, options); + } + + return interact; + } + + if (utils.is.object(type)) { + for (var prop in type) { + interact.off(prop, type[prop], listener); + } + + return interact; + } + + if (!utils.contains(Interactable.eventTypes, type)) { + events.remove(scope.document, type, listener, options); + } else { + var index = void 0; + + if (type in globalEvents && (index = globalEvents[type].indexOf(listener)) !== -1) { + globalEvents[type].splice(index, 1); + } + } + + return interact; +}; + +/** + * Returns an object which exposes internal data + + * @alias module:interact.debug + * + * @return {object} An object with properties that outline the current state + * and expose internal functions and variables + */ +interact.debug = function () { + return scope; +}; + +// expose the functions used to calculate multi-touch properties +interact.getPointerAverage = utils.pointerAverage; +interact.getTouchBBox = utils.touchBBox; +interact.getTouchDistance = utils.touchDistance; +interact.getTouchAngle = utils.touchAngle; + +interact.getElementRect = utils.getElementRect; +interact.getElementClientRect = utils.getElementClientRect; +interact.matchesSelector = utils.matchesSelector; +interact.closest = utils.closest; + +/** + * @alias module:interact.supportsTouch + * + * @return {boolean} Whether or not the browser supports touch input + */ +interact.supportsTouch = function () { + return browser.supportsTouch; +}; + +/** + * @alias module:interact.supportsPointerEvent + * + * @return {boolean} Whether or not the browser supports PointerEvents + */ +interact.supportsPointerEvent = function () { + return browser.supportsPointerEvent; +}; + +/** + * Cancels all interactions (end events are not fired) + * + * @alias module:interact.stop + * + * @param {Event} event An event on which to call preventDefault() + * @return {object} interact + */ +interact.stop = function (event) { + for (var i = scope.interactions.length - 1; i >= 0; i--) { + scope.interactions[i].stop(event); + } + + return interact; +}; + +/** + * Returns or sets the distance the pointer must be moved before an action + * sequence occurs. This also affects tolerance for tap events. + * + * @alias module:interact.pointerMoveTolerance + * + * @param {number} [newValue] The movement from the start position must be greater than this value + * @return {interact | number} + */ +interact.pointerMoveTolerance = function (newValue) { + if (utils.is.number(newValue)) { + Interaction.pointerMoveTolerance = newValue; + + return interact; + } + + return Interaction.pointerMoveTolerance; +}; + +interact.addDocument = scope.addDocument; +interact.removeDocument = scope.removeDocument; + +scope.interact = interact; + +module.exports = interact; + +},{"./Interactable":4,"./Interaction":5,"./scope":33,"./utils":44,"./utils/browser":36,"./utils/events":40}],22:[function(require,module,exports){ +'use strict'; + +var Interactable = require('./Interactable'); +var Interaction = require('./Interaction'); +var scope = require('./scope'); +var is = require('./utils/is'); +var events = require('./utils/events'); +var browser = require('./utils/browser'); + +var _require = require('./utils/domUtils'), + nodeContains = _require.nodeContains, + matchesSelector = _require.matchesSelector; + +/** + * Returns or sets whether to prevent the browser's default behaviour in + * response to pointer events. Can be set to: + * - `'always'` to always prevent + * - `'never'` to never prevent + * - `'auto'` to let interact.js try to determine what would be best + * + * @param {string} [newValue] `true`, `false` or `'auto'` + * @return {string | Interactable} The current setting or this Interactable + */ + + +Interactable.prototype.preventDefault = function (newValue) { + if (/^(always|never|auto)$/.test(newValue)) { + this.options.preventDefault = newValue; + return this; + } + + if (is.bool(newValue)) { + this.options.preventDefault = newValue ? 'always' : 'never'; + return this; + } + + return this.options.preventDefault; +}; + +Interactable.prototype.checkAndPreventDefault = function (event) { + var setting = this.options.preventDefault; + + if (setting === 'never') { + return; + } + + if (setting === 'always') { + event.preventDefault(); + return; + } + + // setting === 'auto' + + // don't preventDefault of touch{start,move} events if the browser supports passive + // events listeners. CSS touch-action and user-selecct should be used instead + if (events.supportsPassive && /^touch(start|move)$/.test(event.type) && !browser.isIOS) { + return; + } + + // don't preventDefault of pointerdown events + if (/^(mouse|pointer|touch)*(down|start)/i.test(event.type)) { + return; + } + + // don't preventDefault on editable elements + if (is.element(event.target) && matchesSelector(event.target, 'input,select,textarea,[contenteditable=true],[contenteditable=true] *')) { + return; + } + + event.preventDefault(); +}; + +function onInteractionEvent(_ref) { + var interaction = _ref.interaction, + event = _ref.event; + + if (interaction.target) { + interaction.target.checkAndPreventDefault(event); + } +} + +var _arr = ['down', 'move', 'up', 'cancel']; +for (var _i = 0; _i < _arr.length; _i++) { + var eventSignal = _arr[_i]; + Interaction.signals.on(eventSignal, onInteractionEvent); +} + +// prevent native HTML5 drag on interact.js target elements +Interaction.docEvents.dragstart = function preventNativeDrag(event) { + for (var _i2 = 0; _i2 < scope.interactions.length; _i2++) { + var _ref2; + + _ref2 = scope.interactions[_i2]; + var interaction = _ref2; + + + if (interaction.element && (interaction.element === event.target || nodeContains(interaction.element, event.target))) { + + interaction.target.checkAndPreventDefault(event); + return; + } + } +}; + +},{"./Interactable":4,"./Interaction":5,"./scope":33,"./utils/browser":36,"./utils/domUtils":39,"./utils/events":40,"./utils/is":46}],23:[function(require,module,exports){ +'use strict'; + +var InteractEvent = require('../InteractEvent'); +var Interaction = require('../Interaction'); +var extend = require('../utils/extend'); + +var modifiers = { + names: [], + + setOffsets: function setOffsets(arg) { + var interaction = arg.interaction, + page = arg.pageCoords; + var target = interaction.target, + element = interaction.element, + startOffset = interaction.startOffset; + + var rect = target.getRect(element); + + if (rect) { + startOffset.left = page.x - rect.left; + startOffset.top = page.y - rect.top; + + startOffset.right = rect.right - page.x; + startOffset.bottom = rect.bottom - page.y; + + if (!('width' in rect)) { + rect.width = rect.right - rect.left; + } + if (!('height' in rect)) { + rect.height = rect.bottom - rect.top; + } + } else { + startOffset.left = startOffset.top = startOffset.right = startOffset.bottom = 0; + } + + arg.rect = rect; + arg.interactable = target; + arg.element = element; + + for (var _i = 0; _i < modifiers.names.length; _i++) { + var _ref; + + _ref = modifiers.names[_i]; + var modifierName = _ref; + + arg.options = target.options[interaction.prepared.name][modifierName]; + + if (!arg.options) { + continue; + } + + interaction.modifierOffsets[modifierName] = modifiers[modifierName].setOffset(arg); + } + }, + + setAll: function setAll(arg) { + var interaction = arg.interaction, + statuses = arg.statuses, + preEnd = arg.preEnd, + requireEndOnly = arg.requireEndOnly; + + var result = { + dx: 0, + dy: 0, + changed: false, + locked: false, + shouldMove: true + }; + + arg.modifiedCoords = extend({}, arg.pageCoords); + + for (var _i2 = 0; _i2 < modifiers.names.length; _i2++) { + var _ref2; + + _ref2 = modifiers.names[_i2]; + var modifierName = _ref2; + + var modifier = modifiers[modifierName]; + var options = interaction.target.options[interaction.prepared.name][modifierName]; + + if (!shouldDo(options, preEnd, requireEndOnly)) { + continue; + } + + arg.status = arg.status = statuses[modifierName]; + arg.options = options; + arg.offset = arg.interaction.modifierOffsets[modifierName]; + + modifier.set(arg); + + if (arg.status.locked) { + arg.modifiedCoords.x += arg.status.dx; + arg.modifiedCoords.y += arg.status.dy; + + result.dx += arg.status.dx; + result.dy += arg.status.dy; + + result.locked = true; + } + } + + // a move should be fired if: + // - there are no modifiers enabled, + // - no modifiers are "locked" i.e. have changed the pointer's coordinates, or + // - the locked coords have changed since the last pointer move + result.shouldMove = !arg.status || !result.locked || arg.status.changed; + + return result; + }, + + resetStatuses: function resetStatuses(statuses) { + for (var _i3 = 0; _i3 < modifiers.names.length; _i3++) { + var _ref3; + + _ref3 = modifiers.names[_i3]; + var modifierName = _ref3; + + var status = statuses[modifierName] || {}; + + status.dx = status.dy = 0; + status.modifiedX = status.modifiedY = NaN; + status.locked = false; + status.changed = true; + + statuses[modifierName] = status; + } + + return statuses; + }, + + start: function start(_ref4, signalName) { + var interaction = _ref4.interaction; + + var arg = { + interaction: interaction, + pageCoords: (signalName === 'action-resume' ? interaction.curCoords : interaction.startCoords).page, + startOffset: interaction.startOffset, + statuses: interaction.modifierStatuses, + preEnd: false, + requireEndOnly: false + }; + + modifiers.setOffsets(arg); + modifiers.resetStatuses(arg.statuses); + + arg.pageCoords = extend({}, interaction.startCoords.page); + interaction.modifierResult = modifiers.setAll(arg); + }, + + beforeMove: function beforeMove(_ref5) { + var interaction = _ref5.interaction, + preEnd = _ref5.preEnd, + interactingBeforeMove = _ref5.interactingBeforeMove; + + var modifierResult = modifiers.setAll({ + interaction: interaction, + preEnd: preEnd, + pageCoords: interaction.curCoords.page, + statuses: interaction.modifierStatuses, + requireEndOnly: false + }); + + // don't fire an action move if a modifier would keep the event in the same + // cordinates as before + if (!modifierResult.shouldMove && interactingBeforeMove) { + interaction._dontFireMove = true; + } + + interaction.modifierResult = modifierResult; + }, + + end: function end(_ref6) { + var interaction = _ref6.interaction, + event = _ref6.event; + + for (var _i4 = 0; _i4 < modifiers.names.length; _i4++) { + var _ref7; + + _ref7 = modifiers.names[_i4]; + var modifierName = _ref7; + + var options = interaction.target.options[interaction.prepared.name][modifierName]; + + // if the endOnly option is true for any modifier + if (shouldDo(options, true, true)) { + // fire a move event at the modified coordinates + interaction.doMove({ event: event, preEnd: true }); + break; + } + } + }, + + setXY: function setXY(arg) { + var iEvent = arg.iEvent, + interaction = arg.interaction; + + var modifierArg = extend({}, arg); + + for (var i = 0; i < modifiers.names.length; i++) { + var modifierName = modifiers.names[i]; + modifierArg.options = interaction.target.options[interaction.prepared.name][modifierName]; + + if (!modifierArg.options) { + continue; + } + + var modifier = modifiers[modifierName]; + + modifierArg.status = interaction.modifierStatuses[modifierName]; + + iEvent[modifierName] = modifier.modifyCoords(modifierArg); + } + } +}; + +Interaction.signals.on('new', function (interaction) { + interaction.startOffset = { left: 0, right: 0, top: 0, bottom: 0 }; + interaction.modifierOffsets = {}; + interaction.modifierStatuses = modifiers.resetStatuses({}); + interaction.modifierResult = null; +}); + +Interaction.signals.on('action-start', modifiers.start); +Interaction.signals.on('action-resume', modifiers.start); +Interaction.signals.on('before-action-move', modifiers.beforeMove); +Interaction.signals.on('action-end', modifiers.end); + +InteractEvent.signals.on('set-xy', modifiers.setXY); + +function shouldDo(options, preEnd, requireEndOnly) { + return options && options.enabled && (preEnd || !options.endOnly) && (!requireEndOnly || options.endOnly); +} + +module.exports = modifiers; + +},{"../InteractEvent":3,"../Interaction":5,"../utils/extend":41}],24:[function(require,module,exports){ +'use strict'; + +var modifiers = require('./base'); +var utils = require('../utils'); +var defaultOptions = require('../defaultOptions'); + +var restrict = { + defaults: { + enabled: false, + endOnly: false, + restriction: null, + elementRect: null + }, + + setOffset: function setOffset(_ref) { + var rect = _ref.rect, + startOffset = _ref.startOffset, + options = _ref.options; + + var elementRect = options && options.elementRect; + var offset = {}; + + if (rect && elementRect) { + offset.left = startOffset.left - rect.width * elementRect.left; + offset.top = startOffset.top - rect.height * elementRect.top; + + offset.right = startOffset.right - rect.width * (1 - elementRect.right); + offset.bottom = startOffset.bottom - rect.height * (1 - elementRect.bottom); + } else { + offset.left = offset.top = offset.right = offset.bottom = 0; + } + + return offset; + }, + + set: function set(_ref2) { + var modifiedCoords = _ref2.modifiedCoords, + interaction = _ref2.interaction, + status = _ref2.status, + options = _ref2.options; + + if (!options) { + return status; + } + + var page = status.useStatusXY ? { x: status.x, y: status.y } : utils.extend({}, modifiedCoords); + + var restriction = getRestrictionRect(options.restriction, interaction, page); + + if (!restriction) { + return status; + } + + status.dx = 0; + status.dy = 0; + status.locked = false; + + var rect = restriction; + var modifiedX = page.x; + var modifiedY = page.y; + + var offset = interaction.modifierOffsets.restrict; + + // object is assumed to have + // x, y, width, height or + // left, top, right, bottom + if ('x' in restriction && 'y' in restriction) { + modifiedX = Math.max(Math.min(rect.x + rect.width - offset.right, page.x), rect.x + offset.left); + modifiedY = Math.max(Math.min(rect.y + rect.height - offset.bottom, page.y), rect.y + offset.top); + } else { + modifiedX = Math.max(Math.min(rect.right - offset.right, page.x), rect.left + offset.left); + modifiedY = Math.max(Math.min(rect.bottom - offset.bottom, page.y), rect.top + offset.top); + } + + status.dx = modifiedX - page.x; + status.dy = modifiedY - page.y; + + status.changed = status.modifiedX !== modifiedX || status.modifiedY !== modifiedY; + status.locked = !!(status.dx || status.dy); + + status.modifiedX = modifiedX; + status.modifiedY = modifiedY; + }, + + modifyCoords: function modifyCoords(_ref3) { + var page = _ref3.page, + client = _ref3.client, + status = _ref3.status, + phase = _ref3.phase, + options = _ref3.options; + + var elementRect = options && options.elementRect; + + if (options && options.enabled && !(phase === 'start' && elementRect && status.locked)) { + + if (status.locked) { + page.x += status.dx; + page.y += status.dy; + client.x += status.dx; + client.y += status.dy; + + return { + dx: status.dx, + dy: status.dy + }; + } + } + }, + + getRestrictionRect: getRestrictionRect +}; + +function getRestrictionRect(value, interaction, page) { + if (utils.is.function(value)) { + return utils.resolveRectLike(value, interaction.target, interaction.element, [page.x, page.y, interaction]); + } else { + return utils.resolveRectLike(value, interaction.target, interaction.element); + } +} + +modifiers.restrict = restrict; +modifiers.names.push('restrict'); + +defaultOptions.perAction.restrict = restrict.defaults; + +module.exports = restrict; + +},{"../defaultOptions":18,"../utils":44,"./base":23}],25:[function(require,module,exports){ +'use strict'; + +// This module adds the options.resize.restrictEdges setting which sets min and +// max for the top, left, bottom and right edges of the target being resized. +// +// interact(target).resize({ +// edges: { top: true, left: true }, +// restrictEdges: { +// inner: { top: 200, left: 200, right: 400, bottom: 400 }, +// outer: { top: 0, left: 0, right: 600, bottom: 600 }, +// }, +// }); + +var modifiers = require('./base'); +var utils = require('../utils'); +var rectUtils = require('../utils/rect'); +var defaultOptions = require('../defaultOptions'); +var resize = require('../actions/resize'); + +var _require = require('./restrict'), + getRestrictionRect = _require.getRestrictionRect; + +var noInner = { top: +Infinity, left: +Infinity, bottom: -Infinity, right: -Infinity }; +var noOuter = { top: -Infinity, left: -Infinity, bottom: +Infinity, right: +Infinity }; + +var restrictEdges = { + defaults: { + enabled: false, + endOnly: false, + min: null, + max: null, + offset: null + }, + + setOffset: function setOffset(_ref) { + var interaction = _ref.interaction, + startOffset = _ref.startOffset, + options = _ref.options; + + if (!options) { + return utils.extend({}, startOffset); + } + + var offset = getRestrictionRect(options.offset, interaction, interaction.startCoords.page); + + if (offset) { + return { + top: startOffset.top + offset.y, + left: startOffset.left + offset.x, + bottom: startOffset.bottom + offset.y, + right: startOffset.right + offset.x + }; + } + + return startOffset; + }, + + set: function set(_ref2) { + var modifiedCoords = _ref2.modifiedCoords, + interaction = _ref2.interaction, + status = _ref2.status, + offset = _ref2.offset, + options = _ref2.options; + + var edges = interaction.prepared.linkedEdges || interaction.prepared.edges; + + if (!interaction.interacting() || !edges) { + return; + } + + var page = status.useStatusXY ? { x: status.x, y: status.y } : utils.extend({}, modifiedCoords); + var inner = rectUtils.xywhToTlbr(getRestrictionRect(options.inner, interaction, page)) || noInner; + var outer = rectUtils.xywhToTlbr(getRestrictionRect(options.outer, interaction, page)) || noOuter; + + var modifiedX = page.x; + var modifiedY = page.y; + + status.dx = 0; + status.dy = 0; + status.locked = false; + + if (edges.top) { + modifiedY = Math.min(Math.max(outer.top + offset.top, page.y), inner.top + offset.top); + } else if (edges.bottom) { + modifiedY = Math.max(Math.min(outer.bottom - offset.bottom, page.y), inner.bottom - offset.bottom); + } + if (edges.left) { + modifiedX = Math.min(Math.max(outer.left + offset.left, page.x), inner.left + offset.left); + } else if (edges.right) { + modifiedX = Math.max(Math.min(outer.right - offset.right, page.x), inner.right - offset.right); + } + + status.dx = modifiedX - page.x; + status.dy = modifiedY - page.y; + + status.changed = status.modifiedX !== modifiedX || status.modifiedY !== modifiedY; + status.locked = !!(status.dx || status.dy); + + status.modifiedX = modifiedX; + status.modifiedY = modifiedY; + }, + + modifyCoords: function modifyCoords(_ref3) { + var page = _ref3.page, + client = _ref3.client, + status = _ref3.status, + phase = _ref3.phase, + options = _ref3.options; + + if (options && options.enabled && !(phase === 'start' && status.locked)) { + + if (status.locked) { + page.x += status.dx; + page.y += status.dy; + client.x += status.dx; + client.y += status.dy; + + return { + dx: status.dx, + dy: status.dy + }; + } + } + }, + + noInner: noInner, + noOuter: noOuter, + getRestrictionRect: getRestrictionRect +}; + +modifiers.restrictEdges = restrictEdges; +modifiers.names.push('restrictEdges'); + +defaultOptions.perAction.restrictEdges = restrictEdges.defaults; +resize.defaults.restrictEdges = restrictEdges.defaults; + +module.exports = restrictEdges; + +},{"../actions/resize":10,"../defaultOptions":18,"../utils":44,"../utils/rect":51,"./base":23,"./restrict":24}],26:[function(require,module,exports){ +'use strict'; + +// This module adds the options.resize.restrictSize setting which sets min and +// max width and height for the target being resized. +// +// interact(target).resize({ +// edges: { top: true, left: true }, +// restrictSize: { +// min: { width: -600, height: -600 }, +// max: { width: 600, height: 600 }, +// }, +// }); + +var modifiers = require('./base'); +var restrictEdges = require('./restrictEdges'); +var utils = require('../utils'); +var rectUtils = require('../utils/rect'); +var defaultOptions = require('../defaultOptions'); +var resize = require('../actions/resize'); + +var noMin = { width: -Infinity, height: -Infinity }; +var noMax = { width: +Infinity, height: +Infinity }; + +var restrictSize = { + defaults: { + enabled: false, + endOnly: false, + min: null, + max: null + }, + + setOffset: function setOffset(_ref) { + var interaction = _ref.interaction; + + return interaction.startOffset; + }, + + set: function set(arg) { + var interaction = arg.interaction, + options = arg.options; + + var edges = interaction.prepared.linkedEdges || interaction.prepared.edges; + + if (!interaction.interacting() || !edges) { + return; + } + + var rect = rectUtils.xywhToTlbr(interaction.resizeRects.inverted); + + var minSize = rectUtils.tlbrToXywh(restrictEdges.getRestrictionRect(options.min, interaction)) || noMin; + var maxSize = rectUtils.tlbrToXywh(restrictEdges.getRestrictionRect(options.max, interaction)) || noMax; + + arg.options = { + enabled: options.enabled, + endOnly: options.endOnly, + inner: utils.extend({}, restrictEdges.noInner), + outer: utils.extend({}, restrictEdges.noOuter) + }; + + if (edges.top) { + arg.options.inner.top = rect.bottom - minSize.height; + arg.options.outer.top = rect.bottom - maxSize.height; + } else if (edges.bottom) { + arg.options.inner.bottom = rect.top + minSize.height; + arg.options.outer.bottom = rect.top + maxSize.height; + } + if (edges.left) { + arg.options.inner.left = rect.right - minSize.width; + arg.options.outer.left = rect.right - maxSize.width; + } else if (edges.right) { + arg.options.inner.right = rect.left + minSize.width; + arg.options.outer.right = rect.left + maxSize.width; + } + + restrictEdges.set(arg); + }, + + modifyCoords: restrictEdges.modifyCoords +}; + +modifiers.restrictSize = restrictSize; +modifiers.names.push('restrictSize'); + +defaultOptions.perAction.restrictSize = restrictSize.defaults; +resize.defaults.restrictSize = restrictSize.defaults; + +module.exports = restrictSize; + +},{"../actions/resize":10,"../defaultOptions":18,"../utils":44,"../utils/rect":51,"./base":23,"./restrictEdges":25}],27:[function(require,module,exports){ +'use strict'; + +var modifiers = require('./base'); +var interact = require('../interact'); +var utils = require('../utils'); +var defaultOptions = require('../defaultOptions'); + +var snap = { + defaults: { + enabled: false, + endOnly: false, + range: Infinity, + targets: null, + offsets: null, + + relativePoints: null + }, + + setOffset: function setOffset(_ref) { + var interaction = _ref.interaction, + interactable = _ref.interactable, + element = _ref.element, + rect = _ref.rect, + startOffset = _ref.startOffset, + options = _ref.options; + + var offsets = []; + var optionsOrigin = utils.rectToXY(utils.resolveRectLike(options.origin)); + var origin = optionsOrigin || utils.getOriginXY(interactable, element, interaction.prepared.name); + options = options || interactable.options[interaction.prepared.name].snap || {}; + + var snapOffset = void 0; + + if (options.offset === 'startCoords') { + snapOffset = { + x: interaction.startCoords.page.x - origin.x, + y: interaction.startCoords.page.y - origin.y + }; + } else { + var offsetRect = utils.resolveRectLike(options.offset, interactable, element, [interaction]); + + snapOffset = utils.rectToXY(offsetRect) || { x: 0, y: 0 }; + } + + if (rect && options.relativePoints && options.relativePoints.length) { + for (var _i = 0; _i < options.relativePoints.length; _i++) { + var _ref3; + + _ref3 = options.relativePoints[_i]; + var _ref2 = _ref3; + var relativeX = _ref2.x; + var relativeY = _ref2.y; + + offsets.push({ + x: startOffset.left - rect.width * relativeX + snapOffset.x, + y: startOffset.top - rect.height * relativeY + snapOffset.y + }); + } + } else { + offsets.push(snapOffset); + } + + return offsets; + }, + + set: function set(_ref4) { + var interaction = _ref4.interaction, + modifiedCoords = _ref4.modifiedCoords, + status = _ref4.status, + options = _ref4.options, + offsets = _ref4.offset; + + var targets = []; + var target = void 0; + var page = void 0; + var i = void 0; + + if (status.useStatusXY) { + page = { x: status.x, y: status.y }; + } else { + var origin = utils.getOriginXY(interaction.target, interaction.element, interaction.prepared.name); + + page = utils.extend({}, modifiedCoords); + + page.x -= origin.x; + page.y -= origin.y; + } + + status.realX = page.x; + status.realY = page.y; + + var len = options.targets ? options.targets.length : 0; + + for (var _i2 = 0; _i2 < offsets.length; _i2++) { + var _ref6; + + _ref6 = offsets[_i2]; + var _ref5 = _ref6; + var offsetX = _ref5.x; + var offsetY = _ref5.y; + + var relativeX = page.x - offsetX; + var relativeY = page.y - offsetY; + + for (var _i3 = 0; _i3 < (options.targets || []).length; _i3++) { + var _ref7; + + _ref7 = (options.targets || [])[_i3]; + var snapTarget = _ref7; + + if (utils.is.function(snapTarget)) { + target = snapTarget(relativeX, relativeY, interaction); + } else { + target = snapTarget; + } + + if (!target) { + continue; + } + + targets.push({ + x: utils.is.number(target.x) ? target.x + offsetX : relativeX, + y: utils.is.number(target.y) ? target.y + offsetY : relativeY, + + range: utils.is.number(target.range) ? target.range : options.range + }); + } + } + + var closest = { + target: null, + inRange: false, + distance: 0, + range: 0, + dx: 0, + dy: 0 + }; + + for (i = 0, len = targets.length; i < len; i++) { + target = targets[i]; + + var range = target.range; + var dx = target.x - page.x; + var dy = target.y - page.y; + var distance = utils.hypot(dx, dy); + var inRange = distance <= range; + + // Infinite targets count as being out of range + // compared to non infinite ones that are in range + if (range === Infinity && closest.inRange && closest.range !== Infinity) { + inRange = false; + } + + if (!closest.target || (inRange + // is the closest target in range? + ? closest.inRange && range !== Infinity + // the pointer is relatively deeper in this target + ? distance / range < closest.distance / closest.range + // this target has Infinite range and the closest doesn't + : range === Infinity && closest.range !== Infinity || + // OR this target is closer that the previous closest + distance < closest.distance : + // The other is not in range and the pointer is closer to this target + !closest.inRange && distance < closest.distance)) { + + closest.target = target; + closest.distance = distance; + closest.range = range; + closest.inRange = inRange; + closest.dx = dx; + closest.dy = dy; + + status.range = range; + } + } + + var snapChanged = void 0; + + if (closest.target) { + snapChanged = status.modifiedX !== closest.target.x || status.modifiedY !== closest.target.y; + + status.modifiedX = closest.target.x; + status.modifiedY = closest.target.y; + } else { + snapChanged = true; + + status.modifiedX = NaN; + status.modifiedY = NaN; + } + + status.dx = closest.dx; + status.dy = closest.dy; + + status.changed = snapChanged || closest.inRange && !status.locked; + status.locked = closest.inRange; + }, + + modifyCoords: function modifyCoords(_ref8) { + var page = _ref8.page, + client = _ref8.client, + status = _ref8.status, + phase = _ref8.phase, + options = _ref8.options; + + var relativePoints = options && options.relativePoints; + + if (options && options.enabled && !(phase === 'start' && relativePoints && relativePoints.length)) { + + if (status.locked) { + page.x += status.dx; + page.y += status.dy; + client.x += status.dx; + client.y += status.dy; + } + + return { + range: status.range, + locked: status.locked, + x: status.modifiedX, + y: status.modifiedY, + realX: status.realX, + realY: status.realY, + dx: status.dx, + dy: status.dy + }; + } + } +}; + +interact.createSnapGrid = function (grid) { + return function (x, y) { + var limits = grid.limits || { + left: -Infinity, + right: Infinity, + top: -Infinity, + bottom: Infinity + }; + var offsetX = 0; + var offsetY = 0; + + if (utils.is.object(grid.offset)) { + offsetX = grid.offset.x; + offsetY = grid.offset.y; + } + + var gridx = Math.round((x - offsetX) / grid.x); + var gridy = Math.round((y - offsetY) / grid.y); + + var newX = Math.max(limits.left, Math.min(limits.right, gridx * grid.x + offsetX)); + var newY = Math.max(limits.top, Math.min(limits.bottom, gridy * grid.y + offsetY)); + + return { + x: newX, + y: newY, + range: grid.range + }; + }; +}; + +modifiers.snap = snap; +modifiers.names.push('snap'); + +defaultOptions.perAction.snap = snap.defaults; + +module.exports = snap; + +},{"../defaultOptions":18,"../interact":21,"../utils":44,"./base":23}],28:[function(require,module,exports){ +'use strict'; + +// This module allows snapping of the size of targets during resize +// interactions. + +var modifiers = require('./base'); +var snap = require('./snap'); +var defaultOptions = require('../defaultOptions'); +var resize = require('../actions/resize'); +var utils = require('../utils/'); + +var snapSize = { + defaults: { + enabled: false, + endOnly: false, + range: Infinity, + targets: null, + offsets: null + }, + + setOffset: function setOffset(arg) { + var interaction = arg.interaction, + options = arg.options; + + var edges = interaction.prepared.edges; + + if (!edges) { + return; + } + + arg.options = { + relativePoints: [{ + x: edges.left ? 0 : 1, + y: edges.top ? 0 : 1 + }], + origin: { x: 0, y: 0 }, + offset: 'self', + range: options.range + }; + + var offsets = snap.setOffset(arg); + arg.options = options; + + return offsets; + }, + + set: function set(arg) { + var interaction = arg.interaction, + options = arg.options, + offset = arg.offset, + modifiedCoords = arg.modifiedCoords; + + var page = utils.extend({}, modifiedCoords); + var relativeX = page.x - offset[0].x; + var relativeY = page.y - offset[0].y; + + arg.options = utils.extend({}, options); + arg.options.targets = []; + + for (var _i = 0; _i < (options.targets || []).length; _i++) { + var _ref; + + _ref = (options.targets || [])[_i]; + var snapTarget = _ref; + + var target = void 0; + + if (utils.is.function(snapTarget)) { + target = snapTarget(relativeX, relativeY, interaction); + } else { + target = snapTarget; + } + + if (!target) { + continue; + } + + if ('width' in target && 'height' in target) { + target.x = target.width; + target.y = target.height; + } + + arg.options.targets.push(target); + } + + snap.set(arg); + }, + + modifyCoords: function modifyCoords(arg) { + var options = arg.options; + + + arg.options = utils.extend({}, options); + arg.options.enabled = options.enabled; + arg.options.relativePoints = [null]; + + snap.modifyCoords(arg); + } +}; + +modifiers.snapSize = snapSize; +modifiers.names.push('snapSize'); + +defaultOptions.perAction.snapSize = snapSize.defaults; +resize.defaults.snapSize = snapSize.defaults; + +module.exports = snapSize; + +},{"../actions/resize":10,"../defaultOptions":18,"../utils/":44,"./base":23,"./snap":27}],29:[function(require,module,exports){ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var pointerUtils = require('../utils/pointerUtils'); + +module.exports = function () { + /** */ + function PointerEvent(type, pointer, event, eventTarget, interaction) { + _classCallCheck(this, PointerEvent); + + pointerUtils.pointerExtend(this, event); + + if (event !== pointer) { + pointerUtils.pointerExtend(this, pointer); + } + + this.interaction = interaction; + + this.timeStamp = new Date().getTime(); + this.originalEvent = event; + this.type = type; + this.pointerId = pointerUtils.getPointerId(pointer); + this.pointerType = pointerUtils.getPointerType(pointer); + this.target = eventTarget; + this.currentTarget = null; + + if (type === 'tap') { + var pointerIndex = interaction.getPointerIndex(pointer); + this.dt = this.timeStamp - interaction.downTimes[pointerIndex]; + + var interval = this.timeStamp - interaction.tapTime; + + this.double = !!(interaction.prevTap && interaction.prevTap.type !== 'doubletap' && interaction.prevTap.target === this.target && interval < 500); + } else if (type === 'doubletap') { + this.dt = pointer.timeStamp - interaction.tapTime; + } + } + + PointerEvent.prototype.subtractOrigin = function subtractOrigin(_ref) { + var originX = _ref.x, + originY = _ref.y; + + this.pageX -= originX; + this.pageY -= originY; + this.clientX -= originX; + this.clientY -= originY; + + return this; + }; + + PointerEvent.prototype.addOrigin = function addOrigin(_ref2) { + var originX = _ref2.x, + originY = _ref2.y; + + this.pageX += originX; + this.pageY += originY; + this.clientX += originX; + this.clientY += originY; + + return this; + }; + + /** */ + + + PointerEvent.prototype.preventDefault = function preventDefault() { + this.originalEvent.preventDefault(); + }; + + /** */ + + + PointerEvent.prototype.stopPropagation = function stopPropagation() { + this.propagationStopped = true; + }; + + /** */ + + + PointerEvent.prototype.stopImmediatePropagation = function stopImmediatePropagation() { + this.immediatePropagationStopped = this.propagationStopped = true; + }; + + return PointerEvent; +}(); + +},{"../utils/pointerUtils":49}],30:[function(require,module,exports){ +'use strict'; + +var PointerEvent = require('./PointerEvent'); +var Interaction = require('../Interaction'); +var utils = require('../utils'); +var defaults = require('../defaultOptions'); +var signals = require('../utils/Signals').new(); + +var simpleSignals = ['down', 'up', 'cancel']; +var simpleEvents = ['down', 'up', 'cancel']; + +var pointerEvents = { + PointerEvent: PointerEvent, + fire: fire, + collectEventTargets: collectEventTargets, + signals: signals, + defaults: { + holdDuration: 600, + ignoreFrom: null, + allowFrom: null, + origin: { x: 0, y: 0 } + }, + types: ['down', 'move', 'up', 'cancel', 'tap', 'doubletap', 'hold'] +}; + +function fire(arg) { + var interaction = arg.interaction, + pointer = arg.pointer, + event = arg.event, + eventTarget = arg.eventTarget, + _arg$type = arg.type, + type = _arg$type === undefined ? arg.pointerEvent.type : _arg$type, + _arg$targets = arg.targets, + targets = _arg$targets === undefined ? collectEventTargets(arg) : _arg$targets, + _arg$pointerEvent = arg.pointerEvent, + pointerEvent = _arg$pointerEvent === undefined ? new PointerEvent(type, pointer, event, eventTarget, interaction) : _arg$pointerEvent; + + + var signalArg = { + interaction: interaction, + pointer: pointer, + event: event, + eventTarget: eventTarget, + targets: targets, + type: type, + pointerEvent: pointerEvent + }; + + for (var i = 0; i < targets.length; i++) { + var target = targets[i]; + + for (var prop in target.props || {}) { + pointerEvent[prop] = target.props[prop]; + } + + var origin = utils.getOriginXY(target.eventable, target.element); + + pointerEvent.subtractOrigin(origin); + pointerEvent.eventable = target.eventable; + pointerEvent.currentTarget = target.element; + + target.eventable.fire(pointerEvent); + + pointerEvent.addOrigin(origin); + + if (pointerEvent.immediatePropagationStopped || pointerEvent.propagationStopped && i + 1 < targets.length && targets[i + 1].element !== pointerEvent.currentTarget) { + break; + } + } + + signals.fire('fired', signalArg); + + if (type === 'tap') { + // if pointerEvent should make a double tap, create and fire a doubletap + // PointerEvent and use that as the prevTap + var prevTap = pointerEvent.double ? fire({ + interaction: interaction, pointer: pointer, event: event, eventTarget: eventTarget, + type: 'doubletap' + }) : pointerEvent; + + interaction.prevTap = prevTap; + interaction.tapTime = prevTap.timeStamp; + } + + return pointerEvent; +} + +function collectEventTargets(_ref) { + var interaction = _ref.interaction, + pointer = _ref.pointer, + event = _ref.event, + eventTarget = _ref.eventTarget, + type = _ref.type; + + var pointerIndex = interaction.getPointerIndex(pointer); + + // do not fire a tap event if the pointer was moved before being lifted + if (type === 'tap' && (interaction.pointerWasMoved + // or if the pointerup target is different to the pointerdown target + || !(interaction.downTargets[pointerIndex] && interaction.downTargets[pointerIndex] === eventTarget))) { + return []; + } + + var path = utils.getPath(eventTarget); + var signalArg = { + interaction: interaction, + pointer: pointer, + event: event, + eventTarget: eventTarget, + type: type, + path: path, + targets: [], + element: null + }; + + for (var _i = 0; _i < path.length; _i++) { + var _ref2; + + _ref2 = path[_i]; + var element = _ref2; + + signalArg.element = element; + + signals.fire('collect-targets', signalArg); + } + + if (type === 'hold') { + signalArg.targets = signalArg.targets.filter(function (target) { + return target.eventable.options.holdDuration === interaction.holdTimers[pointerIndex].duration; + }); + } + + return signalArg.targets; +} + +Interaction.signals.on('update-pointer-down', function (_ref3) { + var interaction = _ref3.interaction, + pointerIndex = _ref3.pointerIndex; + + interaction.holdTimers[pointerIndex] = { duration: Infinity, timeout: null }; +}); + +Interaction.signals.on('remove-pointer', function (_ref4) { + var interaction = _ref4.interaction, + pointerIndex = _ref4.pointerIndex; + + interaction.holdTimers.splice(pointerIndex, 1); +}); + +Interaction.signals.on('move', function (_ref5) { + var interaction = _ref5.interaction, + pointer = _ref5.pointer, + event = _ref5.event, + eventTarget = _ref5.eventTarget, + duplicateMove = _ref5.duplicateMove; + + var pointerIndex = interaction.getPointerIndex(pointer); + + if (!duplicateMove && (!interaction.pointerIsDown || interaction.pointerWasMoved)) { + if (interaction.pointerIsDown) { + clearTimeout(interaction.holdTimers[pointerIndex].timeout); + } + + fire({ + interaction: interaction, pointer: pointer, event: event, eventTarget: eventTarget, + type: 'move' + }); + } +}); + +Interaction.signals.on('down', function (_ref6) { + var interaction = _ref6.interaction, + pointer = _ref6.pointer, + event = _ref6.event, + eventTarget = _ref6.eventTarget, + pointerIndex = _ref6.pointerIndex; + + var timer = interaction.holdTimers[pointerIndex]; + var path = utils.getPath(eventTarget); + var signalArg = { + interaction: interaction, + pointer: pointer, + event: event, + eventTarget: eventTarget, + type: 'hold', + targets: [], + path: path, + element: null + }; + + for (var _i2 = 0; _i2 < path.length; _i2++) { + var _ref7; + + _ref7 = path[_i2]; + var element = _ref7; + + signalArg.element = element; + + signals.fire('collect-targets', signalArg); + } + + if (!signalArg.targets.length) { + return; + } + + var minDuration = Infinity; + + for (var _i3 = 0; _i3 < signalArg.targets.length; _i3++) { + var _ref8; + + _ref8 = signalArg.targets[_i3]; + var target = _ref8; + + var holdDuration = target.eventable.options.holdDuration; + + if (holdDuration < minDuration) { + minDuration = holdDuration; + } + } + + timer.duration = minDuration; + timer.timeout = setTimeout(function () { + fire({ + interaction: interaction, + eventTarget: eventTarget, + pointer: pointer, + event: event, + type: 'hold' + }); + }, minDuration); +}); + +Interaction.signals.on('up', function (_ref9) { + var interaction = _ref9.interaction, + pointer = _ref9.pointer, + event = _ref9.event, + eventTarget = _ref9.eventTarget; + + if (!interaction.pointerWasMoved) { + fire({ interaction: interaction, eventTarget: eventTarget, pointer: pointer, event: event, type: 'tap' }); + } +}); + +var _arr = ['up', 'cancel']; +for (var _i4 = 0; _i4 < _arr.length; _i4++) { + var signalName = _arr[_i4]; + Interaction.signals.on(signalName, function (_ref11) { + var interaction = _ref11.interaction, + pointerIndex = _ref11.pointerIndex; + + if (interaction.holdTimers[pointerIndex]) { + clearTimeout(interaction.holdTimers[pointerIndex].timeout); + } + }); +} + +function createSignalListener(type) { + return function (_ref10) { + var interaction = _ref10.interaction, + pointer = _ref10.pointer, + event = _ref10.event, + eventTarget = _ref10.eventTarget; + + fire({ interaction: interaction, eventTarget: eventTarget, pointer: pointer, event: event, type: type }); + }; +} + +for (var i = 0; i < simpleSignals.length; i++) { + Interaction.signals.on(simpleSignals[i], createSignalListener(simpleEvents[i])); +} + +Interaction.signals.on('new', function (interaction) { + interaction.prevTap = null; // the most recent tap event on this interaction + interaction.tapTime = 0; // time of the most recent tap event + interaction.holdTimers = []; // [{ duration, timeout }] +}); + +defaults.pointerEvents = pointerEvents.defaults; +module.exports = pointerEvents; + +},{"../Interaction":5,"../defaultOptions":18,"../utils":44,"../utils/Signals":34,"./PointerEvent":29}],31:[function(require,module,exports){ +'use strict'; + +var pointerEvents = require('./base'); +var Interaction = require('../Interaction'); + +pointerEvents.signals.on('new', onNew); +pointerEvents.signals.on('fired', onFired); + +var _arr = ['move', 'up', 'cancel', 'endall']; +for (var _i = 0; _i < _arr.length; _i++) { + var signal = _arr[_i]; + Interaction.signals.on(signal, endHoldRepeat); +} + +function onNew(_ref) { + var pointerEvent = _ref.pointerEvent; + + if (pointerEvent.type !== 'hold') { + return; + } + + pointerEvent.count = (pointerEvent.count || 0) + 1; +} + +function onFired(_ref2) { + var interaction = _ref2.interaction, + pointerEvent = _ref2.pointerEvent, + eventTarget = _ref2.eventTarget, + targets = _ref2.targets; + + if (pointerEvent.type !== 'hold' || !targets.length) { + return; + } + + // get the repeat interval from the first eventable + var interval = targets[0].eventable.options.holdRepeatInterval; + + // don't repeat if the interval is 0 or less + if (interval <= 0) { + return; + } + + // set a timeout to fire the holdrepeat event + interaction.holdIntervalHandle = setTimeout(function () { + pointerEvents.fire({ + interaction: interaction, + eventTarget: eventTarget, + type: 'hold', + pointer: pointerEvent, + event: pointerEvent + }); + }, interval); +} + +function endHoldRepeat(_ref3) { + var interaction = _ref3.interaction; + + // set the interaction's holdStopTime property + // to stop further holdRepeat events + if (interaction.holdIntervalHandle) { + clearInterval(interaction.holdIntervalHandle); + interaction.holdIntervalHandle = null; + } +} + +// don't repeat by default +pointerEvents.defaults.holdRepeatInterval = 0; +pointerEvents.types.push('holdrepeat'); + +module.exports = { + onNew: onNew, + onFired: onFired, + endHoldRepeat: endHoldRepeat +}; + +},{"../Interaction":5,"./base":30}],32:[function(require,module,exports){ +'use strict'; + +var pointerEvents = require('./base'); +var Interactable = require('../Interactable'); +var is = require('../utils/is'); +var scope = require('../scope'); +var extend = require('../utils/extend'); + +var _require = require('../utils/arr'), + merge = _require.merge; + +pointerEvents.signals.on('collect-targets', function (_ref) { + var targets = _ref.targets, + element = _ref.element, + type = _ref.type, + eventTarget = _ref.eventTarget; + + scope.interactables.forEachMatch(element, function (interactable) { + var eventable = interactable.events; + var options = eventable.options; + + if (eventable[type] && is.element(element) && interactable.testIgnoreAllow(options, element, eventTarget)) { + + targets.push({ + element: element, + eventable: eventable, + props: { interactable: interactable } + }); + } + }); +}); + +Interactable.signals.on('new', function (_ref2) { + var interactable = _ref2.interactable; + + interactable.events.getRect = function (element) { + return interactable.getRect(element); + }; +}); + +Interactable.signals.on('set', function (_ref3) { + var interactable = _ref3.interactable, + options = _ref3.options; + + extend(interactable.events.options, pointerEvents.defaults); + extend(interactable.events.options, options); +}); + +merge(Interactable.eventTypes, pointerEvents.types); + +Interactable.prototype.pointerEvents = function (options) { + extend(this.events.options, options); + + return this; +}; + +var __backCompatOption = Interactable.prototype._backCompatOption; + +Interactable.prototype._backCompatOption = function (optionName, newValue) { + var ret = __backCompatOption.call(this, optionName, newValue); + + if (ret === this) { + this.events.options[optionName] = newValue; + } + + return ret; +}; + +Interactable.settingsMethods.push('pointerEvents'); + +},{"../Interactable":4,"../scope":33,"../utils/arr":35,"../utils/extend":41,"../utils/is":46,"./base":30}],33:[function(require,module,exports){ +'use strict'; + +var utils = require('./utils'); +var events = require('./utils/events'); +var signals = require('./utils/Signals').new(); + +var _require = require('./utils/window'), + getWindow = _require.getWindow; + +var scope = { + signals: signals, + events: events, + utils: utils, + + // main document + document: require('./utils/domObjects').document, + // all documents being listened to + documents: [], + + addDocument: function addDocument(doc, win) { + // do nothing if document is already known + if (utils.contains(scope.documents, doc)) { + return false; + } + + win = win || getWindow(doc); + + scope.documents.push(doc); + events.documents.push(doc); + + // don't add an unload event for the main document + // so that the page may be cached in browser history + if (doc !== scope.document) { + events.add(win, 'unload', scope.onWindowUnload); + } + + signals.fire('add-document', { doc: doc, win: win }); + }, + + removeDocument: function removeDocument(doc, win) { + var index = scope.documents.indexOf(doc); + + win = win || getWindow(doc); + + events.remove(win, 'unload', scope.onWindowUnload); + + scope.documents.splice(index, 1); + events.documents.splice(index, 1); + + signals.fire('remove-document', { win: win, doc: doc }); + }, + + onWindowUnload: function onWindowUnload() { + scope.removeDocument(this.document, this); + } +}; + +module.exports = scope; + +},{"./utils":44,"./utils/Signals":34,"./utils/domObjects":38,"./utils/events":40,"./utils/window":52}],34:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Signals = function () { + function Signals() { + _classCallCheck(this, Signals); + + this.listeners = { + // signalName: [listeners], + }; + } + + Signals.prototype.on = function on(name, listener) { + if (!this.listeners[name]) { + this.listeners[name] = [listener]; + return; + } + + this.listeners[name].push(listener); + }; + + Signals.prototype.off = function off(name, listener) { + if (!this.listeners[name]) { + return; + } + + var index = this.listeners[name].indexOf(listener); + + if (index !== -1) { + this.listeners[name].splice(index, 1); + } + }; + + Signals.prototype.fire = function fire(name, arg) { + var targetListeners = this.listeners[name]; + + if (!targetListeners) { + return; + } + + for (var _i = 0; _i < targetListeners.length; _i++) { + var _ref; + + _ref = targetListeners[_i]; + var listener = _ref; + + if (listener(arg, name) === false) { + return; + } + } + }; + + return Signals; +}(); + +Signals.new = function () { + return new Signals(); +}; + +module.exports = Signals; + +},{}],35:[function(require,module,exports){ +"use strict"; + +function contains(array, target) { + return array.indexOf(target) !== -1; +} + +function merge(target, source) { + for (var _i = 0; _i < source.length; _i++) { + var _ref; + + _ref = source[_i]; + var item = _ref; + + target.push(item); + } + + return target; +} + +module.exports = { + contains: contains, + merge: merge +}; + +},{}],36:[function(require,module,exports){ +'use strict'; + +var _require = require('./window'), + window = _require.window; + +var is = require('./is'); +var domObjects = require('./domObjects'); + +var Element = domObjects.Element; +var navigator = window.navigator; + +var browser = { + // Does the browser support touch input? + supportsTouch: !!('ontouchstart' in window || is.function(window.DocumentTouch) && domObjects.document instanceof window.DocumentTouch), + + // Does the browser support PointerEvents + supportsPointerEvent: !!domObjects.PointerEvent, + + isIOS: /iP(hone|od|ad)/.test(navigator.platform), + + // scrolling doesn't change the result of getClientRects on iOS 7 + isIOS7: /iP(hone|od|ad)/.test(navigator.platform) && /OS 7[^\d]/.test(navigator.appVersion), + + isIe9: /MSIE 9/.test(navigator.userAgent), + + // prefix matchesSelector + prefixedMatchesSelector: 'matches' in Element.prototype ? 'matches' : 'webkitMatchesSelector' in Element.prototype ? 'webkitMatchesSelector' : 'mozMatchesSelector' in Element.prototype ? 'mozMatchesSelector' : 'oMatchesSelector' in Element.prototype ? 'oMatchesSelector' : 'msMatchesSelector', + + pEventTypes: domObjects.PointerEvent ? domObjects.PointerEvent === window.MSPointerEvent ? { + up: 'MSPointerUp', + down: 'MSPointerDown', + over: 'mouseover', + out: 'mouseout', + move: 'MSPointerMove', + cancel: 'MSPointerCancel' + } : { + up: 'pointerup', + down: 'pointerdown', + over: 'pointerover', + out: 'pointerout', + move: 'pointermove', + cancel: 'pointercancel' + } : null, + + // because Webkit and Opera still use 'mousewheel' event type + wheelEvent: 'onmousewheel' in domObjects.document ? 'mousewheel' : 'wheel' + +}; + +// Opera Mobile must be handled differently +browser.isOperaMobile = navigator.appName === 'Opera' && browser.supportsTouch && navigator.userAgent.match('Presto'); + +module.exports = browser; + +},{"./domObjects":38,"./is":46,"./window":52}],37:[function(require,module,exports){ +'use strict'; + +var is = require('./is'); + +module.exports = function clone(source) { + var dest = {}; + for (var prop in source) { + if (is.plainObject(source[prop])) { + dest[prop] = clone(source[prop]); + } else { + dest[prop] = source[prop]; + } + } + return dest; +}; + +},{"./is":46}],38:[function(require,module,exports){ +'use strict'; + +var domObjects = {}; +var win = require('./window').window; + +function blank() {} + +domObjects.document = win.document; +domObjects.DocumentFragment = win.DocumentFragment || blank; +domObjects.SVGElement = win.SVGElement || blank; +domObjects.SVGSVGElement = win.SVGSVGElement || blank; +domObjects.SVGElementInstance = win.SVGElementInstance || blank; +domObjects.Element = win.Element || blank; +domObjects.HTMLElement = win.HTMLElement || domObjects.Element; + +domObjects.Event = win.Event; +domObjects.Touch = win.Touch || blank; +domObjects.PointerEvent = win.PointerEvent || win.MSPointerEvent; + +module.exports = domObjects; + +},{"./window":52}],39:[function(require,module,exports){ +'use strict'; + +var win = require('./window'); +var browser = require('./browser'); +var is = require('./is'); +var domObjects = require('./domObjects'); + +var domUtils = { + nodeContains: function nodeContains(parent, child) { + while (child) { + if (child === parent) { + return true; + } + + child = child.parentNode; + } + + return false; + }, + + closest: function closest(element, selector) { + while (is.element(element)) { + if (domUtils.matchesSelector(element, selector)) { + return element; + } + + element = domUtils.parentNode(element); + } + + return null; + }, + + parentNode: function parentNode(node) { + var parent = node.parentNode; + + if (is.docFrag(parent)) { + // skip past #shado-root fragments + while ((parent = parent.host) && is.docFrag(parent)) { + continue; + } + + return parent; + } + + return parent; + }, + + matchesSelector: function matchesSelector(element, selector) { + // remove /deep/ from selectors if shadowDOM polyfill is used + if (win.window !== win.realWindow) { + selector = selector.replace(/\/deep\//g, ' '); + } + + return element[browser.prefixedMatchesSelector](selector); + }, + + // Test for the element that's "above" all other qualifiers + indexOfDeepestElement: function indexOfDeepestElement(elements) { + var deepestZoneParents = []; + var dropzoneParents = []; + var dropzone = void 0; + var deepestZone = elements[0]; + var index = deepestZone ? 0 : -1; + var parent = void 0; + var child = void 0; + var i = void 0; + var n = void 0; + + for (i = 1; i < elements.length; i++) { + dropzone = elements[i]; + + // an element might belong to multiple selector dropzones + if (!dropzone || dropzone === deepestZone) { + continue; + } + + if (!deepestZone) { + deepestZone = dropzone; + index = i; + continue; + } + + // check if the deepest or current are document.documentElement or document.rootElement + // - if the current dropzone is, do nothing and continue + if (dropzone.parentNode === dropzone.ownerDocument) { + continue; + } + // - if deepest is, update with the current dropzone and continue to next + else if (deepestZone.parentNode === dropzone.ownerDocument) { + deepestZone = dropzone; + index = i; + continue; + } + + if (!deepestZoneParents.length) { + parent = deepestZone; + while (parent.parentNode && parent.parentNode !== parent.ownerDocument) { + deepestZoneParents.unshift(parent); + parent = parent.parentNode; + } + } + + // if this element is an svg element and the current deepest is + // an HTMLElement + if (deepestZone instanceof domObjects.HTMLElement && dropzone instanceof domObjects.SVGElement && !(dropzone instanceof domObjects.SVGSVGElement)) { + + if (dropzone === deepestZone.parentNode) { + continue; + } + + parent = dropzone.ownerSVGElement; + } else { + parent = dropzone; + } + + dropzoneParents = []; + + while (parent.parentNode !== parent.ownerDocument) { + dropzoneParents.unshift(parent); + parent = parent.parentNode; + } + + n = 0; + + // get (position of last common ancestor) + 1 + while (dropzoneParents[n] && dropzoneParents[n] === deepestZoneParents[n]) { + n++; + } + + var parents = [dropzoneParents[n - 1], dropzoneParents[n], deepestZoneParents[n]]; + + child = parents[0].lastChild; + + while (child) { + if (child === parents[1]) { + deepestZone = dropzone; + index = i; + deepestZoneParents = []; + + break; + } else if (child === parents[2]) { + break; + } + + child = child.previousSibling; + } + } + + return index; + }, + + matchesUpTo: function matchesUpTo(element, selector, limit) { + while (is.element(element)) { + if (domUtils.matchesSelector(element, selector)) { + return true; + } + + element = domUtils.parentNode(element); + + if (element === limit) { + return domUtils.matchesSelector(element, selector); + } + } + + return false; + }, + + getActualElement: function getActualElement(element) { + return element instanceof domObjects.SVGElementInstance ? element.correspondingUseElement : element; + }, + + getScrollXY: function getScrollXY(relevantWindow) { + relevantWindow = relevantWindow || win.window; + return { + x: relevantWindow.scrollX || relevantWindow.document.documentElement.scrollLeft, + y: relevantWindow.scrollY || relevantWindow.document.documentElement.scrollTop + }; + }, + + getElementClientRect: function getElementClientRect(element) { + var clientRect = element instanceof domObjects.SVGElement ? element.getBoundingClientRect() : element.getClientRects()[0]; + + return clientRect && { + left: clientRect.left, + right: clientRect.right, + top: clientRect.top, + bottom: clientRect.bottom, + width: clientRect.width || clientRect.right - clientRect.left, + height: clientRect.height || clientRect.bottom - clientRect.top + }; + }, + + getElementRect: function getElementRect(element) { + var clientRect = domUtils.getElementClientRect(element); + + if (!browser.isIOS7 && clientRect) { + var scroll = domUtils.getScrollXY(win.getWindow(element)); + + clientRect.left += scroll.x; + clientRect.right += scroll.x; + clientRect.top += scroll.y; + clientRect.bottom += scroll.y; + } + + return clientRect; + }, + + getPath: function getPath(element) { + var path = []; + + while (element) { + path.push(element); + element = domUtils.parentNode(element); + } + + return path; + }, + + trySelector: function trySelector(value) { + if (!is.string(value)) { + return false; + } + + // an exception will be raised if it is invalid + domObjects.document.querySelector(value); + return true; + } +}; + +module.exports = domUtils; + +},{"./browser":36,"./domObjects":38,"./is":46,"./window":52}],40:[function(require,module,exports){ +'use strict'; + +var is = require('./is'); +var domUtils = require('./domUtils'); +var pointerUtils = require('./pointerUtils'); +var pExtend = require('./pointerExtend'); + +var _require = require('./window'), + window = _require.window; + +var _require2 = require('./arr'), + contains = _require2.contains; + +var elements = []; +var targets = []; + +// { +// type: { +// selectors: ['selector', ...], +// contexts : [document, ...], +// listeners: [[listener, capture, passive], ...] +// } +// } +var delegatedEvents = {}; +var documents = []; + +var supportsOptions = function () { + var supported = false; + + window.document.createElement('div').addEventListener('test', null, { + get capture() { + supported = true; + } + }); + + return supported; +}(); + +function add(element, type, listener, optionalArg) { + var options = getOptions(optionalArg); + var elementIndex = elements.indexOf(element); + var target = targets[elementIndex]; + + if (!target) { + target = { + events: {}, + typeCount: 0 + }; + + elementIndex = elements.push(element) - 1; + targets.push(target); + } + + if (!target.events[type]) { + target.events[type] = []; + target.typeCount++; + } + + if (!contains(target.events[type], listener)) { + element.addEventListener(type, listener, supportsOptions ? options : !!options.capture); + target.events[type].push(listener); + } +} + +function remove(element, type, listener, optionalArg) { + var options = getOptions(optionalArg); + var elementIndex = elements.indexOf(element); + var target = targets[elementIndex]; + + if (!target || !target.events) { + return; + } + + if (type === 'all') { + for (type in target.events) { + if (target.events.hasOwnProperty(type)) { + remove(element, type, 'all'); + } + } + return; + } + + if (target.events[type]) { + var len = target.events[type].length; + + if (listener === 'all') { + for (var i = 0; i < len; i++) { + remove(element, type, target.events[type][i], options); + } + return; + } else { + for (var _i = 0; _i < len; _i++) { + if (target.events[type][_i] === listener) { + element.removeEventListener('on' + type, listener, supportsOptions ? options : !!options.capture); + target.events[type].splice(_i, 1); + + break; + } + } + } + + if (target.events[type] && target.events[type].length === 0) { + target.events[type] = null; + target.typeCount--; + } + } + + if (!target.typeCount) { + targets.splice(elementIndex, 1); + elements.splice(elementIndex, 1); + } +} + +function addDelegate(selector, context, type, listener, optionalArg) { + var options = getOptions(optionalArg); + if (!delegatedEvents[type]) { + delegatedEvents[type] = { + selectors: [], + contexts: [], + listeners: [] + }; + + // add delegate listener functions + for (var _i2 = 0; _i2 < documents.length; _i2++) { + var doc = documents[_i2]; + add(doc, type, delegateListener); + add(doc, type, delegateUseCapture, true); + } + } + + var delegated = delegatedEvents[type]; + var index = void 0; + + for (index = delegated.selectors.length - 1; index >= 0; index--) { + if (delegated.selectors[index] === selector && delegated.contexts[index] === context) { + break; + } + } + + if (index === -1) { + index = delegated.selectors.length; + + delegated.selectors.push(selector); + delegated.contexts.push(context); + delegated.listeners.push([]); + } + + // keep listener and capture and passive flags + delegated.listeners[index].push([listener, !!options.capture, options.passive]); +} + +function removeDelegate(selector, context, type, listener, optionalArg) { + var options = getOptions(optionalArg); + var delegated = delegatedEvents[type]; + var matchFound = false; + var index = void 0; + + if (!delegated) { + return; + } + + // count from last index of delegated to 0 + for (index = delegated.selectors.length - 1; index >= 0; index--) { + // look for matching selector and context Node + if (delegated.selectors[index] === selector && delegated.contexts[index] === context) { + + var listeners = delegated.listeners[index]; + + // each item of the listeners array is an array: [function, capture, passive] + for (var i = listeners.length - 1; i >= 0; i--) { + var _listeners$i = listeners[i], + fn = _listeners$i[0], + capture = _listeners$i[1], + passive = _listeners$i[2]; + + // check if the listener functions and capture and passive flags match + + if (fn === listener && capture === !!options.capture && passive === options.passive) { + // remove the listener from the array of listeners + listeners.splice(i, 1); + + // if all listeners for this interactable have been removed + // remove the interactable from the delegated arrays + if (!listeners.length) { + delegated.selectors.splice(index, 1); + delegated.contexts.splice(index, 1); + delegated.listeners.splice(index, 1); + + // remove delegate function from context + remove(context, type, delegateListener); + remove(context, type, delegateUseCapture, true); + + // remove the arrays if they are empty + if (!delegated.selectors.length) { + delegatedEvents[type] = null; + } + } + + // only remove one listener + matchFound = true; + break; + } + } + + if (matchFound) { + break; + } + } + } +} + +// bound to the interactable context when a DOM event +// listener is added to a selector interactable +function delegateListener(event, optionalArg) { + var options = getOptions(optionalArg); + var fakeEvent = {}; + var delegated = delegatedEvents[event.type]; + + var _pointerUtils$getEven = pointerUtils.getEventTargets(event), + eventTarget = _pointerUtils$getEven[0]; + + var element = eventTarget; + + // duplicate the event so that currentTarget can be changed + pExtend(fakeEvent, event); + + fakeEvent.originalEvent = event; + fakeEvent.preventDefault = preventOriginalDefault; + + // climb up document tree looking for selector matches + while (is.element(element)) { + for (var i = 0; i < delegated.selectors.length; i++) { + var selector = delegated.selectors[i]; + var context = delegated.contexts[i]; + + if (domUtils.matchesSelector(element, selector) && domUtils.nodeContains(context, eventTarget) && domUtils.nodeContains(context, element)) { + + var listeners = delegated.listeners[i]; + + fakeEvent.currentTarget = element; + + for (var j = 0; j < listeners.length; j++) { + var _listeners$j = listeners[j], + fn = _listeners$j[0], + capture = _listeners$j[1], + passive = _listeners$j[2]; + + + if (capture === !!options.capture && passive === options.passive) { + fn(fakeEvent); + } + } + } + } + + element = domUtils.parentNode(element); + } +} + +function delegateUseCapture(event) { + return delegateListener.call(this, event, true); +} + +function preventOriginalDefault() { + this.originalEvent.preventDefault(); +} + +function getOptions(param) { + return is.object(param) ? param : { capture: param }; +} + +module.exports = { + add: add, + remove: remove, + + addDelegate: addDelegate, + removeDelegate: removeDelegate, + + delegateListener: delegateListener, + delegateUseCapture: delegateUseCapture, + delegatedEvents: delegatedEvents, + documents: documents, + + supportsOptions: supportsOptions, + + _elements: elements, + _targets: targets +}; + +},{"./arr":35,"./domUtils":39,"./is":46,"./pointerExtend":48,"./pointerUtils":49,"./window":52}],41:[function(require,module,exports){ +"use strict"; + +module.exports = function extend(dest, source) { + for (var prop in source) { + dest[prop] = source[prop]; + } + return dest; +}; + +},{}],42:[function(require,module,exports){ +'use strict'; + +var _require = require('./rect'), + resolveRectLike = _require.resolveRectLike, + rectToXY = _require.rectToXY; + +module.exports = function (target, element, action) { + var actionOptions = target.options[action]; + var actionOrigin = actionOptions && actionOptions.origin; + var origin = actionOrigin || target.options.origin; + + var originRect = resolveRectLike(origin, target, element, [target && element]); + + return rectToXY(originRect) || { x: 0, y: 0 }; +}; + +},{"./rect":51}],43:[function(require,module,exports){ +"use strict"; + +module.exports = function (x, y) { + return Math.sqrt(x * x + y * y); +}; + +},{}],44:[function(require,module,exports){ +'use strict'; + +var extend = require('./extend'); +var win = require('./window'); + +var utils = { + warnOnce: function warnOnce(method, message) { + var warned = false; + + return function () { + if (!warned) { + win.window.console.warn(message); + warned = true; + } + + return method.apply(this, arguments); + }; + }, + + // http://stackoverflow.com/a/5634528/2280888 + _getQBezierValue: function _getQBezierValue(t, p1, p2, p3) { + var iT = 1 - t; + return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3; + }, + + getQuadraticCurvePoint: function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) { + return { + x: utils._getQBezierValue(position, startX, cpX, endX), + y: utils._getQBezierValue(position, startY, cpY, endY) + }; + }, + + // http://gizma.com/easing/ + easeOutQuad: function easeOutQuad(t, b, c, d) { + t /= d; + return -c * t * (t - 2) + b; + }, + + copyAction: function copyAction(dest, src) { + dest.name = src.name; + dest.axis = src.axis; + dest.edges = src.edges; + + return dest; + }, + + is: require('./is'), + extend: extend, + hypot: require('./hypot'), + getOriginXY: require('./getOriginXY') +}; + +extend(utils, require('./arr')); +extend(utils, require('./domUtils')); +extend(utils, require('./pointerUtils')); +extend(utils, require('./rect')); + +module.exports = utils; + +},{"./arr":35,"./domUtils":39,"./extend":41,"./getOriginXY":42,"./hypot":43,"./is":46,"./pointerUtils":49,"./rect":51,"./window":52}],45:[function(require,module,exports){ +'use strict'; + +var scope = require('../scope'); +var utils = require('./index'); + +var finder = { + methodOrder: ['simulationResume', 'mouseOrPen', 'hasPointer', 'idle'], + + search: function search(pointer, eventType, eventTarget) { + var pointerType = utils.getPointerType(pointer); + var pointerId = utils.getPointerId(pointer); + var details = { pointer: pointer, pointerId: pointerId, pointerType: pointerType, eventType: eventType, eventTarget: eventTarget }; + + for (var _i = 0; _i < finder.methodOrder.length; _i++) { + var _ref; + + _ref = finder.methodOrder[_i]; + var method = _ref; + + var interaction = finder[method](details); + + if (interaction) { + return interaction; + } + } + }, + + // try to resume simulation with a new pointer + simulationResume: function simulationResume(_ref2) { + var pointerType = _ref2.pointerType, + eventType = _ref2.eventType, + eventTarget = _ref2.eventTarget; + + if (!/down|start/i.test(eventType)) { + return null; + } + + for (var _i2 = 0; _i2 < scope.interactions.length; _i2++) { + var _ref3; + + _ref3 = scope.interactions[_i2]; + var interaction = _ref3; + + var element = eventTarget; + + if (interaction.simulation && interaction.simulation.allowResume && interaction.pointerType === pointerType) { + while (element) { + // if the element is the interaction element + if (element === interaction.element) { + return interaction; + } + element = utils.parentNode(element); + } + } + } + + return null; + }, + + // if it's a mouse or pen interaction + mouseOrPen: function mouseOrPen(_ref4) { + var pointerId = _ref4.pointerId, + pointerType = _ref4.pointerType, + eventType = _ref4.eventType; + + if (pointerType !== 'mouse' && pointerType !== 'pen') { + return null; + } + + var firstNonActive = void 0; + + for (var _i3 = 0; _i3 < scope.interactions.length; _i3++) { + var _ref5; + + _ref5 = scope.interactions[_i3]; + var interaction = _ref5; + + if (interaction.pointerType === pointerType) { + // if it's a down event, skip interactions with running simulations + if (interaction.simulation && !utils.contains(interaction.pointerIds, pointerId)) { + continue; + } + + // if the interaction is active, return it immediately + if (interaction.interacting()) { + return interaction; + } + // otherwise save it and look for another active interaction + else if (!firstNonActive) { + firstNonActive = interaction; + } + } + } + + // if no active mouse interaction was found use the first inactive mouse + // interaction + if (firstNonActive) { + return firstNonActive; + } + + // find any mouse or pen interaction. + // ignore the interaction if the eventType is a *down, and a simulation + // is active + for (var _i4 = 0; _i4 < scope.interactions.length; _i4++) { + var _ref6; + + _ref6 = scope.interactions[_i4]; + var _interaction = _ref6; + + if (_interaction.pointerType === pointerType && !(/down/i.test(eventType) && _interaction.simulation)) { + return _interaction; + } + } + + return null; + }, + + // get interaction that has this pointer + hasPointer: function hasPointer(_ref7) { + var pointerId = _ref7.pointerId; + + for (var _i5 = 0; _i5 < scope.interactions.length; _i5++) { + var _ref8; + + _ref8 = scope.interactions[_i5]; + var interaction = _ref8; + + if (utils.contains(interaction.pointerIds, pointerId)) { + return interaction; + } + } + }, + + // get first idle interaction with a matching pointerType + idle: function idle(_ref9) { + var pointerType = _ref9.pointerType; + + for (var _i6 = 0; _i6 < scope.interactions.length; _i6++) { + var _ref10; + + _ref10 = scope.interactions[_i6]; + var interaction = _ref10; + + // if there's already a pointer held down + if (interaction.pointerIds.length === 1) { + var target = interaction.target; + // don't add this pointer if there is a target interactable and it + // isn't gesturable + if (target && !target.options.gesture.enabled) { + continue; + } + } + // maximum of 2 pointers per interaction + else if (interaction.pointerIds.length >= 2) { + continue; + } + + if (!interaction.interacting() && pointerType === interaction.pointerType) { + return interaction; + } + } + + return null; + } +}; + +module.exports = finder; + +},{"../scope":33,"./index":44}],46:[function(require,module,exports){ +'use strict'; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var win = require('./window'); +var isWindow = require('./isWindow'); + +var is = { + array: function array() {}, + + window: function window(thing) { + return thing === win.window || isWindow(thing); + }, + + docFrag: function docFrag(thing) { + return is.object(thing) && thing.nodeType === 11; + }, + + object: function object(thing) { + return !!thing && (typeof thing === 'undefined' ? 'undefined' : _typeof(thing)) === 'object'; + }, + + function: function _function(thing) { + return typeof thing === 'function'; + }, + + number: function number(thing) { + return typeof thing === 'number'; + }, + + bool: function bool(thing) { + return typeof thing === 'boolean'; + }, + + string: function string(thing) { + return typeof thing === 'string'; + }, + + element: function element(thing) { + if (!thing || (typeof thing === 'undefined' ? 'undefined' : _typeof(thing)) !== 'object') { + return false; + } + + var _window = win.getWindow(thing) || win.window; + + return (/object|function/.test(_typeof(_window.Element)) ? thing instanceof _window.Element //DOM2 + : thing.nodeType === 1 && typeof thing.nodeName === 'string' + ); + }, + + plainObject: function plainObject(thing) { + return is.object(thing) && thing.constructor.name === 'Object'; + } +}; + +is.array = function (thing) { + return is.object(thing) && typeof thing.length !== 'undefined' && is.function(thing.splice); +}; + +module.exports = is; + +},{"./isWindow":47,"./window":52}],47:[function(require,module,exports){ +"use strict"; + +module.exports = function (thing) { + return !!(thing && thing.Window) && thing instanceof thing.Window; +}; + +},{}],48:[function(require,module,exports){ +'use strict'; + +function pointerExtend(dest, source) { + for (var prop in source) { + var prefixedPropREs = module.exports.prefixedPropREs; + var deprecated = false; + + // skip deprecated prefixed properties + for (var vendor in prefixedPropREs) { + if (prop.indexOf(vendor) === 0 && prefixedPropREs[vendor].test(prop)) { + deprecated = true; + break; + } + } + + if (!deprecated && typeof source[prop] !== 'function') { + dest[prop] = source[prop]; + } + } + return dest; +} + +pointerExtend.prefixedPropREs = { + webkit: /(Movement[XY]|Radius[XY]|RotationAngle|Force)$/ +}; + +module.exports = pointerExtend; + +},{}],49:[function(require,module,exports){ +'use strict'; + +var hypot = require('./hypot'); +var browser = require('./browser'); +var dom = require('./domObjects'); +var domUtils = require('./domUtils'); +var domObjects = require('./domObjects'); +var is = require('./is'); +var pointerExtend = require('./pointerExtend'); + +var pointerUtils = { + copyCoords: function copyCoords(dest, src) { + dest.page = dest.page || {}; + dest.page.x = src.page.x; + dest.page.y = src.page.y; + + dest.client = dest.client || {}; + dest.client.x = src.client.x; + dest.client.y = src.client.y; + + dest.timeStamp = src.timeStamp; + }, + + setCoordDeltas: function setCoordDeltas(targetObj, prev, cur) { + targetObj.page.x = cur.page.x - prev.page.x; + targetObj.page.y = cur.page.y - prev.page.y; + targetObj.client.x = cur.client.x - prev.client.x; + targetObj.client.y = cur.client.y - prev.client.y; + targetObj.timeStamp = cur.timeStamp - prev.timeStamp; + + // set pointer velocity + var dt = Math.max(targetObj.timeStamp / 1000, 0.001); + + targetObj.page.speed = hypot(targetObj.page.x, targetObj.page.y) / dt; + targetObj.page.vx = targetObj.page.x / dt; + targetObj.page.vy = targetObj.page.y / dt; + + targetObj.client.speed = hypot(targetObj.client.x, targetObj.page.y) / dt; + targetObj.client.vx = targetObj.client.x / dt; + targetObj.client.vy = targetObj.client.y / dt; + }, + + isNativePointer: function isNativePointer(pointer) { + return pointer instanceof dom.Event || pointer instanceof dom.Touch; + }, + + // Get specified X/Y coords for mouse or event.touches[0] + getXY: function getXY(type, pointer, xy) { + xy = xy || {}; + type = type || 'page'; + + xy.x = pointer[type + 'X']; + xy.y = pointer[type + 'Y']; + + return xy; + }, + + getPageXY: function getPageXY(pointer, page) { + page = page || {}; + + // Opera Mobile handles the viewport and scrolling oddly + if (browser.isOperaMobile && pointerUtils.isNativePointer(pointer)) { + pointerUtils.getXY('screen', pointer, page); + + page.x += window.scrollX; + page.y += window.scrollY; + } else { + pointerUtils.getXY('page', pointer, page); + } + + return page; + }, + + getClientXY: function getClientXY(pointer, client) { + client = client || {}; + + if (browser.isOperaMobile && pointerUtils.isNativePointer(pointer)) { + // Opera Mobile handles the viewport and scrolling oddly + pointerUtils.getXY('screen', pointer, client); + } else { + pointerUtils.getXY('client', pointer, client); + } + + return client; + }, + + getPointerId: function getPointerId(pointer) { + return is.number(pointer.pointerId) ? pointer.pointerId : pointer.identifier; + }, + + setCoords: function setCoords(targetObj, pointers, timeStamp) { + var pointer = pointers.length > 1 ? pointerUtils.pointerAverage(pointers) : pointers[0]; + + var tmpXY = {}; + + pointerUtils.getPageXY(pointer, tmpXY); + targetObj.page.x = tmpXY.x; + targetObj.page.y = tmpXY.y; + + pointerUtils.getClientXY(pointer, tmpXY); + targetObj.client.x = tmpXY.x; + targetObj.client.y = tmpXY.y; + + targetObj.timeStamp = is.number(timeStamp) ? timeStamp : new Date().getTime(); + }, + + pointerExtend: pointerExtend, + + getTouchPair: function getTouchPair(event) { + var touches = []; + + // array of touches is supplied + if (is.array(event)) { + touches[0] = event[0]; + touches[1] = event[1]; + } + // an event + else { + if (event.type === 'touchend') { + if (event.touches.length === 1) { + touches[0] = event.touches[0]; + touches[1] = event.changedTouches[0]; + } else if (event.touches.length === 0) { + touches[0] = event.changedTouches[0]; + touches[1] = event.changedTouches[1]; + } + } else { + touches[0] = event.touches[0]; + touches[1] = event.touches[1]; + } + } + + return touches; + }, + + pointerAverage: function pointerAverage(pointers) { + var average = { + pageX: 0, + pageY: 0, + clientX: 0, + clientY: 0, + screenX: 0, + screenY: 0 + }; + + for (var _i = 0; _i < pointers.length; _i++) { + var _ref; + + _ref = pointers[_i]; + var pointer = _ref; + + for (var _prop in average) { + average[_prop] += pointer[_prop]; + } + } + for (var prop in average) { + average[prop] /= pointers.length; + } + + return average; + }, + + touchBBox: function touchBBox(event) { + if (!event.length && !(event.touches && event.touches.length > 1)) { + return; + } + + var touches = pointerUtils.getTouchPair(event); + var minX = Math.min(touches[0].pageX, touches[1].pageX); + var minY = Math.min(touches[0].pageY, touches[1].pageY); + var maxX = Math.max(touches[0].pageX, touches[1].pageX); + var maxY = Math.max(touches[0].pageY, touches[1].pageY); + + return { + x: minX, + y: minY, + left: minX, + top: minY, + width: maxX - minX, + height: maxY - minY + }; + }, + + touchDistance: function touchDistance(event, deltaSource) { + var sourceX = deltaSource + 'X'; + var sourceY = deltaSource + 'Y'; + var touches = pointerUtils.getTouchPair(event); + + var dx = touches[0][sourceX] - touches[1][sourceX]; + var dy = touches[0][sourceY] - touches[1][sourceY]; + + return hypot(dx, dy); + }, + + touchAngle: function touchAngle(event, prevAngle, deltaSource) { + var sourceX = deltaSource + 'X'; + var sourceY = deltaSource + 'Y'; + var touches = pointerUtils.getTouchPair(event); + var dx = touches[1][sourceX] - touches[0][sourceX]; + var dy = touches[1][sourceY] - touches[0][sourceY]; + var angle = 180 * Math.atan2(dy, dx) / Math.PI; + + return angle; + }, + + getPointerType: function getPointerType(pointer) { + return is.string(pointer.pointerType) ? pointer.pointerType : is.number(pointer.pointerType) ? [undefined, undefined, 'touch', 'pen', 'mouse'][pointer.pointerType] + // if the PointerEvent API isn't available, then the "pointer" must + // be either a MouseEvent, TouchEvent, or Touch object + : /touch/.test(pointer.type) || pointer instanceof domObjects.Touch ? 'touch' : 'mouse'; + }, + + // [ event.target, event.currentTarget ] + getEventTargets: function getEventTargets(event) { + var path = is.function(event.composedPath) ? event.composedPath() : event.path; + + return [domUtils.getActualElement(path ? path[0] : event.target), domUtils.getActualElement(event.currentTarget)]; + } +}; + +module.exports = pointerUtils; + +},{"./browser":36,"./domObjects":38,"./domUtils":39,"./hypot":43,"./is":46,"./pointerExtend":48}],50:[function(require,module,exports){ +'use strict'; + +var _require = require('./window'), + window = _require.window; + +var vendors = ['ms', 'moz', 'webkit', 'o']; +var lastTime = 0; +var request = void 0; +var cancel = void 0; + +for (var x = 0; x < vendors.length && !window.requestAnimationFrame; x++) { + request = window[vendors[x] + 'RequestAnimationFrame']; + cancel = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; +} + +if (!request) { + request = function request(callback) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + + lastTime = currTime + timeToCall; + return id; + }; +} + +if (!cancel) { + cancel = function cancel(id) { + clearTimeout(id); + }; +} + +module.exports = { + request: request, + cancel: cancel +}; + +},{"./window":52}],51:[function(require,module,exports){ +'use strict'; + +var extend = require('./extend'); +var is = require('./is'); + +var _require = require('./domUtils'), + closest = _require.closest, + parentNode = _require.parentNode, + getElementRect = _require.getElementRect; + +var rectUtils = { + getStringOptionResult: function getStringOptionResult(value, interactable, element) { + if (!is.string(value)) { + return null; + } + + if (value === 'parent') { + value = parentNode(element); + } else if (value === 'self') { + value = interactable.getRect(element); + } else { + value = closest(element, value); + } + + return value; + }, + + resolveRectLike: function resolveRectLike(value, interactable, element, functionArgs) { + value = rectUtils.getStringOptionResult(value, interactable, element) || value; + + if (is.function(value)) { + value = value.apply(null, functionArgs); + } + + if (is.element(value)) { + value = getElementRect(value); + } + + return value; + }, + + rectToXY: function rectToXY(rect) { + return rect && { + x: 'x' in rect ? rect.x : rect.left, + y: 'y' in rect ? rect.y : rect.top + }; + }, + + xywhToTlbr: function xywhToTlbr(rect) { + if (rect && !('left' in rect && 'top' in rect)) { + rect = extend({}, rect); + + rect.left = rect.x || 0; + rect.top = rect.y || 0; + rect.right = rect.right || rect.left + rect.width; + rect.bottom = rect.bottom || rect.top + rect.height; + } + + return rect; + }, + + tlbrToXywh: function tlbrToXywh(rect) { + if (rect && !('x' in rect && 'y' in rect)) { + rect = extend({}, rect); + + rect.x = rect.left || 0; + rect.top = rect.top || 0; + rect.width = rect.width || rect.right - rect.x; + rect.height = rect.height || rect.bottom - rect.y; + } + + return rect; + } +}; + +module.exports = rectUtils; + +},{"./domUtils":39,"./extend":41,"./is":46}],52:[function(require,module,exports){ +'use strict'; + +var win = module.exports; +var isWindow = require('./isWindow'); + +function init(window) { + // get wrapped window if using Shadow DOM polyfill + + win.realWindow = window; + + // create a TextNode + var el = window.document.createTextNode(''); + + // check if it's wrapped by a polyfill + if (el.ownerDocument !== window.document && typeof window.wrap === 'function' && window.wrap(el) === el) { + // use wrapped window + window = window.wrap(window); + } + + win.window = window; +} + +if (typeof window === 'undefined') { + win.window = undefined; + win.realWindow = undefined; +} else { + init(window); +} + +win.getWindow = function getWindow(node) { + if (isWindow(node)) { + return node; + } + + var rootNode = node.ownerDocument || node; + + return rootNode.defaultView || rootNode.parentWindow || win.window; +}; + +win.init = init; + +},{"./isWindow":47}]},{},[1])(1) +}); + + +//# sourceMappingURL=interact.js.map diff --git a/cvat/apps/engine/static/engine/js/3rdparty/jquery-3.3.1.js b/cvat/apps/engine/static/engine/js/3rdparty/jquery-3.3.1.js new file mode 100644 index 000000000000..9b5206bcc607 --- /dev/null +++ b/cvat/apps/engine/static/engine/js/3rdparty/jquery-3.3.1.js @@ -0,0 +1,10364 @@ +/*! + * jQuery JavaScript Library v3.3.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2018-01-20T17:24Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + + + + var preservedScriptAttributes = { + type: true, + src: true, + noModule: true + }; + + function DOMEval( code, doc, node ) { + doc = doc || document; + + var i, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + if ( node[ i ] ) { + script[ i ] = node[ i ]; + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.3.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
      " ], + col: [ 2, "", "
      " ], + tr: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + div.style.position = "absolute"; + scrollboxSizeVal = div.offsetWidth === 36 || "absolute"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + ) ); + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + val = curCSS( elem, dimension, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox; + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = valueIsBorderBox && + ( support.boxSizingReliable() || val === elem.style[ dimension ] ); + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + if ( val === "auto" || + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) { + + val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ]; + + // offsetWidth/offsetHeight provide border-box values + valueIsBorderBox = true; + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra && boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ); + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && support.scrollboxSize() === styles.position ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = Date.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + {% for js_file in js_3rdparty %} + + {% endfor %} +{% endblock %} + + +{% block head_js_cvat %} + {{ block.super }} + + + + + + + + + + + + + + + + + + + + + + + + + + +{% endblock %} + + +{% block content %} +
      +
      +
      + + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + + + + +
      + + +
      +
      +
      + + + + + + +
      + + +
      +
      +
      + + + + +
      + +
      +{% endblock %} diff --git a/cvat/apps/engine/templates/engine/base.html b/cvat/apps/engine/templates/engine/base.html new file mode 100644 index 000000000000..4578079521ac --- /dev/null +++ b/cvat/apps/engine/templates/engine/base.html @@ -0,0 +1,85 @@ + +{% load static compress %} + + + + + + {% block head_title %} + Computer Vision Annotation Tool (CVAT) + {% endblock %} + + + {% compress css %} + {% block head_css %} + + {% endblock %} + {% endcompress %} + + {% compress js file platformchecker %} + + + {% endcompress %} + + {% compress js file thirdparty %} + {% block head_js_3rdparty %} + + + + {% endblock %} + {% endcompress %} + + {% compress js file cvat %} + {% block head_js_cvat %} + + + {% endblock %} + {% endcompress %} + + + {% block header %} + {% endblock %} + + {% block content %} + {% endblock %} + + {% block footer %} + {% endblock %} + + + LOADING + + + + + + + + + + diff --git a/cvat/apps/engine/tests.py b/cvat/apps/engine/tests.py new file mode 100644 index 000000000000..7ce503c2dd97 --- /dev/null +++ b/cvat/apps/engine/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cvat/apps/engine/urls.py b/cvat/apps/engine/urls.py new file mode 100644 index 000000000000..3d31fe4e0b20 --- /dev/null +++ b/cvat/apps/engine/urls.py @@ -0,0 +1,20 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('', views.dispatch_request), + path('create/task', views.create_task), + path('get/task//frame/', views.get_frame), + path('check/task/', views.check_task), + path('delete/task/', views.delete_task), + path('update/task/', views.update_task), + path('get/job/', views.get_job), + path('get/task/', views.get_task), + path('dump/annotation/task/', views.dump_annotation), + path('check/annotation/task/', views.check_annotation), + path('download/annotation/task/', views.download_annotation), + path('save/annotation/job/', views.save_annotation_for_job), + path('save/annotation/task/', views.save_annotation_for_task), + path('get/annotation/job/', views.get_annotation), + path('get/username', views.get_username), +] diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py new file mode 100644 index 000000000000..c3363f32d68c --- /dev/null +++ b/cvat/apps/engine/views.py @@ -0,0 +1,279 @@ +import os +import json +import logging +import traceback + +from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse +from django.shortcuts import redirect, render +from django.conf import settings +from django.contrib.auth.decorators import permission_required +from django.views.decorators.gzip import gzip_page +from sendfile import sendfile + +from . import annotation, task, models +from cvat.settings.base import JS_3RDPARTY +from cvat.apps.authentication.decorators import login_required +from cvat.apps.log_proxy.proxy_logger import client_log_proxy +from requests.exceptions import RequestException +from .logging import task_logger, job_logger + +global_logger = logging.getLogger(__name__) + +############################# High Level server API +@login_required +def dispatch_request(request): + """An entry point to dispatch legacy requests""" + if request.method == 'GET' and 'id' in request.GET: + return render(request, 'engine/annotation.html', { + 'js_3rdparty': JS_3RDPARTY.get('engine', []) + }) + else: + return redirect('/dashboard/') + +@login_required +@permission_required('engine.add_task', raise_exception=True) +def create_task(request): + """Create a new annotation task""" + + db_task = None + params = request.POST.dict() + params['owner'] = request.user + global_logger.info("create task with params = {}".format(params)) + try: + db_task = task.create_empty(params) + target_paths = [] + source_paths = [] + upload_dir = db_task.get_upload_dirname() + share_root = settings.SHARE_ROOT + if params['storage'] == 'share': + data_list = request.POST.getlist('data') + data_list.sort(key=len) + for share_path in data_list: + relpath = os.path.normpath(share_path).lstrip('/') + if '..' in relpath.split(os.path.sep): + raise Exception('Permission denied') + abspath = os.path.abspath(os.path.join(share_root, relpath)) + if os.path.commonprefix([share_root, abspath]) != share_root: + raise Exception('Bad file path on share: ' + abspath) + source_paths.append(abspath) + target_paths.append(os.path.join(upload_dir, relpath)) + else: + data_list = request.FILES.getlist('data') + + if len(data_list) > settings.LOCAL_LOAD_MAX_FILES_COUNT: + raise Exception('Too many files. Please use download via share') + common_size = 0 + for f in data_list: + common_size += f.size + if common_size > settings.LOCAL_LOAD_MAX_FILES_SIZE: + raise Exception('Too many size. Please use download via share') + + for data_file in data_list: + source_paths.append(data_file.name) + path = os.path.join(upload_dir, data_file.name) + target_paths.append(path) + with open(path, 'wb') as upload_file: + for chunk in data_file.chunks(): + upload_file.write(chunk) + + params['SOURCE_PATHS'] = source_paths + params['TARGET_PATHS'] = target_paths + + task.create(db_task.id, params) + + return JsonResponse({'tid': db_task.id}) + except Exception as exc: + global_logger.error("cannot create task {}".format(params['task_name']), exc_info=True) + db_task.delete() + return HttpResponseBadRequest(str(exc)) + + return JsonResponse({'tid': db_task.id}) + +@login_required +@permission_required('engine.view_task', raise_exception=True) +def check_task(request, tid): + """Check the status of a task""" + + try: + global_logger.info("check task #{}".format(tid)) + response = task.check(tid) + except Exception as e: + global_logger.error("cannot check task #{}".format(tid), exc_info=True) + return HttpResponseBadRequest(str(e)) + + return JsonResponse(response) + +@login_required +@permission_required('engine.view_task', raise_exception=True) +def get_frame(request, tid, frame): + """Stream corresponding from for the task""" + + try: + # Follow symbol links if the frame is a link on a real image otherwise + # mimetype detection inside sendfile will work incorrectly. + path = os.path.realpath(task.get_frame_path(tid, frame)) + return sendfile(request, path) + except Exception as e: + task_logger[tid].error("cannot get frame #{}".format(frame), exc_info=True) + return HttpResponseBadRequest(str(e)) + +@login_required +@permission_required('engine.delete_task', raise_exception=True) +def delete_task(request, tid): + """Delete the task""" + try: + global_logger.info("delete task #{}".format(tid)) + if not task.is_task_owner(request.user, tid): + return HttpResponseBadRequest("You don't have permissions to delete the task.") + + task.delete(tid) + except Exception as e: + global_logger.error("cannot delete task #{}".format(tid), exc_info=True) + return HttpResponseBadRequest(str(e)) + + return HttpResponse() + +@login_required +@permission_required('engine.change_task', raise_exception=True) +def update_task(request, tid): + """Update labels for the task""" + try: + task_logger[tid].info("update task request") + if not task.is_task_owner(request.user, tid): + return HttpResponseBadRequest("You don't have permissions to change the task.") + + labels = request.POST['labels'] + task.update(tid, labels) + except Exception as e: + task_logger[tid].error("cannot update task", exc_info=True) + return HttpResponseBadRequest(str(e)) + + return HttpResponse() + +@login_required +@permission_required(perm='engine.view_task', raise_exception=True) +def get_task(request, tid): + try: + task_logger[tid].info("get task request") + response = task.get(tid) + except Exception as e: + task_logger[tid].error("cannot get task", exc_info=True) + return HttpResponseBadRequest(str(e)) + + return JsonResponse(response, safe=False) + +@login_required +@permission_required(perm=['engine.view_task', 'engine.view_annotation'], raise_exception=True) +def get_job(request, jid): + try: + job_logger[jid].info("get job #{} request".format(jid)) + response = task.get_job(jid) + except Exception as e: + job_logger[jid].error("cannot get job #{}".format(jid), exc_info=True) + return HttpResponseBadRequest(str(e)) + + return JsonResponse(response, safe=False) + +@login_required +@permission_required(perm=['engine.view_task', 'engine.view_annotation'], raise_exception=True) +def dump_annotation(request, tid): + try: + task_logger[tid].info("dump annotation request") + annotation.dump(tid, annotation.FORMAT_XML, request.scheme, request.get_host()) + except Exception as e: + task_logger[tid].error("cannot dump annotation", exc_info=True) + return HttpResponseBadRequest(str(e)) + + return HttpResponse() + +@login_required +@gzip_page +@permission_required(perm=['engine.view_task', 'engine.view_annotation'], raise_exception=True) +def check_annotation(request, tid): + try: + task_logger[tid].info("check annotation") + response = annotation.check(tid) + except Exception as e: + task_logger[tid].error("cannot check annotation", exc_info=True) + return HttpResponseBadRequest(str(e)) + + return JsonResponse(response) + + +@login_required +@gzip_page +@permission_required(perm=['engine.view_task', 'engine.view_annotation'], raise_exception=True) +def download_annotation(request, tid): + try: + task_logger[tid].info("get dumped annotation") + db_task = models.Task.objects.get(pk=tid) + response = sendfile(request, db_task.get_dump_path(), attachment=True, + attachment_filename='{}_{}.xml'.format(db_task.id, db_task.name)) + except Exception as e: + task_logger[tid].error("cannot get dumped annotation", exc_info=True) + return HttpResponseBadRequest(str(e)) + + return response + + +@login_required +@gzip_page +@permission_required(perm=['engine.view_task', 'engine.view_annotation'], raise_exception=True) +def get_annotation(request, jid): + try: + job_logger[jid].info("get annotation for {} job".format(jid)) + response = annotation.get(jid) + except Exception as e: + job_logger[jid].error("cannot get annotation for job {}".format(jid), exc_info=True) + return HttpResponseBadRequest(str(e)) + + return JsonResponse(response, safe=False) + +@login_required +@permission_required(perm=['engine.view_task', 'engine.change_annotation'], raise_exception=True) +def save_annotation_for_job(request, jid): + try: + job_logger[jid].info("save annotation for {} job".format(jid)) + data = request.POST.dict() + if 'annotation' in data: + annotation.save_job(jid, json.loads(data['annotation'])) + if 'logs' in data: + client_log_proxy.push_logs(jid, json.loads(data['logs'])) + except RequestException as e: + job_logger[jid].error("cannot send annotation logs for job {}".format(jid), exc_info=True) + return HttpResponseBadRequest(str(e)) + except Exception as e: + job_logger[jid].error("cannot save annotation for job {}".format(jid), exc_info=True) + return HttpResponseBadRequest(str(e)) + + return HttpResponse() + + +@login_required +@permission_required(perm=['engine.view_task', 'engine.change_annotation'], raise_exception=True) +def save_annotation_for_task(request, tid): + try: + task_logger[tid].info("save annotation request") + data = json.loads(request.body.decode('utf-8')) + annotation.save_task(tid, data) + except Exception as e: + task_logger[tid].error("cannot save annotation", exc_info=True) + return HttpResponseBadRequest(str(e)) + + return HttpResponse() + +@login_required +def get_username(request): + response = {'username': request.user.username} + return JsonResponse(response, safe=False) + +def rq_handler(job, exc_type, exc_value, tb): + job.exc_info = "".join(traceback.format_exception_only(exc_type, exc_value)) + job.save() + module = job.id.split('.')[0] + if module == 'task': + return task.rq_handler(job, exc_type, exc_value, tb) + elif module == 'annotation': + return annotation.rq_handler(job, exc_type, exc_value, tb) + + return True diff --git a/cvat/apps/log_proxy/__init__.py b/cvat/apps/log_proxy/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/log_proxy/admin.py b/cvat/apps/log_proxy/admin.py new file mode 100644 index 000000000000..8c38f3f3dad5 --- /dev/null +++ b/cvat/apps/log_proxy/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cvat/apps/log_proxy/apps.py b/cvat/apps/log_proxy/apps.py new file mode 100644 index 000000000000..f857c3ed1ad4 --- /dev/null +++ b/cvat/apps/log_proxy/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class LogProxyConfig(AppConfig): + name = 'log_proxy' diff --git a/cvat/apps/log_proxy/migrations/__init__.py b/cvat/apps/log_proxy/migrations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/log_proxy/models.py b/cvat/apps/log_proxy/models.py new file mode 100644 index 000000000000..71a836239075 --- /dev/null +++ b/cvat/apps/log_proxy/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/cvat/apps/log_proxy/proxy_logger.py b/cvat/apps/log_proxy/proxy_logger.py new file mode 100644 index 000000000000..6087abaa6aec --- /dev/null +++ b/cvat/apps/log_proxy/proxy_logger.py @@ -0,0 +1,86 @@ +from django.conf import settings +import os +import logging +import requests +import json +from urllib.parse import urlparse +from enum import Enum +from cvat.apps.engine.models import Job, Task + +from requests.adapters import HTTPAdapter +from urllib3.util.retry import Retry + +class ClientLoggerStorage: + def __init__(self): + self._storage = dict() + self._formatter = logging.Formatter('%(message)s') + + def __getitem__(self, tid): + if tid not in self._storage: + self._storage[tid] = self._create_client_logger(tid) + return self._storage[tid] + + def _create_client_logger(self, tid): + task = self._get_task(tid) + logger = logging.getLogger(name='client_annotation_logger_{}'.format(tid)) + logger.setLevel(logging.INFO) + handler = logging.FileHandler(filename=task.get_client_log_path()) + handler.setFormatter(self._formatter) + logger.addHandler(handler) + return logger + + def _get_task(self, tid): + try: + return Task.objects.get(pk=tid) + except Exception: + raise Exception('Key must be task indentificator') + +class ClientLogProxy(): + class _HandlerType(Enum): + FILE = 1 + HTTP = 2 + + def __init__(self): + self._client_logger = ClientLoggerStorage() + def file_log_handler(tid, messages): + for event in messages: + self._client_logger[tid].info(json.dumps(event)) + + self._handlers = {self._HandlerType.FILE: file_log_handler} + + log_server_url = os.environ.get('DJANGO_LOG_SERVER_URL') + + def create_retry_session(retries=3, session=None, backoff_factor=0.3): + session = session or requests.Session() + retry = Retry(total=retries, backoff_factor=backoff_factor) + adapter = HTTPAdapter(max_retries=retry) + session.mount('http://', adapter) + session.mount('https://', adapter) + return session + + if log_server_url: + parse_result = urlparse(log_server_url) + + if parse_result.scheme and 'http' not in parse_result.scheme: + raise Exception('unsuported annotation log destination') + + def http_log_handler(taskID, messages): + r = create_retry_session().post(url=log_server_url, json=messages, verify=False) + r.raise_for_status() + + self._handlers[self._HandlerType.HTTP] = http_log_handler + + def push_logs(self, jid, logs): + taskID = self._get_task_id(jid) + + for handler in self._handlers.values(): + handler(taskID, logs) + + def _get_task_id(self, jid): + try: + job = Job.objects.select_related("segment__task").get(id=jid) + return job.segment.task.id + except: + raise Exception('Key must be job indentificator') + +client_log_proxy = ClientLogProxy() diff --git a/cvat/apps/log_proxy/tests.py b/cvat/apps/log_proxy/tests.py new file mode 100644 index 000000000000..7ce503c2dd97 --- /dev/null +++ b/cvat/apps/log_proxy/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cvat/apps/log_proxy/urls.py b/cvat/apps/log_proxy/urls.py new file mode 100644 index 000000000000..f76a01b20bd2 --- /dev/null +++ b/cvat/apps/log_proxy/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('exception/', views.exception_receiver), +] diff --git a/cvat/apps/log_proxy/views.py b/cvat/apps/log_proxy/views.py new file mode 100644 index 000000000000..e2f44f02d6fd --- /dev/null +++ b/cvat/apps/log_proxy/views.py @@ -0,0 +1,20 @@ +from django.http import HttpResponse, HttpResponseBadRequest +from django.contrib.auth.decorators import permission_required +from .proxy_logger import client_log_proxy +from cvat.apps.authentication.decorators import login_required + + +import json + +# Create your views here. +@login_required() +@permission_required('engine.view_task', raise_exception=True) +def exception_receiver(request, jid): + data = json.loads(request.body.decode('utf-8')) + try: + if 'exceptions' in data: + client_log_proxy.push_logs(jid, data['exceptions']) + except Exception as e: + return HttpResponseBadRequest(str(e)) + + return HttpResponse() diff --git a/cvat/apps/tf_annotation/README.md b/cvat/apps/tf_annotation/README.md new file mode 100644 index 000000000000..5e7cf7ba24ea --- /dev/null +++ b/cvat/apps/tf_annotation/README.md @@ -0,0 +1,23 @@ +# Tensorflow annotation cvat django-app + +#### What is it? +This application allows you automatically to annotate many various objects on images. [Tensorflow object detector](https://github.com/tensorflow/models/tree/master/research/object_detection) work in backend. It needs NVIDIA GPU for convenience using, but you may run it on CPU (just remove tensorflow-gpu python package and install the CPU tensorflow package version). + +#### Enable instructions +1. Download the root dir with this app to cvat/apps if need. +2. Add urls for tf annotation in ```urls.py```: +``` +urlpatterns += [path('tf_annotation/', include('cvat.apps.tf_annotation.urls'))] +``` +3. Enable this application in ```settings/base.py``` +``` +INSTALLED_APPS += ['cvat.apps.tf_annotation'] +``` + +1. If you want to run CVAT in container: + +* Set TF_ANNOTATION argument to "yes" in ```docker-compose.yml``` +* Add ```runtime: nvidia``` (if you have nvidia-gpu) to cvat block ([nvidia-docker2](https://github.com/nvidia/nvidia-docker/wiki/Installation-(version-2.0)) must be installed) + +5. Else you must download [model](http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_resnet_v2_atrous_coco_11_06_2017.tar.gz), unpack it and set TF_ANNOTATION_MODEL_PATH environment variable to unpacked file ```frozen_inference_graph.pb```. +This variable must be available from cvat runtime environment. diff --git a/cvat/apps/tf_annotation/__init__.py b/cvat/apps/tf_annotation/__init__.py new file mode 100644 index 000000000000..0fd4ef7364db --- /dev/null +++ b/cvat/apps/tf_annotation/__init__.py @@ -0,0 +1,3 @@ +from cvat.settings.base import JS_3RDPARTY + +JS_3RDPARTY['dashboard'] = JS_3RDPARTY.get('dashboard', []) + ['tf_annotation/js/tf_annotation.js'] diff --git a/cvat/apps/tf_annotation/admin.py b/cvat/apps/tf_annotation/admin.py new file mode 100644 index 000000000000..8c38f3f3dad5 --- /dev/null +++ b/cvat/apps/tf_annotation/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cvat/apps/tf_annotation/apps.py b/cvat/apps/tf_annotation/apps.py new file mode 100644 index 000000000000..54b58bbf290b --- /dev/null +++ b/cvat/apps/tf_annotation/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class TFAnnotationConfig(AppConfig): + name = 'tf_annotation' diff --git a/cvat/apps/tf_annotation/docker_setup_tf_annotation.sh b/cvat/apps/tf_annotation/docker_setup_tf_annotation.sh new file mode 100755 index 000000000000..f8ee20bb168a --- /dev/null +++ b/cvat/apps/tf_annotation/docker_setup_tf_annotation.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -e + +NVIDIA_GPGKEY_SUM=d1be581509378368edeec8c1eb2958702feedf3bc3d17011adbf24efacce4ab5 && \ +NVIDIA_GPGKEY_FPR=ae09fe4bbd223a84b2ccfce3f60f4b3d7fa2af80 && \ +apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub && \ +apt-key adv --export --no-emit-version -a $NVIDIA_GPGKEY_FPR | tail -n +5 > cudasign.pub && \ +echo "$NVIDIA_GPGKEY_SUM cudasign.pub" | sha256sum -c --strict - && rm cudasign.pub && \ +echo "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/cuda.list && \ +echo "deb http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/nvidia-ml.list + +CUDA_VERSION=9.0.176 +NCCL_VERSION=2.1.15 +CUDNN_VERSION=7.0.5.15 +CUDA_PKG_VERSION="9-0=${CUDA_VERSION}-1" +echo "export PATH=/usr/local/nvidia/bin:/usr/local/cuda/bin:${PATH}" >> ${HOME}/.bashrc +echo "export LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64:${LD_LIBRARY_PATH}" >> ${HOME}/.bashrc + +apt-get update && apt-get install -y --no-install-recommends \ + libprotobuf-dev \ + libprotoc-dev \ + protobuf-compiler \ + cuda-cudart-$CUDA_PKG_VERSION \ + cuda-libraries-$CUDA_PKG_VERSION \ + libnccl2=$NCCL_VERSION-1+cuda9.0 \ + libcudnn7=$CUDNN_VERSION-1+cuda9.0 && \ + ln -s cuda-9.0 /usr/local/cuda && \ +rm -rf /var/lib/apt/lists/* \ + /etc/apt/sources.list.d/nvidia-ml.list + +pip3 install --no-cache-dir -r "$(cd `dirname $0` && pwd)/requirements.txt" + +cd ${HOME} +wget -O model.tar.gz http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_resnet_v2_atrous_coco_11_06_2017.tar.gz +tar -xzf model.tar.gz +rm model.tar.gz +mv faster_rcnn_inception_resnet_v2_atrous_coco_11_06_2017 rcnn diff --git a/cvat/apps/tf_annotation/migrations/__init__.py b/cvat/apps/tf_annotation/migrations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/apps/tf_annotation/models.py b/cvat/apps/tf_annotation/models.py new file mode 100644 index 000000000000..71a836239075 --- /dev/null +++ b/cvat/apps/tf_annotation/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/cvat/apps/tf_annotation/requirements.txt b/cvat/apps/tf_annotation/requirements.txt new file mode 100644 index 000000000000..5fda99fb0533 --- /dev/null +++ b/cvat/apps/tf_annotation/requirements.txt @@ -0,0 +1,2 @@ +tensorflow==1.7.0 +tensorflow-gpu==1.7.0 \ No newline at end of file diff --git a/cvat/apps/tf_annotation/static/tf_annotation/js/tf_annotation.js b/cvat/apps/tf_annotation/static/tf_annotation/js/tf_annotation.js new file mode 100644 index 000000000000..6bebcbc045ad --- /dev/null +++ b/cvat/apps/tf_annotation/static/tf_annotation/js/tf_annotation.js @@ -0,0 +1,103 @@ +function CheckTFAnnotationRequest(taskId, tfAnnotationButton) { + let frequence = 5000; + let errorCount = 0; + let interval = setInterval(function() { + $.ajax ({ + url: '/tf_annotation/check/task/' + taskId, + success: function(jsonData) { + let status = jsonData["status"]; + if (status == "started" || status == "queued") { + let progress = Math.round(jsonData["progress"]) || "0"; + tfAnnotationButton.text(`Cancel TF Annotation (${progress}%)`); + } + else { + tfAnnotationButton.text("Run TF Annotation"); + tfAnnotationButton.removeClass("tfAnnotationProcess"); + tfAnnotationButton.prop("disabled", false); + clearInterval(interval); + } + }, + error: function() { + errorCount ++; + if (errorCount > 5) { + clearInterval(interval); + tfAnnotationButton.prop("disabled", false); + tfAnnotationButton.text("Status Check Error"); + throw Error(`TF annotation check request error for task ${window.cvat.dashboard.taskID}:${window.cvat.dashboard.taskName}`); + } + } + }); + }, frequence); +} + +function RunTFAnnotationRequest() { + let tfAnnotationButton = this; + let taskID = window.cvat.dashboard.taskID; + $.ajax ({ + url: '/tf_annotation/create/task/' + taskID, + success: function() { + showMessage('Process started.'); + tfAnnotationButton.text(`Cancel TF Annotation (0%)`); + tfAnnotationButton.addClass("tfAnnotationProcess"); + CheckTFAnnotationRequest(taskID, tfAnnotationButton); + }, + error: function(response) { + let message = 'Abort. Reason: ' + response.responseText; + showMessage(message); + } + }); +} + +function CancelTFAnnotationRequest() { + let tfAnnotationButton = this; + $.ajax ({ + url: '/tf_annotation/cancel/task/' + window.cvat.dashboard.taskID, + success: function() { + tfAnnotationButton.prop("disabled", true); + }, + error: function(data) { + let message = `TF annotation cancel error: ${data.responseText}`; + showMessage(message); + } + }); +} + +function onTFAnnotationClick() { + let button = this; + let uiElem = button.closest('div.dashboardTaskUI'); + let taskId = +uiElem.attr('id').split('_')[1]; + let taskName = $.trim($( uiElem.find('label.dashboardTaskNameLabel')[0] ).text()); + + window.cvat.dashboard.taskID = taskId; + window.cvat.dashboard.taskName = taskName; + + if (button.hasClass("tfAnnotationProcess")) { + confirm('The process will be canceled. Continue?', CancelTFAnnotationRequest.bind(button)); + } + else { + confirm('The current annotation will be lost. Are you sure?', RunTFAnnotationRequest.bind(button)); + } +} + +window.cvat = window.cvat || {}; +window.cvat.dashboard = window.cvat.dashboard || {}; +window.cvat.dashboard.uiCallbacks = window.cvat.dashboard.uiCallbacks || []; + +window.cvat.dashboard.uiCallbacks.push(function(newElements) { + newElements.each(function(idx) { + let elem = $(newElements[idx]); + let taskId = +elem.attr('id').split('_')[1]; + let status = $.trim($(elem.find('label.dashboardStatusLabel')[0]).text()); + let buttonsUI = elem.find('div.dashboardButtonsUI')[0]; + let tfAnnotationButton = $(''); + tfAnnotationButton.on('click', onTFAnnotationClick.bind(tfAnnotationButton)); + tfAnnotationButton.addClass('dashboardTFAnnotationButton semiBold dashboardButtonUI'); + tfAnnotationButton.appendTo(buttonsUI); + + if (status == "TF Annotation") { + tfAnnotationButton.text("Cancel TF Annotation"); + tfAnnotationButton.addClass("tfAnnotationProcess"); + CheckTFAnnotationRequest(taskId, tfAnnotationButton); + } + }); +}); diff --git a/cvat/apps/tf_annotation/tests.py b/cvat/apps/tf_annotation/tests.py new file mode 100644 index 000000000000..7ce503c2dd97 --- /dev/null +++ b/cvat/apps/tf_annotation/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cvat/apps/tf_annotation/urls.py b/cvat/apps/tf_annotation/urls.py new file mode 100644 index 000000000000..210ac7853e3a --- /dev/null +++ b/cvat/apps/tf_annotation/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path('create/task/', views.create), + path('check/task/', views.check), + path('cancel/task/', views.cancel), +] \ No newline at end of file diff --git a/cvat/apps/tf_annotation/views.py b/cvat/apps/tf_annotation/views.py new file mode 100644 index 000000000000..1a1b6b6d1a36 --- /dev/null +++ b/cvat/apps/tf_annotation/views.py @@ -0,0 +1,264 @@ +from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest, QueryDict +from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import render +from django.contrib.auth.decorators import permission_required +from cvat.apps.authentication.decorators import login_required +from cvat.apps.engine.models import Task as TaskModel +from cvat.apps.engine import annotation, task + +import django_rq +import fnmatch +import logging +import json +import os +import rq + +import tensorflow as tf +import numpy as np +from PIL import Image + +_logger = logging.getLogger(__name__) + +def load_image_into_numpy(image): + (im_width, im_height) = image.size + return np.array(image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8) + + +def normalize_box(box, w, h): + xmin = int(box[1] * w) + ymin = int(box[0] * h) + xmax = int(box[3] * w) + ymax = int(box[2] * h) + return xmin, ymin, xmax, ymax + + +def run_annotation(image_list, labels_mapping, treshold): + result = {} + model_path = os.environ.get('TF_ANNOTATION_MODEL_PATH') + if model_path is None: + raise OSError('Model path env not found in the system. Please check the installation manual.') + job = rq.get_current_job() + + detection_graph = tf.Graph() + with detection_graph.as_default(): + od_graph_def = tf.GraphDef() + with tf.gfile.GFile(model_path, 'rb') as fid: + serialized_graph = fid.read() + od_graph_def.ParseFromString(serialized_graph) + tf.import_graph_def(od_graph_def, name='') + + try: + config = tf.ConfigProto() + config.gpu_options.allow_growth=True + sess = tf.Session(graph=detection_graph,config=config) + for image_num, image_path in enumerate(image_list): + job.refresh() + if 'cancel' in job.meta: + del job.meta['cancel'] + job.save() + return None + job.meta['progress'] = image_num * 100 / len(image_list) + job.save_meta() + image = Image.open(image_path) + width, height = image.size + if width > 1920 or height > 1080: + image = image.resize((width // 2, height // 2), Image.ANTIALIAS) + image_np = load_image_into_numpy(image) + image_np_expanded = np.expand_dims(image_np, axis=0) + + image_tensor = detection_graph.get_tensor_by_name('image_tensor:0') + boxes = detection_graph.get_tensor_by_name('detection_boxes:0') + scores = detection_graph.get_tensor_by_name('detection_scores:0') + classes = detection_graph.get_tensor_by_name('detection_classes:0') + num_detections = detection_graph.get_tensor_by_name('num_detections:0') + (boxes, scores, classes, num_detections) = sess.run([boxes, scores, classes, num_detections], feed_dict={image_tensor: image_np_expanded}) + + for i in range(len(classes[0])): + if classes[0][i] in labels_mapping.keys(): + if scores[0][i] >= treshold: + xmin, ymin, xmax, ymax = normalize_box(boxes[0][i], width, height) + label = labels_mapping[classes[0][i]] + if label not in result: + result[label] = [] + result[label].append([image_num, xmin, ymin, xmax, ymax]) + finally: + sess.close() + del sess + return result + + +def make_image_list(path_to_data): + def get_image_key(item): + return int(os.path.splitext(os.path.basename(item))[0]) + + image_list = [] + for root, dirnames, filenames in os.walk(path_to_data): + for filename in fnmatch.filter(filenames, '*.jpg'): + image_list.append(os.path.join(root, filename)) + + image_list.sort(key=get_image_key) + return image_list + + +def convert_to_cvat_format(data): + result = { + "boxes": [], + "tracks": [] + } + for label in data: + boxes = data[label] + for box in boxes: + result['boxes'].append({ + "label_id": label, + "frame": box[0], + "xtl": box[1], + "ytl": box[2], + "xbr": box[3], + "ybr": box[4], + "occluded": False, + "attributes": [] + }) + + return result + + +def create_thread(id, labels_mapping): + try: + TRESHOLD = 0.5 + # Init rq job + job = rq.get_current_job() + job.meta['progress'] = 0 + job.save_meta() + # Get job indexes and segment length + db_task = TaskModel.objects.get(pk=id) + db_segments = list(db_task.segment_set.prefetch_related('job_set').all()) + segment_length = max(db_segments[0].stop_frame - db_segments[0].start_frame + 1, 1) + job_indexes = [segment.job_set.first().id for segment in db_segments] + # Get image list + image_list = make_image_list(db_task.get_data_dirname()) + + # Run auto annotation by tf + result = run_annotation(image_list, labels_mapping, TRESHOLD) + if result is None: + _logger.info('tf annotation for task {} canceled by user'.format(id)) + return + + # Modify data format and save + result = convert_to_cvat_format(result) + annotation.save_task(id, result) + db_task.status = "Annotation" + db_task.save() + _logger.info('tf annotation for task {} done'.format(id)) + except Exception: + _logger.exception('exception was occured during tf annotation of the task {}'.format(id)) + db_task.status = "TF Annotation Fault" + db_task.save() + +@login_required +@permission_required(perm=['engine.view_task', 'engine.change_annotation'], raise_exception=True) +def create(request, tid): + _logger.info('tf annotation create request for task {}'.format(tid)) + try: + db_task = TaskModel.objects.get(pk=tid) + except ObjectDoesNotExist: + _logger.exception('task with id {} not found'.format(tid)) + return HttpResponseBadRequest("A task with this ID was not found") + + if not task.is_task_owner(request.user, tid): + _logger.error('not enought of permissions for tf annotation of the task {}'.format(tid)) + return HttpResponseBadRequest("You don't have permissions to tf annotation of the task.") + + queue = django_rq.get_queue('low') + job = queue.fetch_job('tf_annotation.create/{}'.format(tid)) + if job is not None and (job.is_started or job.is_queued): + _logger.error('tf annotation for task {} already running'.format(tid)) + return HttpResponseBadRequest("The process is already running") + db_labels = db_task.label_set.prefetch_related('attributespec_set').all() + db_labels = {db_label.id:db_label.name for db_label in db_labels} + + tf_annotation_labels = { + "person": 1, "bicycle": 2, "car": 3, "motorcycle": 4, "airplane": 5, + "bus": 6, "train": 7, "truck": 8, "boat": 9, "traffic_light": 10, + "fire_hydrant": 11, "stop_sign": 13, "parking_meter": 14, "bench": 15, + "bird": 16, "cat": 17, "dog": 18, "horse": 19, "sheep": 20, "cow": 21, + "elephant": 22, "bear": 23, "zebra": 24, "giraffe": 25, "backpack": 27, + "umbrella": 28, "handbag": 31, "tie": 32, "suitcase": 33, "frisbee": 34, + "skis": 35, "snowboard": 36, "sports_ball": 37, "kite": 38, "baseball_bat": 39, + "baseball_glove": 40, "skateboard": 41, "surfboard": 42, "tennis_racket": 43, + "bottle": 44, "wine_glass": 46, "cup": 47, "fork": 48, "knife": 49, "spoon": 50, + "bowl": 51, "banana": 52, "apple": 53, "sandwich": 54, "orange": 55, "broccoli": 56, + "carrot": 57, "hot_dog": 58, "pizza": 59, "donut": 60, "cake": 61, "chair": 62, + "couch": 63, "potted_plant": 64, "bed": 65, "dining_table": 67, "toilet": 70, + "tv": 72, "laptop": 73, "mouse": 74, "remote": 75, "keyboard": 76, "cell_phone": 77, + "microwave": 78, "oven": 79, "toaster": 80, "sink": 81, "refrigerator": 83, + "book": 84, "clock": 85, "vase": 86, "scissors": 87, "teddy_bear": 88, "hair_drier": 89, + "toothbrush": 90 + } + + labels_mapping = {} + for key, labels in db_labels.items(): + if labels in tf_annotation_labels.keys(): + labels_mapping[tf_annotation_labels[labels]] = key + + if not len(labels_mapping.values()): + _logger.error('no labels found for task {} tf annotation'.format(tid)) + return HttpResponseBadRequest("No labels found for tf annotation") + + db_task.status = "TF Annotation" + db_task.save() + + # Run tf annotation job + queue.enqueue_call(func=create_thread, + args=(tid, labels_mapping), + job_id='tf_annotation.create/{}'.format(tid), + timeout=604800) # 7 days + _logger.info('tf annotation job enqueued for task {} with labels {}'.format(tid, labels_mapping)) + + return HttpResponse() + +@login_required +@permission_required(perm='engine.view_task', raise_exception=True) +def check(request, tid): + queue = django_rq.get_queue('low') + job = queue.fetch_job('tf_annotation.create/{}'.format(tid)) + if job is not None and 'cancel' in job.meta: + return JsonResponse({'status': 'finished'}) + data = {} + try: + if job is None: + data['status'] = 'unknown' + elif job.is_queued: + data['status'] = 'queued' + elif job.is_started: + data['status'] = 'started' + data['progress'] = job.meta['progress'] + elif job.is_finished: + data['status'] = 'finished' + job.delete() + else: + data['status'] = 'failed' + job.delete() + except Exception: + data['status'] = 'unknown' + + return JsonResponse(data) + + +@login_required +@permission_required(perm='engine.view_task', raise_exception=True) +def cancel(request, tid): + try: + queue = django_rq.get_queue('low') + job = queue.fetch_job('tf_annotation.create/{}'.format(tid)) + if job is None or job.is_finished or job.is_failed: + raise Exception('Task is not in tf annotation process') + elif 'cancel' not in job.meta: + job.meta['cancel'] = True + job.save() + db_task = TaskModel.objects.get(pk=tid) + db_task.status = "Annotation" + db_task.save() + + except Exception as ex: + return HttpResponseBadRequest("TF annotation cancel error: {}".format(str(ex))) + return HttpResponse() diff --git a/cvat/requirements/base.txt b/cvat/requirements/base.txt new file mode 100644 index 000000000000..8f6092361d2b --- /dev/null +++ b/cvat/requirements/base.txt @@ -0,0 +1,24 @@ +click==6.7 +Django==2.0.3 +django-appconf==1.0.2 +django-auth-ldap==1.4.0 +django-cacheops==4.0.6 +django-compressor==2.2 +django-rq==1.0.1 +EasyProcess==0.2.3 +ffmpy==0.2.2 +Pillow==5.1.0 +numpy==1.14.2 +patool==1.12 +python-ldap==3.0.0 +pytz==2018.3 +pyunpack==0.1.2 +rcssmin==1.0.6 +redis==2.10.6 +requests==2.18.4 +rjsmin==1.0.12 +rq==0.10.0 +scipy==1.0.1 +sqlparse==0.2.4 +django-sendfile==0.3.11 +dj-pagination==2.3.2 diff --git a/cvat/requirements/development.txt b/cvat/requirements/development.txt new file mode 100644 index 000000000000..dd5c44918209 --- /dev/null +++ b/cvat/requirements/development.txt @@ -0,0 +1,14 @@ +-r base.txt +astroid==1.6.2 +isort==4.3.4 +lazy-object-proxy==1.3.1 +mccabe==0.6.1 +pylint==1.8.3 +pylint-django==0.9.4 +pylint-plugin-utils==0.2.6 +rope==0.10.7 +six==1.11.0 +wrapt==1.10.11 +django-extensions==2.0.6 +Werkzeug==0.14.1 +snakeviz==0.4.2 \ No newline at end of file diff --git a/cvat/requirements/production.txt b/cvat/requirements/production.txt new file mode 100644 index 000000000000..340e26bed754 --- /dev/null +++ b/cvat/requirements/production.txt @@ -0,0 +1,3 @@ +-r base.txt +psycopg2-binary==2.7.4 +mod-wsgi==4.6.2 \ No newline at end of file diff --git a/cvat/requirements/staging.txt b/cvat/requirements/staging.txt new file mode 100644 index 000000000000..d7f1e2f90a3f --- /dev/null +++ b/cvat/requirements/staging.txt @@ -0,0 +1 @@ +-r production.txt diff --git a/cvat/settings/__init__.py b/cvat/settings/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cvat/settings/base.py b/cvat/settings/base.py new file mode 100644 index 000000000000..63b4b7208ac4 --- /dev/null +++ b/cvat/settings/base.py @@ -0,0 +1,215 @@ +""" +Django settings for CVAT project. + +Generated by 'django-admin startproject' using Django 2.0.1. + +For more information on this file, see +https://docs.djangoproject.com/en/2.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.0/ref/settings/ +""" + +import os +import sys +from pathlib import Path + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = str(Path(__file__).parents[2]) + +ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',') +INTERNAL_IPS = ['127.0.0.1'] + +try: + sys.path.append(BASE_DIR) + from keys.secret_key import SECRET_KEY +except ImportError: + from django.utils.crypto import get_random_string + with open(os.path.join(BASE_DIR, 'keys', 'secret_key.py'), 'w') as f: + chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' + f.write("SECRET_KEY = '{}'\n".format(get_random_string(50, chars))) + from keys.secret_key import SECRET_KEY + +# Application definition +JS_3RDPARTY = {} + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'cvat.apps.engine', + 'cvat.apps.dashboard', + 'cvat.apps.authentication', + 'cvat.apps.documentation', + 'django_rq', + 'compressor', + 'cacheops', + 'sendfile', + 'dj_pagination', +] + +if 'yes' == os.environ.get('TF_ANNOTATION', 'no'): + INSTALLED_APPS += ['cvat.apps.tf_annotation'] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'dj_pagination.middleware.PaginationMiddleware', +] + +STATICFILES_FINDERS = [ + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', +] + +ROOT_URLCONF = 'cvat.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'cvat.wsgi.application' + +# Django-RQ +# https://github.com/rq/django-rq + +RQ_QUEUES = { + 'default': { + 'HOST': 'localhost', + 'PORT': 6379, + 'DB': 0, + 'DEFAULT_TIMEOUT': '1h' + }, + 'low': { + 'HOST': 'localhost', + 'PORT': 6379, + 'DB': 0, + 'DEFAULT_TIMEOUT': '24h' + } +} + +RQ_SHOW_ADMIN_LINK = True +RQ_EXCEPTION_HANDLERS = ['cvat.apps.engine.views.rq_handler'] + + +# JavaScript and CSS compression +# https://django-compressor.readthedocs.io + +COMPRESS_CSS_FILTERS = [ + 'compressor.filters.css_default.CssAbsoluteFilter', + 'compressor.filters.cssmin.rCSSMinFilter', +] + +# Password validation +# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# Cache DB access (e.g. for engine.task.get_frame) +# https://github.com/Suor/django-cacheops +CACHEOPS_REDIS = { + 'host': 'localhost', # redis-server is on same machine + 'port': 6379, # default redis port + 'db': 1, # SELECT non-default redis database +} + +CACHEOPS = { + # Automatically cache any Task.objects.get() calls for 15 minutes + # This also includes .first() and .last() calls. + 'engine.task': {'ops': 'get', 'timeout': 60*15}, +} + +CACHEOPS_DEGRADE_ON_FAILURE = True + +# Internationalization +# https://docs.djangoproject.com/en/2.0/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Europe/Moscow' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'standard': { + 'format': '[%(asctime)s] %(levelname)s %(name)s: %(message)s' + } + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'standard', + }, + 'file': { + 'class': 'logging.handlers.RotatingFileHandler', + 'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'), + 'filename': os.path.join(BASE_DIR, 'logs', 'cvat.log'), + 'formatter': 'standard', + 'maxBytes': 1024*1024*50, # 50 MB + 'backupCount': 5, + } + }, + 'loggers': { + 'cvat': { + 'handlers': ['console', 'file'], + 'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'), + } + }, +} + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.0/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'static') +os.makedirs(STATIC_ROOT, exist_ok=True) +DATA_ROOT = os.path.join(BASE_DIR, 'data') +os.makedirs(DATA_ROOT, exist_ok=True) +SHARE_ROOT = os.path.join(BASE_DIR, 'share') +os.makedirs(SHARE_ROOT, exist_ok=True) + +DATA_UPLOAD_MAX_MEMORY_SIZE = 100 * 1024 * 1024 # 100 MB +DATA_UPLOAD_MAX_NUMBER_FIELDS = None # this django check disabled +LOCAL_LOAD_MAX_FILES_COUNT = 500 +LOCAL_LOAD_MAX_FILES_SIZE = 512 * 1024 * 1024 # 512 MB diff --git a/cvat/settings/development.py b/cvat/settings/development.py new file mode 100644 index 000000000000..1aa07ee49861 --- /dev/null +++ b/cvat/settings/development.py @@ -0,0 +1,25 @@ +from .base import * + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ + +INSTALLED_APPS += [ + 'django_extensions', +] + +# Django-sendfile: +# https://github.com/johnsensible/django-sendfile +SENDFILE_BACKEND = 'sendfile.backends.development' + +# Database +# https://docs.djangoproject.com/en/2.0/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} diff --git a/cvat/settings/production.py b/cvat/settings/production.py new file mode 100644 index 000000000000..826a8e16e1d2 --- /dev/null +++ b/cvat/settings/production.py @@ -0,0 +1,29 @@ +from .base import * + +DEBUG = False + +INSTALLED_APPS += [ + 'mod_wsgi.server', +] + +for key in RQ_QUEUES: + RQ_QUEUES[key]['HOST'] = 'cvat_redis' + +CACHEOPS_REDIS['host'] = 'cvat_redis' + +# Django-sendfile: +# https://github.com/johnsensible/django-sendfile +SENDFILE_BACKEND = 'sendfile.backends.xsendfile' + +# Database +# https://docs.djangoproject.com/en/2.0/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'HOST': 'cvat_db', + 'NAME': 'cvat', + 'USER': 'root', + 'PASSWORD': os.getenv('POSTGRES_PASSWORD', ''), + } +} diff --git a/cvat/settings/staging.py b/cvat/settings/staging.py new file mode 100644 index 000000000000..78e75d2fb467 --- /dev/null +++ b/cvat/settings/staging.py @@ -0,0 +1,3 @@ +from .production import * + +DEBUG = True \ No newline at end of file diff --git a/cvat/simpleworker.py b/cvat/simpleworker.py new file mode 100644 index 000000000000..a2d250604d05 --- /dev/null +++ b/cvat/simpleworker.py @@ -0,0 +1,23 @@ +from rq import Worker + + +class BaseDeathPenalty(object): + def __init__(self, timeout): + pass + + def __enter__(self): + pass + + def __exit__(self, type, value, traceback): + pass + + +class SimpleWorker(Worker): + death_penalty_class = BaseDeathPenalty + + def main_work_horse(self, *args, **kwargs): + raise NotImplementedError("Test worker does not implement this method") + + def execute_job(self, *args, **kwargs): + """Execute job in same thread/process, do not fork()""" + return self.perform_job(*args, **kwargs) \ No newline at end of file diff --git a/cvat/urls.py b/cvat/urls.py new file mode 100644 index 000000000000..29b5e12b9a3d --- /dev/null +++ b/cvat/urls.py @@ -0,0 +1,33 @@ +"""CVAT URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from django.conf import settings +from django.conf.urls.static import static +import os + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', include('cvat.apps.engine.urls')), + path('dashboard/', include('cvat.apps.dashboard.urls')), + path('django-rq/', include('django_rq.urls')), + path('auth/', include('cvat.apps.authentication.urls')), + path('documentation/', include('cvat.apps.documentation.urls')), + path('logs/', include('cvat.apps.log_proxy.urls')) +] + +if 'yes' == os.environ.get('TF_ANNOTATION', 'no'): + urlpatterns += [path('tf_annotation/', include('cvat.apps.tf_annotation.urls'))] diff --git a/cvat/wsgi.py b/cvat/wsgi.py new file mode 100644 index 000000000000..3e5b0a65fae2 --- /dev/null +++ b/cvat/wsgi.py @@ -0,0 +1,17 @@ +""" +WSGI config for CVAT project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cvat.settings.{}" \ + .format(os.environ.get("DJANGO_CONFIGURATION", "development"))) + +application = get_wsgi_application() diff --git a/docker-compose.nvidia.yml b/docker-compose.nvidia.yml new file mode 100644 index 000000000000..614a45e521c9 --- /dev/null +++ b/docker-compose.nvidia.yml @@ -0,0 +1,13 @@ +version: "2.3" + +services: + cvat: + build: + context: . + args: + TF_ANNOTATION: "yes" + runtime: "nvidia" + environment: + NVIDIA_VISIBLE_DEVICES: all + NVIDIA_DRIVER_CAPABILITIES: compute,utility + NVIDIA_REQUIRE_CUDA: "cuda>=9.0" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000000..4f570540e64d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,51 @@ +version: "2.3" + +services: + cvat_db: + container_name: cvat_db + image: postgres:10.3-alpine + restart: always + environment: + POSTGRES_USER: root + POSTGRES_DB: cvat + volumes: + - cvat_db:/var/lib/postgresql/data + + cvat_redis: + container_name: cvat_redis + image: redis:4.0.5-alpine + restart: always + + cvat: + container_name: cvat + image: cvat + restart: always + depends_on: + - cvat_redis + - cvat_db + ports: + - "8080:8080" + build: + context: . + args: + http_proxy: + https_proxy: + no_proxy: + TF_ANNOTATION: "no" + USER: "django" + DJANGO_CONFIGURATION: "production" + WITH_TESTS: "no" + environment: + DJANGO_MODWSGI_EXTRA_ARGS: "" + DJANGO_LOG_SERVER_URL: "" + volumes: + - cvat_data:/home/django/data + - cvat_keys:/home/django/keys + - cvat_logs:/home/django/logs + - ./share:/home/django/share + +volumes: + cvat_db: + cvat_data: + cvat_keys: + cvat_logs: diff --git a/manage.py b/manage.py new file mode 100644 index 000000000000..a3b9bad37a81 --- /dev/null +++ b/manage.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cvat.settings.{}" \ + .format(os.environ.get("DJANGO_CONFIGURATION", "development"))) + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) diff --git a/mod_wsgi.conf b/mod_wsgi.conf new file mode 100644 index 000000000000..5e36db15834b --- /dev/null +++ b/mod_wsgi.conf @@ -0,0 +1,3 @@ +LoadModule xsendfile_module /usr/lib/apache2/modules/mod_xsendfile.so +XSendFile On +XSendFilePath ${HOME}/data/ diff --git a/supervisord.conf b/supervisord.conf new file mode 100644 index 000000000000..70c3cf8dee38 --- /dev/null +++ b/supervisord.conf @@ -0,0 +1,33 @@ +[unix_http_server] +file = /tmp/supervisord/supervisor.sock + +[supervisorctl] +serverurl = unix:///tmp/supervisord/supervisor.sock + + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisord] +nodaemon=true +logfile=%(ENV_HOME)s/logs/supervisord.log ; supervisord log file +logfile_maxbytes=50MB ; maximum size of logfile before rotation +logfile_backups=10 ; number of backed up logfiles +loglevel=debug ; info, debug, warn, trace +pidfile=/tmp/supervisord/supervisord.pid ; pidfile location +childlogdir=%(ENV_HOME)s/logs/ ; where child log files will live + +[program:rqworker_default] +command=%(ENV_HOME)s/wait-for-it.sh cvat_redis:6379 -t 0 -- bash -ic "/usr/bin/python3 %(ENV_HOME)s/manage.py rqworker -v 3 default" +numprocs=2 +process_name=rqworker_default_%(process_num)s + +[program:rqworker_low] +command=%(ENV_HOME)s/wait-for-it.sh cvat_redis:6379 -t 0 -- bash -ic "/usr/bin/python3 %(ENV_HOME)s/manage.py rqworker -v 3 low" +numprocs=1 + +[program:runserver] +command=%(ENV_HOME)s/wait-for-it.sh cvat_db:5432 -t 0 -- bash -ic "/usr/bin/python3 ~/manage.py migrate && \ + exec /usr/bin/python3 $HOME/manage.py runmodwsgi --log-to-terminal --port 8080 \ + --limit-request-body 1073741824 --log-level INFO --include-file ~/mod_wsgi.conf \ + %(ENV_DJANGO_MODWSGI_EXTRA_ARGS)s --locale %(ENV_LC_ALL)s" diff --git a/tests/eslintrc.conf.js b/tests/eslintrc.conf.js new file mode 100644 index 000000000000..e6967d8dceb3 --- /dev/null +++ b/tests/eslintrc.conf.js @@ -0,0 +1,103 @@ +module.exports = { + 'env': { + 'browser': true, + 'es6': true, + 'jquery': true, + 'qunit': true, + }, + "extends": "eslint:recommended", + 'rules': { + 'indent': [ + 'warn', + 4 + ], + 'linebreak-style': [ + 'error', + 'unix' + ], + 'semi': [ + 'warn' + ], + 'no-extra-semi': [ + 'warn' + ], + 'no-console': [ + 'warn' + ], + }, + 'globals': { + // from attributeAnnotationMode.js + 'AAMController': true, + 'AAMModel': true, + 'AAMView': true, + 'AAMUndefinedKeyword': true, + // from annotationParser.js + 'AnnotationParser': true, + // from annotationUI.js + 'callAnnotationUI': true, + 'translateSVGPos': true, + // from base.js + 'showMessage': true, + 'showOverlay': true, + 'confirm': true, + 'dumpAnnotationRequest': true, + // from collectionController.js, collectionModel.js, collectionView.js + 'CollectionController': true, + 'CollectionModel': true, + 'CollectionView': true, + // from drawer.js + 'DrawerController': true, + 'DrawerModel': true, + 'DrawerView': true, + // from interact.js + 'interact': true, + // from labelsInfo.js + 'LabelsInfo': true, + // from listener.js + 'Listener': true, + // from logger.js + 'Logger': true, + // from merger.js + 'MergerController': true, + 'MergerModel': true, + 'MergerView': true, + // from trackModel.js + 'MIN_BOX_SIZE': true, + // from mousetrap.js + 'Mousetrap': true, + // from objecthash.js + 'objectHash': true, + // from platform.js + 'platform': true, + // from playerController.js, playerModel.js, playerView.js + 'PlayerController': true, + 'PlayerModel': true, + 'PlayerView': true, + // from server.js + 'serverRequest': true, + 'encodeFilePathToURI': true, + 'saveJobOnServer': true, + // from shapeBuffer.js + 'ShapeBufferController': true, + 'ShapeBufferModel': true, + 'ShapeBufferView': true, + // from trackController.js, trackModel.js, trackView.js + 'TrackController': true, + 'TrackModel':true, + 'TrackView': true, + 'MIN_BOX_SIZE': true, + // from trackFilter.js + 'TrackFilterModel': true, + 'TrackFilterController': true, + 'TrackFilterView': true, + // from userConfig.js + 'userConfig': true, + // from cookies.js + 'Cookies': true, + // from api.js + 'setupAPI': true, + // from dashboard django template + 'maxUploadCount': true, + 'maxUploadSize': true, + }, +}; diff --git a/tests/karma.conf.js b/tests/karma.conf.js new file mode 100644 index 000000000000..c87a2fe303b5 --- /dev/null +++ b/tests/karma.conf.js @@ -0,0 +1,66 @@ +const path = require('path'); +module.exports = function(config) { + config.set({ + basePath: path.join(process.env.HOME, 'cvat/apps/'), + frameworks: ['qunit'], + files: [ + 'engine/static/engine/js/labelsInfo.js', + 'engine/static/engine/js/annotationParser.js', + 'engine/static/engine/js/listener.js', + 'engine/static/engine/js/player.js', + 'engine/static/engine/js/trackFilter.js', + 'engine/static/engine/js/trackModel.js', + 'engine/static/engine/js/collectionModel.js', + 'engine/static/engine/js/merger.js', + 'engine/static/engine/js/attributeAnnotationMode.js', + 'engine/static/engine/js/qunitTests.js', + ], + port: 9876, + colors: true, + autoWatch: false, + browsers: ['ChromeNoSandbox'], + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true, + + // Concurrency level + // how many browser should be started simultanous + concurrency: Infinity, + + preprocessors: { + '**/!(qunitTests).js': ['coverage'] + }, + + reporters: ['progress', 'junit', 'coverage'], + + coverageReporter: { + dir: path.join(process.env.HOME, 'media/coverage'), + reporters: [ + { type: 'html', subdir: '.' }, + ], + instrumenterOptions: { + istanbul: { noCompact: true } + } + }, + + junitReporter: { + outputDir: path.join(process.env.HOME, 'media/junit'), + outputFile: undefined, + useBrowserName: true, + nameFormatter: undefined, + classNameFormatter: undefined, + properties: {}, + xmlVersion: null + }, + + customLaunchers: { + ChromeNoSandbox: { + base: 'ChromeHeadless', + flags: ['--no-sandbox'] + } + }, + + logLevel: config.LOG_DEBUG + }); +} diff --git a/tests/run_js_linter.sh b/tests/run_js_linter.sh new file mode 100644 index 000000000000..1ad4368c36df --- /dev/null +++ b/tests/run_js_linter.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +eslint -c ~/tests/eslintrc.conf.js -f ~/tests/node_modules/eslint-detailed-reporter/lib/detailed-multi.js \ + ~/cvat/apps/**/js/*.js -o ./report.html +ret_code=$? + +mkdir -p ~/media/eslint +mv -t ~/media/eslint main.js styles.css report.html + +exit $ret_code diff --git a/wait-for-it.sh b/wait-for-it.sh new file mode 100755 index 000000000000..12f10ee7dcd7 --- /dev/null +++ b/wait-for-it.sh @@ -0,0 +1,178 @@ +#!/usr/bin/env bash +# Use this script to test if a given TCP host/port are available +# https://github.com/vishnubob/wait-for-it + +cmdname=$(basename $0) + +echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } + +usage() +{ + cat << USAGE >&2 +Usage: + $cmdname host:port [-s] [-t timeout] [-- command args] + -h HOST | --host=HOST Host or IP under test + -p PORT | --port=PORT TCP port under test + Alternatively, you specify the host and port as host:port + -s | --strict Only execute subcommand if the test succeeds + -q | --quiet Don't output any status messages + -t TIMEOUT | --timeout=TIMEOUT + Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit 1 +} + +wait_for() +{ + if [[ $TIMEOUT -gt 0 ]]; then + echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" + else + echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" + fi + start_ts=$(date +%s) + while : + do + if [[ $ISBUSY -eq 1 ]]; then + nc -z $HOST $PORT + result=$? + else + (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 + result=$? + fi + if [[ $result -eq 0 ]]; then + end_ts=$(date +%s) + echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" + break + fi + sleep 1 + done + return $result +} + +wait_for_wrapper() +{ + # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 + if [[ $QUIET -eq 1 ]]; then + timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & + else + timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & + fi + PID=$! + trap "kill -INT -$PID" INT + wait $PID + RESULT=$? + if [[ $RESULT -ne 0 ]]; then + echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" + fi + return $RESULT +} + +# process arguments +while [[ $# -gt 0 ]] +do + case "$1" in + *:* ) + hostport=(${1//:/ }) + HOST=${hostport[0]} + PORT=${hostport[1]} + shift 1 + ;; + --child) + CHILD=1 + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -s | --strict) + STRICT=1 + shift 1 + ;; + -h) + HOST="$2" + if [[ $HOST == "" ]]; then break; fi + shift 2 + ;; + --host=*) + HOST="${1#*=}" + shift 1 + ;; + -p) + PORT="$2" + if [[ $PORT == "" ]]; then break; fi + shift 2 + ;; + --port=*) + PORT="${1#*=}" + shift 1 + ;; + -t) + TIMEOUT="$2" + if [[ $TIMEOUT == "" ]]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + CLI=("$@") + break + ;; + --help) + usage + ;; + *) + echoerr "Unknown argument: $1" + usage + ;; + esac +done + +if [[ "$HOST" == "" || "$PORT" == "" ]]; then + echoerr "Error: you need to provide a host and port to test." + usage +fi + +TIMEOUT=${TIMEOUT:-15} +STRICT=${STRICT:-0} +CHILD=${CHILD:-0} +QUIET=${QUIET:-0} + +# check to see if timeout is from busybox? +# check to see if timeout is from busybox? +TIMEOUT_PATH=$(realpath $(which timeout)) +if [[ $TIMEOUT_PATH =~ "busybox" ]]; then + ISBUSY=1 + BUSYTIMEFLAG="-t" +else + ISBUSY=0 + BUSYTIMEFLAG="" +fi + +if [[ $CHILD -gt 0 ]]; then + wait_for + RESULT=$? + exit $RESULT +else + if [[ $TIMEOUT -gt 0 ]]; then + wait_for_wrapper + RESULT=$? + else + wait_for + RESULT=$? + fi +fi + +if [[ $CLI != "" ]]; then + if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then + echoerr "$cmdname: strict mode, refusing to execute subprocess" + exit $RESULT + fi + exec "${CLI[@]}" +else + exit $RESULT +fi