[
  {
    "path": ".coveragerc",
    "content": "[run]\nbranch = True\nomit =\n  example_project/django_mptt_example/tests/base_playwright_testcase.py\n  example_project/django_mptt_example/tests/playwright_page.py\n  example_project/django_mptt_example/tests/test_playwright.py\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"pip\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Continuous integration\n\non: [push]\n\njobs:\n  runner-job:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        django: [\"django==4.2.30\", \"django==5.2.13\", \"django==6.0.4\"]\n\n    services:\n      postgres:\n        image: postgres\n        env:\n          POSTGRES_PASSWORD: postgres\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n        ports:\n          - 5432:5432\n\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v6\n      - name: Check spelling\n        uses: streetsidesoftware/cspell-action@v8\n        with:\n          files: |\n            frontend/src/**/*.ts\n            django_mptt_admin/**/*.py\n            example_project/**/*.py\n          incremental_files_only: false\n      - name: Setup node\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"20\"\n      - name: Install pnpm\n        run: npm install -g pnpm\n      - name: Get pnpm store directory\n        id: pnpm-cache\n        run: |\n          echo \"STORE_PATH=$(pnpm store path)\" >> $GITHUB_OUTPUT\n      - uses: actions/cache@v5\n        name: Setup pnpm cache\n        with:\n          path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n      - name: Install javascript packages\n        working-directory: ./frontend\n        run: pnpm install\n      - name: Cache python packages\n        uses: actions/cache@v5\n        with:\n          path: ~/.cache/pip\n          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements**.txt') }}\n          restore-keys: |\n            ${{ runner.os }}-pip-\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version: \"3.12\"\n      - name: Install python packages\n        run: |\n          pip install ${{ matrix.django }} && pip install -r example_project/requirements_test.txt && playwright install chromium && pip install -r example_project/requirements_ci.txt && pip install -e .\n      - name: Build javascript\n        working-directory: ./frontend\n        run: pnpm run build\n      - name: Javascript test\n        working-directory: ./frontend\n        run: pnpm run test:coverage\n      - name: Collect static files\n        run: python manage.py collectstatic --no-input\n        working-directory: example_project\n      - name: Create javascript coverage directory\n        run: mkdir js_coverage\n      - name: Test with coverage\n        run: |\n          COVERAGE=true coverage run --source=django_mptt_admin,example_project/django_mptt_example example_project/manage.py test django_mptt_example\n        env:\n          POSTGRES_HOST: localhost\n          POSTGRES_PASSWORD: postgres\n          POSTGRES_PORT: 5432\n      - name: Merge Python coverage\n        run: coverage report && coverage lcov\n      - name: Merge javascript coverage\n        working-directory: ./coverage\n        run: pnpm i && pnpm run merge_coverage\n      - name: Codecov\n        uses: codecov/codecov-action@v6\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          verbose: true\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [\"master\"]\n  pull_request:\n    branches: [\"master\"]\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [\"javascript\", \"python\"]\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: ${{ matrix.language }}\n\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@v3\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".github/workflows/mkdocs.yml",
    "content": "name: Publish docs via GitHub Pages\n\non:\n  push:\n    branches:\n      - master\n      - mkdocs-workflow\n\njobs:\n  build:\n    name: Deploy docs\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout master\n        uses: actions/checkout@v6\n\n      - name: Set up Python\n        uses: actions/setup-python@v6\n        with:\n          python-version: 3.12\n\n      - name: Install python packages\n        run: |\n          pip install -r requirements_docs.txt\n\n      - name: Run mkdocs\n        run: mkdocs gh-deploy --force\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.pyc\ndjango_mptt_admin/static/django_mptt_admin/django_mptt_admin.coverage.js\ndjango_mptt_admin/static/django_mptt_admin/django_mptt_admin.coverage.js.map\n"
  },
  {
    "path": "LICENSE.rst",
    "content": "=======\nLICENSE\n=======\n\nCopyright © 2013, Marco Braak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this software except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include LICENSE.rst\ninclude README.md\nrecursive-include django_mptt_admin/templates *\nrecursive-include django_mptt_admin/static *\nrecursive-include django_mptt_admin/locale *\n"
  },
  {
    "path": "README.md",
    "content": "![Continuous integration](https://github.com/mbraak/django-mptt-admin/workflows/Continuous%20integration/badge.svg) [![Version](https://badge.fury.io/py/django-mptt-admin.svg)](https://pypi.python.org/pypi/django-mptt-admin/)\n\n[![codecov](https://codecov.io/gh/mbraak/django-mptt-admin/branch/master/graph/badge.svg?token=YGojePND2M)](https://codecov.io/gh/mbraak/django-mptt-admin)\n\n[![License](https://img.shields.io/pypi/l/django-mptt-admin.svg)](https://pypi.python.org/pypi/django-mptt-admin/)\n\n# Django Mptt Admin\n\n_Django-mptt-admin_ provides a nice Django Admin interface for [django-mptt models](https://django-mptt.readthedocs.io/).\n\n- The source is available on [https://github.com/mbraak/django-mptt-admin](https://github.com/mbraak/django-mptt-admin).\n- Documentation is available on [https://mbraak.github.io/django-mptt-admin/](https://mbraak.github.io/django-mptt-admin/).\n\n![Screenshot](https://raw.github.com/mbraak/django-mptt-admin/master/screenshot.png)\n"
  },
  {
    "path": "coverage/.nycrc.json",
    "content": "{\n  \"exclude-after-remap\": false\n}\n"
  },
  {
    "path": "coverage/package.json",
    "content": "{\n  \"name\": \"coverage\",\n  \"dependencies\": {\n    \"nyc\": \"^18\"\n  },\n  \"scripts\": {\n    \"merge_coverage\": \"nyc --reporter lcov -t ./js_coverage --cwd .. report\"\n  }\n}\n"
  },
  {
    "path": "cspell.json",
    "content": "{\n  \"language\": \"en-GB\",\n  \"words\": [\n    \"Åland\",\n    \"bouvet\",\n    \"countrycode\",\n    \"countrycodeandname\",\n    \"crsf\",\n    \"csrfmiddlewaretoken\",\n    \"jqtree\",\n    \"mptt\",\n    \"rght\",\n    \"tabindex\",\n    \"testcsrf\",\n    \"toggler\",\n    \"webtest\"\n  ]\n}\n"
  },
  {
    "path": "django_mptt_admin/__init__.py",
    "content": ""
  },
  {
    "path": "django_mptt_admin/admin.py",
    "content": "from mptt.admin import MPTTModelAdmin\n\nfrom .django_mptt_admin_mixin import DjangoMpttAdminMixin\n\n\nclass DjangoMpttAdmin(DjangoMpttAdminMixin, MPTTModelAdmin):\n    pass\n\n\nclass FilterableDjangoMpttAdmin(DjangoMpttAdmin):\n    pass\n"
  },
  {
    "path": "django_mptt_admin/django_mptt_admin_mixin.py",
    "content": "from functools import update_wrapper\nfrom typing import Union\n\nfrom django.conf import settings\nfrom django.templatetags.static import static\nfrom django.contrib.admin.templatetags.admin_urls import add_preserved_filters\nfrom django.core.exceptions import PermissionDenied, SuspiciousOperation\nfrom django.http import JsonResponse\nfrom django.template.response import TemplateResponse\nfrom django.contrib.admin.options import csrf_protect_m, ModelAdmin\nfrom django.contrib.admin.utils import unquote, quote\nfrom django.contrib.admin.options import IS_POPUP_VAR\nfrom django.db import transaction\nfrom django.utils.http import urlencode\nfrom django.forms import Media\nfrom django.urls import re_path, reverse\nfrom django.views.i18n import JavaScriptCatalog\nimport django\n\nfrom . import util\nfrom .tree_change_list import TreeChangeList\n\n\nclass DjangoMpttAdminMixin:\n    tree_animation_speed = None\n    tree_auto_open = 1\n    tree_load_on_demand = 1\n    tree_mouse_delay = None\n    trigger_save_after_move = False\n\n    # Autoescape the tree data; default is True\n    autoescape = True\n\n    # useContextMenu option for the tree; default is False\n    use_context_menu = False\n\n    change_list_template = \"django_mptt_admin/grid_view.html\"\n    change_tree_template = \"django_mptt_admin/change_list.html\"\n\n    # define which field of the model should be the label for tree items\n    item_label_field_name = None\n\n    # list and tree filter\n    list_filter = ()\n\n    change_list_tree_class = TreeChangeList\n\n    @csrf_protect_m\n    def changelist_view(\n        self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"], request, extra_context=None\n    ):\n        request.current_app = self.admin_site.name\n        is_popup = IS_POPUP_VAR in request.GET\n        if is_popup:\n            return super(DjangoMpttAdminMixin, self).changelist_view(\n                request, extra_context=extra_context\n            )\n\n        if not self.has_view_or_change_permission(request):\n            raise PermissionDenied()\n\n        change_list = self.get_change_list_for_tree(request)\n\n        preserved_filters = self.get_preserved_filters(request)\n\n        def get_admin_url_with_filters(name):\n            admin_url = self.get_admin_url(name)\n\n            if change_list.params:\n                return admin_url + change_list.get_query_string()\n            else:\n                return admin_url\n\n        def get_admin_url_with_preserved_filters(name):\n            return add_preserved_filters(\n                {\"preserved_filters\": preserved_filters, \"opts\": self.opts},\n                self.get_admin_url(name),\n            )\n\n        def get_csrf_cookie_name():\n            if settings.CSRF_USE_SESSIONS:\n                return \"\"\n            else:\n                return settings.CSRF_COOKIE_NAME\n\n        grid_url = get_admin_url_with_filters(\"grid\")\n        tree_json_url = get_admin_url_with_filters(\"tree_json\")\n        insert_at_url = get_admin_url_with_preserved_filters(\"add\")\n\n        tree_options = {\n            \"autoescape\": self.autoescape,\n            \"csrf_cookie_name\": get_csrf_cookie_name(),\n            \"drag_and_drop\": self.is_drag_and_drop_enabled(),\n            \"grid_url\": grid_url,\n            \"has_add_permission\": self.has_add_permission(request),\n            \"has_change_permission\": self.has_change_permission(request),\n            \"insert_at_url\": insert_at_url,\n            \"jsi18n_url\": self.get_admin_url(\"jsi18n\"),\n            \"model_name\": util.get_model_name(self.model),\n            \"tree_animation_speed\": self.tree_animation_speed,\n            \"tree_auto_open\": self.tree_auto_open,\n            \"tree_json_url\": tree_json_url,\n            \"tree_mouse_delay\": self.get_tree_mouse_delay(),\n            \"use_context_menu\": self.use_context_menu,\n        }\n\n        context = {\n            **self.admin_site.each_context(request),\n            \"django_major_version\": django.VERSION[0],\n            \"module_name\": str(self.opts.verbose_name_plural),\n            \"title\": change_list.title,\n            \"subtitle\": None,\n            \"is_popup\": change_list.is_popup,\n            \"to_field\": change_list.to_field,\n            \"cl\": change_list,\n            \"media\": self.get_tree_media(),\n            \"opts\": change_list.opts,\n            \"preserved_filters\": self.get_preserved_filters(request),\n            **tree_options,\n            **(extra_context or {}),\n        }\n\n        request.current_app = self.admin_site.name\n\n        return TemplateResponse(request, self.change_tree_template, context)\n\n    def get_urls(self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"]):\n        def wrap(view, cacheable=False):\n            def wrapper(*args, **kwargs):\n                return self.admin_site.admin_view(view, cacheable)(*args, **kwargs)\n\n            return update_wrapper(wrapper, view)\n\n        def create_url(regex, url_name, view, kwargs=None, cacheable=False):\n            return re_path(\n                regex,\n                wrap(view, cacheable),\n                kwargs=kwargs,\n                name=\"{0!s}_{1!s}_{2!s}\".format(\n                    self.opts.app_label,\n                    util.get_model_name(self.model),\n                    url_name,\n                ),\n            )\n\n        def create_js_catalog_url():\n            packages = [\"django_mptt_admin\"]\n            url_pattern = r\"^jsi18n/$\"\n\n            return create_url(\n                url_pattern,\n                \"jsi18n\",\n                JavaScriptCatalog.as_view(packages=packages),\n                cacheable=True,\n            )\n\n        # prepend new urls to existing urls\n        return [\n            create_url(r\"^(.+)/move/$\", \"move\", self.move_view),\n            create_url(r\"^tree_json/$\", \"tree_json\", self.tree_json_view),\n            create_url(r\"^grid/$\", \"grid\", self.grid_view),\n            create_js_catalog_url(),\n        ] + super(DjangoMpttAdminMixin, self).get_urls()\n\n    def get_tree_media(self: ModelAdmin):\n        django_mptt_admin_js = (\n            \"django_mptt_admin.coverage.js\"\n            if getattr(settings, \"DJANGO_MPTT_ADMIN_COVERAGE_JS\", False)\n            else \"django_mptt_admin.js\"\n        )\n\n        js = [\n            \"admin/js/jquery.init.js\",\n            static(\"django_mptt_admin/jquery_namespace.js\"),\n            static(f\"django_mptt_admin/{django_mptt_admin_js}\"),\n        ]\n        css = dict(all=(static(\"django_mptt_admin/django_mptt_admin.css\"),))\n\n        tree_media = Media(js=js, css=css)\n\n        return self.media + tree_media\n\n    @csrf_protect_m\n    @transaction.atomic()\n    def move_view(self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"], request, object_id):\n        request.current_app = self.admin_site.name\n        instance = self.get_object(request, unquote(object_id))\n\n        if not self.has_change_permission(request, instance):\n            raise PermissionDenied()\n\n        if request.method != \"POST\":\n            raise SuspiciousOperation()\n\n        target_id = request.POST[\"target_id\"]\n        position = request.POST[\"position\"]\n        target_instance = self.get_object(request, target_id)\n\n        self.do_move(instance, position, target_instance)\n\n        return JsonResponse(dict(success=True))\n\n    def do_move(self, instance, position, target_instance):\n        if position == \"before\":\n            instance.move_to(target_instance, \"left\")\n        elif position == \"after\":\n            instance.move_to(target_instance, \"right\")\n        elif position == \"inside\":\n            instance.move_to(target_instance)\n        else:\n            raise Exception(\"Unknown position\")\n\n        if self.trigger_save_after_move:\n            instance.save()\n\n    def get_change_list_for_tree(\n        self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"],\n        request,\n        node_id=None,\n        max_level=None,\n    ):\n        request.current_app = self.admin_site.name\n\n        return self.change_list_tree_class(\n            request=request,\n            model=self.model,\n            model_admin=self,\n            list_filter=self.get_list_filter(request),\n            node_id=node_id,\n            max_level=max_level,\n        )\n\n    def get_admin_url(self: ModelAdmin, name, args=None):\n        opts = self.opts\n        url_name = \"admin:{0!s}_{1!s}_{2!s}\".format(\n            opts.app_label, util.get_model_name(self.model), name\n        )\n        return reverse(url_name, args=args, current_app=self.admin_site.name)\n\n    def get_tree_data(\n        self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"], qs, max_level, filters_params\n    ):\n        pk_attname = self.opts.pk.attname\n\n        preserved_filters = urlencode(\n            {\"_changelist_filters\": urlencode(filters_params)}\n        )\n\n        def add_preserved_filters_to_url(url):\n            return add_preserved_filters(\n                {\"preserved_filters\": preserved_filters, \"opts\": self.opts}, url\n            )\n\n        def handle_create_node(instance, node_info):\n            pk = getattr(instance, pk_attname)\n\n            node_url = add_preserved_filters_to_url(\n                self.get_admin_url(\"change\", (quote(pk),))\n            )\n\n            node_info.update(\n                url=node_url, move_url=self.get_admin_url(\"move\", (quote(pk),))\n            )\n\n        return util.get_tree_from_queryset(\n            qs, handle_create_node, max_level, self.item_label_field_name\n        )\n\n    def tree_json_view(self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"], request):\n        request.current_app = self.admin_site.name\n        node_id = request.GET.get(\"node\")\n\n        def get_max_level():\n            if node_id:\n                node = self.model.objects.get(pk=node_id)\n                return node.level + 1\n            else:\n                return self.tree_load_on_demand\n\n        max_level = get_max_level()\n\n        change_list = self.get_change_list_for_tree(request, node_id, max_level)\n\n        qs = change_list.get_queryset(request)\n        qs = self.filter_tree_queryset(qs, request)\n\n        tree_data = self.get_tree_data(qs, max_level, change_list.get_filters_params())\n\n        # Set safe to False because the data is a list instead of a dict\n        return JsonResponse(tree_data, safe=False)\n\n    def grid_view(\n        self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"], request, extra_context=None\n    ):\n        request.current_app = self.admin_site.name\n\n        preserved_filters = self.get_preserved_filters(request)\n\n        tree_url = add_preserved_filters(\n            {\"preserved_filters\": preserved_filters, \"opts\": self.opts},\n            self.get_admin_url(\"changelist\"),\n        )\n\n        context = dict(tree_url=tree_url)\n\n        if extra_context:\n            context.update(extra_context)\n        return super(DjangoMpttAdminMixin, self).changelist_view(request, context)\n\n    def get_preserved_filters(self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"], request):\n        \"\"\"\n        Override `get_preserved_filters` to make sure that it returns the current filters for the grid view.\n        \"\"\"\n\n        def must_return_current_filters():\n            match = request.resolver_match\n\n            if not self.preserve_filters or not match:\n                return False\n            else:\n                opts = self.opts\n                current_url = \"{0!s}:{1!s}\".format(match.app_name, match.url_name)\n                grid_url = \"admin:{0!s}_{1!s}_grid\".format(\n                    opts.app_label, opts.model_name\n                )\n\n                return current_url == grid_url\n\n        if must_return_current_filters():\n            # for the grid view return the current filters\n            preserved_filters = request.GET.urlencode()\n            return urlencode({\"_changelist_filters\": preserved_filters})\n        else:\n            return super(DjangoMpttAdminMixin, self).get_preserved_filters(request)\n\n    def filter_tree_queryset(self, queryset, request):\n        \"\"\"\n        Override 'filter_tree_queryset' to filter the queryset for the tree.\n        \"\"\"\n        return queryset\n\n    def get_changeform_initial_data(\n        self: Union[ModelAdmin, \"DjangoMpttAdminMixin\"], request\n    ):\n        initial_data = super(DjangoMpttAdminMixin, self).get_changeform_initial_data(\n            request=request\n        )\n\n        if \"insert_at\" in request.GET:\n            initial_data[self.get_insert_at_field()] = request.GET.get(\"insert_at\")\n\n        return initial_data\n\n    def get_insert_at_field(self):\n        return \"parent\"\n\n    def is_drag_and_drop_enabled(self) -> bool:\n        # Override this method to disable drag-and-drop\n        return True\n\n    def get_tree_mouse_delay(self):\n        return self.tree_mouse_delay\n"
  },
  {
    "path": "django_mptt_admin/locale/ca/LC_MESSAGES/django.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-03-12 11:48+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n#: django_mptt_admin/templates/django_mptt_admin/change_list.html:31\nmsgid \"Filter\"\nmsgstr \"Filtre\"\n\n#: django_mptt_admin/templates/django_mptt_admin/change_list.html:42\nmsgid \"Grid view\"\nmsgstr \"Vista de quadrícula\"\n\n#: django_mptt_admin/templates/django_mptt_admin/grid_view.html:7\nmsgid \"Tree view\"\nmsgstr \"Vista d'arbre\"\n"
  },
  {
    "path": "django_mptt_admin/locale/ca/LC_MESSAGES/djangojs.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-03-12 11:51+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"edit\"\nmsgstr \"editar\"\n\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"add\"\nmsgstr \"afegir\"\n\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Error quan es carregaven les dades del servidor\"\n\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"move failed\"\nmsgstr \"moviment fallit\"\n"
  },
  {
    "path": "django_mptt_admin/locale/de/LC_MESSAGES/django.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-01-22 09:30+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: templates/django_mptt_admin/change_list.html:31\nmsgid \"Filter\"\nmsgstr \"\"\n\n#: templates/django_mptt_admin/change_list.html:42\nmsgid \"Grid view\"\nmsgstr \"Tabellenansicht\"\n\n#: templates/django_mptt_admin/grid_view.html:7\nmsgid \"Tree view\"\nmsgstr \"Baumansicht\"\n"
  },
  {
    "path": "django_mptt_admin/locale/de/LC_MESSAGES/djangojs.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-01-22 09:32+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"edit\"\nmsgstr \"Bearbeiten\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"add\"\nmsgstr \"Neu\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Fehler beim Laden der Daten vom Server\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"move failed\"\nmsgstr \"Verschieben fehlgeschlagen\"\n"
  },
  {
    "path": "django_mptt_admin/locale/es/LC_MESSAGES/django.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-03-12 11:55+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n#: django_mptt_admin/templates/django_mptt_admin/change_list.html:31\nmsgid \"Filter\"\nmsgstr \"Filtro\"\n\n#: django_mptt_admin/templates/django_mptt_admin/change_list.html:42\nmsgid \"Grid view\"\nmsgstr \"Vista de cuadrícula\"\n\n#: django_mptt_admin/templates/django_mptt_admin/grid_view.html:7\nmsgid \"Tree view\"\nmsgstr \"Vista de árbol\"\n"
  },
  {
    "path": "django_mptt_admin/locale/es/LC_MESSAGES/djangojs.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-03-12 11:56+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"edit\"\nmsgstr \"editar\"\n\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"add\"\nmsgstr \"añadir\"\n\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Error cuando se cargaban los datos del servidor\"\n\n#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"move failed\"\nmsgstr \"movimiento fallido\"\n"
  },
  {
    "path": "django_mptt_admin/locale/fr/LC_MESSAGES/django.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2016-11-05 20:20+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n#: django_mptt_admin/templates/django_mptt_admin/change_list.html:30\nmsgid \"Filter\"\nmsgstr \"Filtre\"\n\n#: django_mptt_admin/templates/django_mptt_admin/change_list.html:41\nmsgid \"Grid view\"\nmsgstr \"Vue Tableau\"\n\n#: django_mptt_admin/templates/django_mptt_admin/grid_view.html:7\nmsgid \"Tree view\"\nmsgstr \"Vue arbre\"\n"
  },
  {
    "path": "django_mptt_admin/locale/fr/LC_MESSAGES/djangojs.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2016-11-05 20:18+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"edit\"\nmsgstr \"éditer\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"add\"\nmsgstr \"ajouter\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"move failed\"\nmsgstr \"déplacement échoué\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Erreur en chargeant les données depuis le serveur\"\n"
  },
  {
    "path": "django_mptt_admin/locale/he/LC_MESSAGES/django.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2014-11-10 15:29+0200\\n\"\n\"PO-Revision-Date: 2014-11-10 15:30+0200\\n\"\n\"Last-Translator: Udi Oron <udioron@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 1.5.7\\n\"\n\nmsgid \"Grid view\"\nmsgstr \"תצוגה טבלאית\"\n\nmsgid \"Tree view\"\nmsgstr \"תצוגת עץ\"\n"
  },
  {
    "path": "django_mptt_admin/locale/he/LC_MESSAGES/djangojs.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2014-11-10 15:29+0200\\n\"\n\"PO-Revision-Date: 2014-11-10 15:30+0200\\n\"\n\"Last-Translator: Udi Oron <udioron@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 1.5.7\\n\"\n\nmsgid \"edit\"\nmsgstr \"עריכה\"\n\nmsgid \"add\"\nmsgstr \"הוספה\"\n\nmsgid \"move failed\"\nmsgstr \"ההעברה נכשלה\"\n\nmsgid \"Error while loading the data from the server\"\nmsgstr \"שגיאה במהלך שליחת הנתונים לשרת\"\n"
  },
  {
    "path": "django_mptt_admin/locale/hu/LC_MESSAGES/django.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2016-11-21 14:32+0100\\n\"\n\"PO-Revision-Date: 2016-11-21 14:32+0100\\n\"\n\"Last-Translator: Istvan Farkas <istvan.farkas@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: .\\templates\\django_mptt_admin\\change_list.html:30\nmsgid \"Filter\"\nmsgstr \"Szűrő\"\n\n#: .\\templates\\django_mptt_admin\\change_list.html:41\nmsgid \"Grid view\"\nmsgstr \"Táblázatos nézet\"\n\n#: .\\templates\\django_mptt_admin\\grid_view.html:7\nmsgid \"Tree view\"\nmsgstr \"Fa nézet\"\n"
  },
  {
    "path": "django_mptt_admin/locale/hu/LC_MESSAGES/djangojs.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2016-11-21 14:32+0100\\n\"\n\"PO-Revision-Date: 2016-11-21 14:32+0100\\n\"\n\"Last-Translator: Istvan Farkas <istvan.farkas@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\nmsgid \"edit\"\nmsgstr \"szerkeszt\"\n\nmsgid \"add\"\nmsgstr \"új\"\n\nmsgid \"move failed\"\nmsgstr \"mozgatás sikertelen\"\n\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Hiba történt az adatok betöltése közben\"\n"
  },
  {
    "path": "django_mptt_admin/locale/pl/LC_MESSAGES/django.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-01-22 09:30+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: templates/django_mptt_admin/change_list.html:31\nmsgid \"Filter\"\nmsgstr \"Filtruj\"\n\n#: templates/django_mptt_admin/change_list.html:42\nmsgid \"Grid view\"\nmsgstr \"Widok tabeli\"\n\n#: templates/django_mptt_admin/grid_view.html:7\nmsgid \"Tree view\"\nmsgstr \"Widok drzewa\"\n"
  },
  {
    "path": "django_mptt_admin/locale/pl/LC_MESSAGES/djangojs.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2020-01-22 09:32+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"edit\"\nmsgstr \"zmień\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"add\"\nmsgstr \"dodaj\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Błąd podczas wczytywania danych z serwera\"\n\n#: static/django_mptt_admin/django_mptt_admin.js:1\nmsgid \"move failed\"\nmsgstr \"przenoszenie nieudane\"\n"
  },
  {
    "path": "django_mptt_admin/locale/ru/LC_MESSAGES/django.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-05-21 00:42+0300\\n\"\n\"PO-Revision-Date: 2015-05-21 00:42+0300\\n\"\n\"Last-Translator: Mikhail Silonov <m.silonov@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n\"\n\"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\\n\"\n\nmsgid \"Grid view\"\nmsgstr \"В виде сетки\"\n\nmsgid \"Tree view\"\nmsgstr \"В виде дерева\"\n"
  },
  {
    "path": "django_mptt_admin/locale/ru/LC_MESSAGES/djangojs.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-05-21 00:42+0300\\n\"\n\"PO-Revision-Date: 2015-05-21 00:42+0300\\n\"\n\"Last-Translator: Mikhail Silonov <m.silonov@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n\"\n\"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\\n\"\n\nmsgid \"edit\"\nmsgstr \"редактировать\"\n\nmsgid \"add\"\nmsgstr \"Добавить\"\n\nmsgid \"move failed\"\nmsgstr \"не удалось переместить\"\n\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Ошибка при загрузке данных с сервера\"\n\nmsgid \"Grid view\"\nmsgstr \"В виде сетки\"\n\nmsgid \"Tree view\"\nmsgstr \"В виде дерева\"\n"
  },
  {
    "path": "django_mptt_admin/locale/tr/LC_MESSAGES/django.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-01-05 06:00+0300\\n\"\n\"PO-Revision-Date: 2015-01-05 06:00+0300\\n\"\n\"Last-Translator: Emir Tagmat <emir@tagmat.net>\\n\"\n\"Language-Team: \\n\"\n\"Language: Turkish\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\nmsgid \"Grid view\"\nmsgstr \"Tablo görünümü\"\n\nmsgid \"Tree view\"\nmsgstr \"Ağaç görünümü\"\n"
  },
  {
    "path": "django_mptt_admin/locale/tr/LC_MESSAGES/djangojs.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-01-05 06:00+0300\\n\"\n\"PO-Revision-Date: 2015-01-05 06:00+0300\\n\"\n\"Last-Translator: Emir Tagmat <emir@tagmat.net>\\n\"\n\"Language-Team: \\n\"\n\"Language: Turkish\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\nmsgid \"edit\"\nmsgstr \"düzenle\"\n\nmsgid \"add\"\nmsgstr \"ekle\"\n\nmsgid \"move failed\"\nmsgstr \"taşıma başarısız\"\n\nmsgid \"Error while loading the data from the server\"\nmsgstr \"Veri sunucudan yüklenirken hata oluştu\"\n"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.css",
    "content": "ul.jqtree-tree {\n  list-style: none outside;\n  margin-left: 0;\n  margin-bottom: 0;\n  padding: 0;\n}\n\nul.jqtree-tree.jqtree-dnd {\n  touch-action: none;\n}\n\nul.jqtree-tree ul.jqtree_common {\n  list-style: none outside;\n  margin-left: 12px;\n  margin-right: 0;\n  margin-bottom: 0;\n  padding: 0;\n  display: block;\n}\n\nul.jqtree-tree li.jqtree-closed > ul.jqtree_common {\n  display: none;\n}\n\nul.jqtree-tree li.jqtree_common {\n  clear: both;\n  list-style-type: none;\n}\n\nul.jqtree-tree .jqtree-toggler {\n  border-bottom: none;\n  color: #333;\n  text-decoration: none;\n  vertical-align: middle;\n}\n\nul.jqtree-tree .jqtree-toggler:hover {\n  color: #000;\n  text-decoration: none;\n}\n\nul.jqtree-tree .jqtree-toggler.jqtree-closed {\n  background-position: 0 0;\n}\n\nul.jqtree-tree .jqtree-toggler.jqtree-toggler-left {\n  margin-right: 0.5em;\n}\n\nul.jqtree-tree .jqtree-toggler.jqtree-toggler-right {\n  margin-left: 0.5em;\n}\n\nul.jqtree-tree .jqtree-element {\n  cursor: pointer;\n  position: relative;\n  display: flex;\n}\n\nul.jqtree-tree .jqtree-element:has(.jqtree-title-button-right) {\n  display: block;\n}\n\nul.jqtree-tree .jqtree-title {\n  color: #1c4257;\n  vertical-align: middle;\n}\n\nul.jqtree-tree .jqtree-title-button-left {\n  margin-left: 1.5em;\n}\n\nul.jqtree-tree .jqtree-title-button-left.jqtree-title-folder {\n  margin-left: 0;\n}\n\nul.jqtree-tree li.jqtree-folder {\n  margin-bottom: 4px;\n}\n\nul.jqtree-tree li.jqtree-folder.jqtree-closed {\n  margin-bottom: 1px;\n}\n\nul.jqtree-tree li.jqtree-ghost {\n  position: relative;\n  z-index: 10;\n  margin-right: 10px;\n}\n\nul.jqtree-tree li.jqtree-ghost span {\n  display: block;\n}\n\nul.jqtree-tree li.jqtree-ghost span.jqtree-circle {\n  border: solid 2px #0000ff;\n  border-radius: 100px;\n  height: 8px;\n  width: 8px;\n  position: absolute;\n  top: -4px;\n  left: -6px;\n  box-sizing: border-box;\n}\n\nul.jqtree-tree li.jqtree-ghost span.jqtree-line {\n  background-color: #0000ff;\n  height: 2px;\n  padding: 0;\n  position: absolute;\n  top: -1px;\n  left: 2px;\n  width: 100%;\n}\n\nul.jqtree-tree li.jqtree-ghost.jqtree-inside {\n  margin-left: 48px;\n}\n\nul.jqtree-tree span.jqtree-border {\n  position: absolute;\n  display: block;\n  left: -2px;\n  top: 0;\n  border: solid 2px #0000ff;\n  border-radius: 6px;\n  margin: 0;\n  box-sizing: content-box;\n}\n\nul.jqtree-tree li.jqtree-selected > .jqtree-element,\nul.jqtree-tree li.jqtree-selected > .jqtree-element:hover {\n  background-color: #97bdd6;\n  background: linear-gradient(#bee0f5, #89afca);\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);\n}\n\nul.jqtree-tree .jqtree-moving > .jqtree-element .jqtree-title {\n  outline: dashed 1px #0000ff;\n}\n\nul.jqtree-tree.jqtree-rtl {\n  direction: rtl;\n}\n\nul.jqtree-tree.jqtree-rtl ul.jqtree_common {\n  margin-left: 0;\n  margin-right: 12px;\n}\n\nul.jqtree-tree.jqtree-rtl .jqtree-toggler {\n  margin-left: 0.5em;\n  margin-right: 0;\n}\n\nul.jqtree-tree.jqtree-rtl .jqtree-title {\n  margin-left: 0;\n  margin-right: 1.5em;\n}\n\nul.jqtree-tree.jqtree-rtl .jqtree-title.jqtree-title-folder {\n  margin-right: 0;\n}\n\nul.jqtree-tree.jqtree-rtl li.jqtree-ghost {\n  margin-right: 0;\n  margin-left: 10px;\n}\n\nul.jqtree-tree.jqtree-rtl li.jqtree-ghost span.jqtree-circle {\n  right: -6px;\n}\n\nul.jqtree-tree.jqtree-rtl li.jqtree-ghost span.jqtree-line {\n  right: 2px;\n}\n\nul.jqtree-tree.jqtree-rtl li.jqtree-ghost.jqtree-inside {\n  margin-left: 0;\n  margin-right: 48px;\n}\n\nul.jqtree-tree.jqtree-rtl span.jqtree-border {\n  right: -2px;\n}\n\nspan.jqtree-dragging {\n  color: #fff;\n  background: #000;\n  opacity: 0.6;\n  cursor: pointer;\n  padding: 2px 8px;\n}\n\n@keyframes jqtree-spin {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n#changelist {\n  border: none;\n}\n\n#tree {\n  padding: 1em 0 1em 0;\n}\n#tree .mptt-admin-error {\n  color: var(--error-fg);\n  margin-left: 8px;\n}\n#tree ul.jqtree-tree .jqtree-toggler {\n  top: 10%;\n  color: var(--link-fg);\n  text-decoration: none;\n}\n#tree ul.jqtree-tree .edit {\n  margin-left: 0.5em;\n  vertical-align: middle;\n  color: var(--link-fg);\n}\n#tree ul.jqtree-tree ul.jqtree_common {\n  margin-top: 0;\n}\n#tree ul.jqtree-tree li.jqtree_common {\n  padding: 0;\n}\n#tree ul.jqtree-tree.jqtree-rtl .edit {\n  margin-left: 0;\n  margin-right: 0.5em;\n}\n#tree .jqtree-spin {\n  margin-left: 1em;\n  width: 1em;\n  height: 1em;\n  border: 2px solid var(--body-fg);\n  border-bottom-color: transparent;\n  border-radius: 50%;\n  display: inline-block;\n  box-sizing: border-box;\n  animation: jqtree-spin 1s linear infinite;\n  vertical-align: middle;\n}\n#tree.block-style ul.jqtree-tree {\n  margin-left: 0;\n  margin-right: 0;\n}\n#tree.block-style ul.jqtree-tree ul.jqtree_common {\n  margin-left: 2em;\n}\n#tree.block-style ul.jqtree-tree .jqtree-element {\n  margin-bottom: 8px;\n  background-color: var(--darkened-bg);\n  padding: 8px;\n}\n#tree.block-style ul.jqtree-tree .jqtree-element .jqtree-title {\n  color: var(--body-fg);\n  margin-left: 0;\n  margin-right: 0;\n}\n#tree.block-style ul.jqtree-tree .jqtree-element .jqtree-toggler.jqtree-toggler-right {\n  margin-left: 1em;\n}\n#tree.block-style ul.jqtree-tree li.jqtree-selected > .jqtree-element {\n  background: var(--breadcrumbs-bg);\n  color: var(--header-color);\n  text-shadow: none;\n}\n#tree.block-style ul.jqtree-tree li.jqtree-selected > .jqtree-element .jqtree-title {\n  color: var(--breadcrumbs-link-fg);\n}\n#tree.block-style ul.jqtree-tree li.jqtree-selected > .jqtree-element .edit {\n  color: var(--breadcrumbs-fg);\n}\n#tree.block-style ul.jqtree-tree.jqtree-rtl ul.jqtree_common {\n  margin-left: 0;\n  margin-right: 2em;\n}\n#tree.block-style ul.jqtree-tree.jqtree-rtl .jqtree-toggler.jqtree-toggler-right {\n  margin-left: 0;\n  margin-right: 1em;\n}\n\n/*# sourceMappingURL=django_mptt_admin.css.map */\n"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.debug.js",
    "content": "/******/ (() => { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 163\n(__unused_webpack_module, exports) {\n\n\"use strict\";\nvar __webpack_unused_export__;\n\n__webpack_unused_export__ = ({ value: true });\n__webpack_unused_export__ = parseCookie;\nexports.qg = parseCookie;\n__webpack_unused_export__ = stringifyCookie;\n__webpack_unused_export__ = stringifySetCookie;\n__webpack_unused_export__ = stringifySetCookie;\n__webpack_unused_export__ = parseSetCookie;\n__webpack_unused_export__ = stringifySetCookie;\n__webpack_unused_export__ = stringifySetCookie;\n/**\n * RegExp to match cookie-name in RFC 6265 sec 4.1.1\n * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2\n * which has been replaced by the token definition in RFC 7230 appendix B.\n *\n * cookie-name       = token\n * token             = 1*tchar\n * tchar             = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" /\n *                     \"*\" / \"+\" / \"-\" / \".\" / \"^\" / \"_\" /\n *                     \"`\" / \"|\" / \"~\" / DIGIT / ALPHA\n *\n * Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191\n * Allow same range as cookie value, except `=`, which delimits end of name.\n */\nconst cookieNameRegExp = /^[\\u0021-\\u003A\\u003C\\u003E-\\u007E]+$/;\n/**\n * RegExp to match cookie-value in RFC 6265 sec 4.1.1\n *\n * cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )\n * cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E\n *                     ; US-ASCII characters excluding CTLs,\n *                     ; whitespace DQUOTE, comma, semicolon,\n *                     ; and backslash\n *\n * Allowing more characters: https://github.com/jshttp/cookie/issues/191\n * Comma, backslash, and DQUOTE are not part of the parsing algorithm.\n */\nconst cookieValueRegExp = /^[\\u0021-\\u003A\\u003C-\\u007E]*$/;\n/**\n * RegExp to match domain-value in RFC 6265 sec 4.1.1\n *\n * domain-value      = <subdomain>\n *                     ; defined in [RFC1034], Section 3.5, as\n *                     ; enhanced by [RFC1123], Section 2.1\n * <subdomain>       = <label> | <subdomain> \".\" <label>\n * <label>           = <let-dig> [ [ <ldh-str> ] <let-dig> ]\n *                     Labels must be 63 characters or less.\n *                     'let-dig' not 'letter' in the first char, per RFC1123\n * <ldh-str>         = <let-dig-hyp> | <let-dig-hyp> <ldh-str>\n * <let-dig-hyp>     = <let-dig> | \"-\"\n * <let-dig>         = <letter> | <digit>\n * <letter>          = any one of the 52 alphabetic characters A through Z in\n *                     upper case and a through z in lower case\n * <digit>           = any one of the ten digits 0 through 9\n *\n * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173\n *\n * > (Note that a leading %x2E (\".\"), if present, is ignored even though that\n * character is not permitted, but a trailing %x2E (\".\"), if present, will\n * cause the user agent to ignore the attribute.)\n */\nconst domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;\n/**\n * RegExp to match path-value in RFC 6265 sec 4.1.1\n *\n * path-value        = <any CHAR except CTLs or \";\">\n * CHAR              = %x01-7F\n *                     ; defined in RFC 5234 appendix B.1\n */\nconst pathValueRegExp = /^[\\u0020-\\u003A\\u003D-\\u007E]*$/;\n/**\n * RegExp to match max-age-value in RFC 6265 sec 5.6.2\n */\nconst maxAgeRegExp = /^-?\\d+$/;\nconst __toString = Object.prototype.toString;\nconst NullObject = /* @__PURE__ */ (() => {\n    const C = function () { };\n    C.prototype = Object.create(null);\n    return C;\n})();\n/**\n * Parse a `Cookie` header.\n *\n * Parse the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nfunction parseCookie(str, options) {\n    const obj = new NullObject();\n    const len = str.length;\n    // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.\n    if (len < 2)\n        return obj;\n    const dec = options?.decode || decode;\n    let index = 0;\n    do {\n        const eqIdx = eqIndex(str, index, len);\n        if (eqIdx === -1)\n            break; // No more cookie pairs.\n        const endIdx = endIndex(str, index, len);\n        if (eqIdx > endIdx) {\n            // backtrack on prior semicolon\n            index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n            continue;\n        }\n        const key = valueSlice(str, index, eqIdx);\n        // only assign once\n        if (obj[key] === undefined) {\n            obj[key] = dec(valueSlice(str, eqIdx + 1, endIdx));\n        }\n        index = endIdx + 1;\n    } while (index < len);\n    return obj;\n}\n/**\n * Stringifies an object into an HTTP `Cookie` header.\n */\nfunction stringifyCookie(cookie, options) {\n    const enc = options?.encode || encodeURIComponent;\n    const cookieStrings = [];\n    for (const name of Object.keys(cookie)) {\n        const val = cookie[name];\n        if (val === undefined)\n            continue;\n        if (!cookieNameRegExp.test(name)) {\n            throw new TypeError(`cookie name is invalid: ${name}`);\n        }\n        const value = enc(val);\n        if (!cookieValueRegExp.test(value)) {\n            throw new TypeError(`cookie val is invalid: ${val}`);\n        }\n        cookieStrings.push(`${name}=${value}`);\n    }\n    return cookieStrings.join(\"; \");\n}\nfunction stringifySetCookie(_name, _val, _opts) {\n    const cookie = typeof _name === \"object\"\n        ? _name\n        : { ..._opts, name: _name, value: String(_val) };\n    const options = typeof _val === \"object\" ? _val : _opts;\n    const enc = options?.encode || encodeURIComponent;\n    if (!cookieNameRegExp.test(cookie.name)) {\n        throw new TypeError(`argument name is invalid: ${cookie.name}`);\n    }\n    const value = cookie.value ? enc(cookie.value) : \"\";\n    if (!cookieValueRegExp.test(value)) {\n        throw new TypeError(`argument val is invalid: ${cookie.value}`);\n    }\n    let str = cookie.name + \"=\" + value;\n    if (cookie.maxAge !== undefined) {\n        if (!Number.isInteger(cookie.maxAge)) {\n            throw new TypeError(`option maxAge is invalid: ${cookie.maxAge}`);\n        }\n        str += \"; Max-Age=\" + cookie.maxAge;\n    }\n    if (cookie.domain) {\n        if (!domainValueRegExp.test(cookie.domain)) {\n            throw new TypeError(`option domain is invalid: ${cookie.domain}`);\n        }\n        str += \"; Domain=\" + cookie.domain;\n    }\n    if (cookie.path) {\n        if (!pathValueRegExp.test(cookie.path)) {\n            throw new TypeError(`option path is invalid: ${cookie.path}`);\n        }\n        str += \"; Path=\" + cookie.path;\n    }\n    if (cookie.expires) {\n        if (!isDate(cookie.expires) || !Number.isFinite(cookie.expires.valueOf())) {\n            throw new TypeError(`option expires is invalid: ${cookie.expires}`);\n        }\n        str += \"; Expires=\" + cookie.expires.toUTCString();\n    }\n    if (cookie.httpOnly) {\n        str += \"; HttpOnly\";\n    }\n    if (cookie.secure) {\n        str += \"; Secure\";\n    }\n    if (cookie.partitioned) {\n        str += \"; Partitioned\";\n    }\n    if (cookie.priority) {\n        const priority = typeof cookie.priority === \"string\"\n            ? cookie.priority.toLowerCase()\n            : undefined;\n        switch (priority) {\n            case \"low\":\n                str += \"; Priority=Low\";\n                break;\n            case \"medium\":\n                str += \"; Priority=Medium\";\n                break;\n            case \"high\":\n                str += \"; Priority=High\";\n                break;\n            default:\n                throw new TypeError(`option priority is invalid: ${cookie.priority}`);\n        }\n    }\n    if (cookie.sameSite) {\n        const sameSite = typeof cookie.sameSite === \"string\"\n            ? cookie.sameSite.toLowerCase()\n            : cookie.sameSite;\n        switch (sameSite) {\n            case true:\n            case \"strict\":\n                str += \"; SameSite=Strict\";\n                break;\n            case \"lax\":\n                str += \"; SameSite=Lax\";\n                break;\n            case \"none\":\n                str += \"; SameSite=None\";\n                break;\n            default:\n                throw new TypeError(`option sameSite is invalid: ${cookie.sameSite}`);\n        }\n    }\n    return str;\n}\n/**\n * Deserialize a `Set-Cookie` header into an object.\n *\n * deserialize('foo=bar; httpOnly')\n *   => { name: 'foo', value: 'bar', httpOnly: true }\n */\nfunction parseSetCookie(str, options) {\n    const dec = options?.decode || decode;\n    const len = str.length;\n    const endIdx = endIndex(str, 0, len);\n    const eqIdx = eqIndex(str, 0, endIdx);\n    const setCookie = eqIdx === -1\n        ? { name: \"\", value: dec(valueSlice(str, 0, endIdx)) }\n        : {\n            name: valueSlice(str, 0, eqIdx),\n            value: dec(valueSlice(str, eqIdx + 1, endIdx)),\n        };\n    let index = endIdx + 1;\n    while (index < len) {\n        const endIdx = endIndex(str, index, len);\n        const eqIdx = eqIndex(str, index, endIdx);\n        const attr = eqIdx === -1\n            ? valueSlice(str, index, endIdx)\n            : valueSlice(str, index, eqIdx);\n        const val = eqIdx === -1 ? undefined : valueSlice(str, eqIdx + 1, endIdx);\n        switch (attr.toLowerCase()) {\n            case \"httponly\":\n                setCookie.httpOnly = true;\n                break;\n            case \"secure\":\n                setCookie.secure = true;\n                break;\n            case \"partitioned\":\n                setCookie.partitioned = true;\n                break;\n            case \"domain\":\n                setCookie.domain = val;\n                break;\n            case \"path\":\n                setCookie.path = val;\n                break;\n            case \"max-age\":\n                if (val && maxAgeRegExp.test(val))\n                    setCookie.maxAge = Number(val);\n                break;\n            case \"expires\":\n                if (!val)\n                    break;\n                const date = new Date(val);\n                if (Number.isFinite(date.valueOf()))\n                    setCookie.expires = date;\n                break;\n            case \"priority\":\n                if (!val)\n                    break;\n                const priority = val.toLowerCase();\n                if (priority === \"low\" ||\n                    priority === \"medium\" ||\n                    priority === \"high\") {\n                    setCookie.priority = priority;\n                }\n                break;\n            case \"samesite\":\n                if (!val)\n                    break;\n                const sameSite = val.toLowerCase();\n                if (sameSite === \"lax\" ||\n                    sameSite === \"strict\" ||\n                    sameSite === \"none\") {\n                    setCookie.sameSite = sameSite;\n                }\n                break;\n        }\n        index = endIdx + 1;\n    }\n    return setCookie;\n}\n/**\n * Find the `;` character between `min` and `len` in str.\n */\nfunction endIndex(str, min, len) {\n    const index = str.indexOf(\";\", min);\n    return index === -1 ? len : index;\n}\n/**\n * Find the `=` character between `min` and `max` in str.\n */\nfunction eqIndex(str, min, max) {\n    const index = str.indexOf(\"=\", min);\n    return index < max ? index : -1;\n}\n/**\n * Slice out a value between startPod to max.\n */\nfunction valueSlice(str, min, max) {\n    let start = min;\n    let end = max;\n    do {\n        const code = str.charCodeAt(start);\n        if (code !== 0x20 /*   */ && code !== 0x09 /* \\t */)\n            break;\n    } while (++start < end);\n    while (end > start) {\n        const code = str.charCodeAt(end - 1);\n        if (code !== 0x20 /*   */ && code !== 0x09 /* \\t */)\n            break;\n        end--;\n    }\n    return str.slice(start, end);\n}\n/**\n * URL-decode string value. Optimized to skip native call when no %.\n */\nfunction decode(str) {\n    if (str.indexOf(\"%\") === -1)\n        return str;\n    try {\n        return decodeURIComponent(str);\n    }\n    catch (e) {\n        return str;\n    }\n}\n/**\n * Determine if value is a Date.\n */\nfunction isDate(val) {\n    return __toString.call(val) === \"[object Date]\";\n}\n//# sourceMappingURL=index.js.map\n\n/***/ },\n\n/***/ 751\n() {\n\n/*\nJqTree 1.8.11\n\nCopyright 2026 Marco Braak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n@license\n\n*/\nvar jqtree=function(e){\"use strict\";class t{constructor({dataFilter:e,loadData:t,onLoadFailed:o,onLoading:n,treeElement:s,triggerEvent:r}){this.dataFilter=e,this.loadData=t,this.onLoadFailed=o,this.onLoading=n,this.treeElement=s,this.triggerEvent=r}loadFromUrl(e,t,o){if(!e)return;const n=this.getDomElement(t);this.addLoadingClass(n),this.notifyLoading(!0,t,n);const s=()=>{this.removeLoadingClass(n),this.notifyLoading(!1,t,n)};this.submitRequest(e,e=>{s(),this.loadData(this.parseData(e),t),o&&\"function\"==typeof o&&o()},e=>{s(),this.onLoadFailed&&this.onLoadFailed(e)})}addLoadingClass(e){e.classList.add(\"jqtree-loading\")}getDomElement(e){return e?.element?e.element:this.treeElement}notifyLoading(e,t,o){const n=jQuery(o);this.onLoading&&this.onLoading(e,t,n),this.triggerEvent(\"tree.loading_data\",{$el:n,isLoading:e,node:t})}parseData(e){const t=\"string\"==typeof e?JSON.parse(e):e;return this.dataFilter?this.dataFilter(t):t}removeLoadingClass(e){e.classList.remove(\"jqtree-loading\")}submitRequest(e,t,o){const n={cache:!1,dataType:\"json\",error:o,method:\"GET\",success:t,...\"string\"==typeof e?{url:e}:e};n.method=n.method?.toUpperCase()??\"GET\",jQuery.ajax(n)}}const o=e=>e?\"true\":\"false\",n=e=>s(e).top,s=e=>{const t=e.getBoundingClientRect();return{left:t.x+window.scrollX,top:t.y+window.scrollY}};class r{constructor({autoEscape:e,nodeName:t,offsetX:o,offsetY:n,treeElement:s}){this.offsetX=o,this.offsetY=n,this.element=this.createElement(t,e),s.appendChild(this.element)}move(e,t){this.element.style.left=e-this.offsetX+\"px\",this.element.style.top=t-this.offsetY+\"px\"}remove(){this.element.remove()}createElement(e,t){const o=document.createElement(\"span\");return o.classList.add(\"jqtree-title\",\"jqtree-dragging\"),t?o.textContent=e:o.innerHTML=e,o.style.position=\"absolute\",o}}const i=(e,t,o,n)=>{const s=Math.min(t.length,4),r=Math.round((n-o)/s);let i=o;for(let o=0;o<s;o++){const n=t[o];n.position&&e.push({bottom:i+r,node:n.node,position:n.position,top:i}),i+=r}},l=(e,t,o)=>((e,t)=>{if(!e.length)return[];let o=e[0].top,n=[];const s=[];for(const t of e)t.top!==o&&n.length&&(i(s,n,o,t.top),o=t.top,n=[]),n.push(t);return i(s,n,o,t),s})(((e,t)=>{const o=[];let s=0;const r=(e,t,n)=>{o.push({node:e,position:t,top:n}),s=n};return((e,{handleAfterOpenFolder:t,handleClosedFolder:o,handleFirstNode:n,handleNode:s,handleOpenFolder:r})=>{let i=!0;const l=(e,d)=>{let a=(e.is_open||!e.element)&&e.hasChildren(),h=null;if(e.element?.offsetParent&&(h=e.element,i&&(n(e),i=!1),e.hasChildren()?e.is_open?r(e,e.element)||(a=!1):o(e,d,h):s(e,d,e.element)),a){const o=e.children.length;e.children.forEach((t,n)=>{const s=e.children[n];if(s)if(n===o-1)l(s,null);else{const t=e.children[n+1];t&&l(s,t)}}),e.is_open&&h&&t(e,d)}};l(e,null)})(e,{handleAfterOpenFolder:(e,o)=>{r(e,e===t||o===t?null:\"after\",s)},handleClosedFolder:(e,o,s)=>{const i=n(s);e===t?r(e,null,i):(r(e,\"inside\",i),o!==t&&r(e,\"after\",i))},handleFirstNode:e=>{e!==t&&e.element&&r(e,\"before\",n(e.element))},handleNode:(e,o,s)=>{const i=n(s);r(e,e===t?null:\"inside\",i),r(e,o===t||e===t?null:\"after\",i)},handleOpenFolder:(e,o)=>{if(e===t){const t=n(o),s=o.clientHeight;return r(e,null,t),s>5&&r(e,null,t+s-5),!1}return e.children[0]!==t&&r(e,\"inside\",n(o)),!0}}),o})(e,t),o);class d{constructor({autoEscape:e,getNodeElement:t,getNodeElementForNode:o,getScrollLeft:n,getTree:s,onCanMove:r,onCanMoveTo:i,onDragMove:l,onDragStop:d,onIsMoveHandle:a,openFolderDelay:h,openNode:c,refreshElements:u,slide:m,treeElement:g,triggerEvent:p}){this.autoEscape=e,this.getNodeElement=t,this.getNodeElementForNode=o,this.getScrollLeft=n,this.getTree=s,this.onCanMove=r,this.onCanMoveTo=i,this.onDragMove=l,this.onDragStop=d,this.onIsMoveHandle=a,this.openFolderDelay=h,this.openNode=c,this.refreshElements=u,this.slide=m,this.treeElement=g,this.triggerEvent=p,this.hoveredArea=null,this.hitAreas=[],this.isDragging=!1,this.currentItem=null}mouseCapture(e){const t=e.target;if(!this.mustCaptureElement(t))return null;if(this.onIsMoveHandle&&!this.onIsMoveHandle(jQuery(t)))return null;let o=this.getNodeElement(t);return o&&this.onCanMove&&(this.onCanMove(o.node)||(o=null)),this.currentItem=o,null!=this.currentItem}mouseDrag(e){if(!this.currentItem||!this.dragElement)return!1;this.dragElement.move(e.pageX,e.pageY);const t=this.findHoveredArea(e.pageX,e.pageY);return t&&this.canMoveToArea(t,this.currentItem)?(t.node.isFolder()||this.stopOpenFolderTimer(),this.hoveredArea!==t&&(this.hoveredArea=t,this.mustOpenFolderTimer(t)?this.startOpenFolderTimer(t.node):this.stopOpenFolderTimer(),this.updateDropHint())):(this.removeDropHint(),this.stopOpenFolderTimer(),this.hoveredArea=t),t||this.onDragMove&&this.onDragMove(this.currentItem.node,e.originalEvent),!0}mouseStart(e){if(!this.currentItem)return!1;this.refresh();const{left:t,top:o}=s(e.target),n=this.currentItem.node;return this.dragElement=new r({autoEscape:this.autoEscape??!0,nodeName:n.name,offsetX:e.pageX-t,offsetY:e.pageY-o,treeElement:this.treeElement}),this.isDragging=!0,this.currentItem.element.classList.add(\"jqtree-moving\"),!0}mouseStop(e){this.moveItem(e),this.clear(),this.removeHover(),this.removeDropHint(),this.removeHitAreas();const t=this.currentItem;return this.currentItem&&(this.currentItem.element.classList.remove(\"jqtree-moving\"),this.currentItem=null),this.isDragging=!1,!this.hoveredArea&&t&&this.onDragStop&&this.onDragStop(t.node,e.originalEvent),!1}refresh(){if(this.removeHitAreas(),this.currentItem){const e=this.currentItem.node;this.generateHitAreas(e),this.currentItem=this.getNodeElementForNode(e),this.isDragging&&this.currentItem.element.classList.add(\"jqtree-moving\")}}canMoveToArea(e,t){return!this.onCanMoveTo||this.onCanMoveTo(t.node,e.node,e.position)}clear(){this.dragElement&&(this.dragElement.remove(),this.dragElement=null)}findHoveredArea(e,t){const o=this.getTreeDimensions();return e<o.left||t<o.top||e>o.right||t>o.bottom?null:function(e,t){let o=0,n=e.length;for(;o<n;){const s=o+n>>1,r=e[s];if(void 0===r)return null;const i=t(r);if(i>0)n=s;else{if(!(i<0))return r;o=s+1}}return null}(this.hitAreas,e=>t<e.top?1:t>e.bottom?-1:0)}generateHitAreas(e){const t=this.getTree();this.hitAreas=t?l(t,e,this.getTreeDimensions().bottom):[]}getTreeDimensions(){const e=s(this.treeElement),t=e.left+this.getScrollLeft(),o=e.top;return{bottom:o+this.treeElement.clientHeight+16,left:t,right:t+this.treeElement.clientWidth,top:o}}moveItem(e){if(this.currentItem&&this.hoveredArea?.position&&this.canMoveToArea(this.hoveredArea,this.currentItem)){const t=this.currentItem.node,o=this.hoveredArea.node,n=this.hoveredArea.position,s=t.parent;\"inside\"===n&&(this.hoveredArea.node.is_open=!0);const r=()=>{const e=this.getTree();e&&(e.moveNode(t,o,n),this.treeElement.textContent=\"\",this.refreshElements(null))};this.triggerEvent(\"tree.move\",{move_info:{do_move:r,moved_node:t,original_event:e.originalEvent,position:n,previous_parent:s,target_node:o}}).isDefaultPrevented()||r()}}mustCaptureElement(e){const t=e.nodeName;return\"INPUT\"!==t&&\"SELECT\"!==t&&\"TEXTAREA\"!==t}mustOpenFolderTimer(e){const t=e.node;return t.isFolder()&&!t.is_open&&\"inside\"===e.position}removeDropHint(){this.previousGhost&&this.previousGhost.remove()}removeHitAreas(){this.hitAreas=[]}removeHover(){this.hoveredArea=null}startOpenFolderTimer(e){const t=()=>{this.openNode(e,this.slide,()=>{this.refresh(),this.updateDropHint()})};this.stopOpenFolderTimer();const o=this.openFolderDelay;!1!==o&&(this.openFolderTimer=window.setTimeout(t,o))}stopOpenFolderTimer(){this.openFolderTimer&&(clearTimeout(this.openFolderTimer),this.openFolderTimer=null)}updateDropHint(){if(!this.hoveredArea)return;this.removeDropHint();const e=this.getNodeElementForNode(this.hoveredArea.node);this.previousGhost=e.addDropHint(this.hoveredArea.position)}}class a{constructor({$element:e,autoEscape:t,buttonLeft:o,closedIcon:n,dragAndDrop:s,getTree:r,isNodeSelected:i,onCreateLi:l,openedIcon:d,rtl:a,showEmptyFolder:h,tabIndex:c}){this.autoEscape=t,this.buttonLeft=o,this.dragAndDrop=s,this.$element=e,this.getTree=r,this.isNodeSelected=i,this.onCreateLi=l,this.rtl=a,this.showEmptyFolder=h,this.tabIndex=c,this.openedIconElement=this.createButtonElement(d??\"+\"),this.closedIconElement=this.createButtonElement(n??\"-\")}render(e){e?.parent?this.renderFromNode(e):this.renderFromRoot()}renderFromNode(e){if(!e.element)return;const t=jQuery(e.element),o=this.createLi(e,e.getLevel());t.after(o),t.remove(),this.createDomElements(o,e.children,!1,e.getLevel()+1)}renderFromRoot(){this.$element.empty();const e=this.getTree();this.$element[0]&&e&&this.createDomElements(this.$element[0],e.children,!0,1)}attachNodeData(e,t){e.element=t,jQuery(t).data(\"node\",e)}createButtonElement(e){if(\"string\"==typeof e){const t=document.createElement(\"div\");return t.innerHTML=e,document.createTextNode(t.innerHTML)}return e.nodeType?e:jQuery(e)[0]}createDomElements(e,t,o,n){const s=this.createUl(o);e.appendChild(s);for(const e of t){const t=this.createLi(e,n);s.appendChild(t),e.hasChildren()&&this.createDomElements(t,e.children,!1,n+1)}}createFolderLi(e,t,n){const s=this.getButtonClasses(e),r=this.getFolderClasses(e,n),i=e.is_open?this.openedIconElement:this.closedIconElement,l=document.createElement(\"li\");l.className=`jqtree_common ${r}`,l.setAttribute(\"role\",\"none\");const d=document.createElement(\"div\");d.className=\"jqtree-element jqtree_common\",d.setAttribute(\"role\",\"none\"),l.appendChild(d);const a=document.createElement(\"a\");a.className=s,i&&a.appendChild(i.cloneNode(!0)),this.buttonLeft&&d.appendChild(a);const h=this.createTitleSpan(e.name,n,!0,t);return h.setAttribute(\"aria-expanded\",o(e.is_open)),d.appendChild(h),this.buttonLeft||d.appendChild(a),l}createLi(e,t){const o=this.isNodeSelected(e),n=e.isFolder()||e.isEmptyFolder&&this.showEmptyFolder?this.createFolderLi(e,t,o):this.createNodeLi(e,t,o);return this.attachNodeData(e,n),this.onCreateLi&&this.onCreateLi(e,jQuery(n),o),n}createNodeLi(e,t,o){const n=[\"jqtree_common\"];o&&n.push(\"jqtree-selected\");const s=n.join(\" \"),r=document.createElement(\"li\");r.className=s,r.setAttribute(\"role\",\"none\");const i=document.createElement(\"div\");i.className=\"jqtree-element jqtree_common\",i.setAttribute(\"role\",\"none\"),r.appendChild(i);const l=this.createTitleSpan(e.name,o,!1,t);return i.appendChild(l),r}createTitleSpan(e,t,o,n){const s=document.createElement(\"span\");let r=\"jqtree-title jqtree_common\";if(o&&(r+=\" jqtree-title-folder\"),r+=\" jqtree-title-button-\"+(this.buttonLeft?\"left\":\"right\"),s.className=r,t){const e=this.tabIndex;void 0!==e&&s.setAttribute(\"tabindex\",`${e}`)}return this.setTreeItemAriaAttributes(s,e,n,t),this.autoEscape?s.textContent=e:s.innerHTML=e,s}createUl(e){let t,o;e?(t=\"jqtree-tree\",o=\"tree\",this.rtl&&(t+=\" jqtree-rtl\")):(t=\"\",o=\"group\"),this.dragAndDrop&&(t+=\" jqtree-dnd\");const n=document.createElement(\"ul\");return n.className=`jqtree_common ${t}`,n.setAttribute(\"role\",o),n}getButtonClasses(e){const t=[\"jqtree-toggler\",\"jqtree_common\"];return e.is_open||t.push(\"jqtree-closed\"),this.buttonLeft?t.push(\"jqtree-toggler-left\"):t.push(\"jqtree-toggler-right\"),t.join(\" \")}getFolderClasses(e,t){const o=[\"jqtree-folder\"];return e.is_open||o.push(\"jqtree-closed\"),t&&o.push(\"jqtree-selected\"),e.is_loading&&o.push(\"jqtree-loading\"),o.join(\" \")}setTreeItemAriaAttributes(e,t,n,s){e.setAttribute(\"aria-label\",t),e.setAttribute(\"aria-level\",`${n}`),e.setAttribute(\"aria-selected\",o(s)),e.setAttribute(\"role\",\"treeitem\")}}class h{constructor({closeNode:e,getSelectedNode:t,isFocusOnTree:o,keyboardSupport:n,openNode:s,selectNode:r}){this.closeNode=e,this.getSelectedNode=t,this.isFocusOnTree=o,this.keyboardSupport=n,this.openNode=s,this.originalSelectNode=r,n&&document.addEventListener(\"keydown\",this.handleKeyDown)}deinit(){this.keyboardSupport&&document.removeEventListener(\"keydown\",this.handleKeyDown)}moveDown(e){return this.selectNode(e.getNextVisibleNode())}moveUp(e){return this.selectNode(e.getPreviousVisibleNode())}canHandleKeyboard(){return this.keyboardSupport&&this.isFocusOnTree()}handleKeyDown=e=>{if(!this.canHandleKeyboard())return;let t=!1;const o=this.getSelectedNode();if(o)switch(e.key){case\"ArrowDown\":t=this.moveDown(o);break;case\"ArrowLeft\":t=this.moveLeft(o);break;case\"ArrowRight\":t=this.moveRight(o);break;case\"ArrowUp\":t=this.moveUp(o)}t&&e.preventDefault()};moveLeft(e){return e.isFolder()&&e.is_open?(this.closeNode(e),!0):this.selectNode(e.getParent())}moveRight(e){return!!e.isFolder()&&(e.is_open?this.selectNode(e.getNextVisibleNode()):(this.openNode(e),!0))}selectNode(e){return!!e&&(this.originalSelectNode(e),!0)}}const c=e=>({originalEvent:e,pageX:e.pageX,pageY:e.pageY,target:e.target}),u=(e,t)=>({originalEvent:t,pageX:e.pageX,pageY:e.pageY,target:e.target});class m{constructor({element:e,getMouseDelay:t,getNode:o,onClickButton:n,onClickTitle:s,onMouseCapture:r,onMouseDrag:i,onMouseStart:l,onMouseStop:d,triggerEvent:a,useContextMenu:h}){this.element=e,this.getMouseDelay=t,this.getNode=o,this.onClickButton=n,this.onClickTitle=s,this.onMouseCapture=r,this.onMouseDrag=i,this.onMouseStart=l,this.onMouseStop=d,this.triggerEvent=a,this.useContextMenu=h,e.addEventListener(\"click\",this.handleClick),e.addEventListener(\"dblclick\",this.handleDblclick),e.addEventListener(\"mousedown\",this.mouseDown,{passive:!1}),e.addEventListener(\"touchstart\",this.touchStart,{passive:!1}),h&&e.addEventListener(\"contextmenu\",this.handleContextmenu),this.isMouseStarted=!1,this.mouseDelayTimer=null,this.isMouseDelayMet=!1,this.mouseDownInfo=null}deinit(){this.element.removeEventListener(\"click\",this.handleClick),this.element.removeEventListener(\"dblclick\",this.handleDblclick),this.useContextMenu&&this.element.removeEventListener(\"contextmenu\",this.handleContextmenu),this.element.removeEventListener(\"mousedown\",this.mouseDown),this.element.removeEventListener(\"touchstart\",this.touchStart),this.removeMouseMoveEventListeners()}getClickTarget(e){const t=e.closest(\".jqtree-toggler\");if(t){const e=this.getNode(t);if(e)return{node:e,type:\"button\"}}else{const t=e.closest(\".jqtree-element\");if(t){const e=this.getNode(t);if(e)return{node:e,type:\"label\"}}}return null}handleClick=e=>{if(!e.target)return;const t=this.getClickTarget(e.target);if(t)switch(t.type){case\"button\":this.onClickButton(t.node),e.preventDefault(),e.stopPropagation();break;case\"label\":this.triggerEvent(\"tree.click\",{click_event:e,node:t.node}).isDefaultPrevented()||this.onClickTitle(t.node);break}};handleContextmenu=e=>{if(!e.target)return;const t=e.target.closest(\"ul.jqtree-tree .jqtree-element\");if(t){const o=this.getNode(t);if(o)return e.preventDefault(),e.stopPropagation(),this.triggerEvent(\"tree.contextmenu\",{click_event:e,node:o}),!1}return null};handleDblclick=e=>{if(!e.target)return;const t=this.getClickTarget(e.target);\"label\"===t?.type&&this.triggerEvent(\"tree.dblclick\",{click_event:e,node:t.node})};handleMouseDown(e){return this.isMouseStarted&&this.handleMouseUp(e),this.mouseDownInfo=e,!!this.onMouseCapture(e)&&(this.handleStartMouse(),!0)}handleMouseMove(e,t){if(this.isMouseStarted)return this.onMouseDrag(t),void(e.cancelable&&e.preventDefault());this.isMouseDelayMet&&(this.mouseDownInfo&&(this.isMouseStarted=this.onMouseStart(this.mouseDownInfo)),this.isMouseStarted?(this.onMouseDrag(t),e.cancelable&&e.preventDefault()):this.handleMouseUp(t))}handleMouseUp(e){this.removeMouseMoveEventListeners(),this.isMouseDelayMet=!1,this.mouseDownInfo=null,this.isMouseStarted&&(this.isMouseStarted=!1,this.onMouseStop(e))}handleStartMouse(){document.addEventListener(\"mousemove\",this.mouseMove,{passive:!1}),document.addEventListener(\"touchmove\",this.touchMove,{passive:!1}),document.addEventListener(\"mouseup\",this.mouseUp,{passive:!1}),document.addEventListener(\"touchend\",this.touchEnd,{passive:!1});const e=this.getMouseDelay();e?this.startMouseDelayTimer(e):this.isMouseDelayMet=!0}mouseDown=e=>{if(0!==e.button)return;this.handleMouseDown(c(e))&&e.cancelable&&e.preventDefault()};mouseMove=e=>{this.handleMouseMove(e,c(e))};mouseUp=e=>{this.handleMouseUp(c(e))};removeMouseMoveEventListeners(){document.removeEventListener(\"mousemove\",this.mouseMove),document.removeEventListener(\"touchmove\",this.touchMove),document.removeEventListener(\"mouseup\",this.mouseUp),document.removeEventListener(\"touchend\",this.touchEnd)}startMouseDelayTimer(e){this.mouseDelayTimer&&clearTimeout(this.mouseDelayTimer),this.mouseDelayTimer=window.setTimeout(()=>{this.mouseDownInfo&&(this.isMouseDelayMet=!0)},e),this.isMouseDelayMet=!1}touchEnd=e=>{if(e.touches.length>1)return;const t=e.touches[0];t&&this.handleMouseUp(u(t,e))};touchMove=e=>{if(e.touches.length>1)return;const t=e.touches[0];t&&this.handleMouseMove(e,u(t,e))};touchStart=e=>{if(e.touches.length>1)return;const t=e.touches[0];t&&this.handleMouseDown(u(t,e))}}const g=e=>\"object\"==typeof e&&\"children\"in e&&e.children instanceof Array;class p{constructor(e=null,t=!1,o=p){this.name=\"\",this.load_on_demand=!1,this.isEmptyFolder=null!=e&&g(e)&&0===e.children.length,this.setData(e),this.children=[],this.parent=null,t&&(this.idMapping=new Map,this.tree=this,this.nodeClass=o)}addAfter(e){if(this.parent){const t=this.createNode(e),o=this.parent.getChildIndex(this);return this.parent.addChildAtPosition(t,o+1),t.loadChildrenFromData(e),t}return null}addBefore(e){if(this.parent){const t=this.createNode(e),o=this.parent.getChildIndex(this);return this.parent.addChildAtPosition(t,o),t.loadChildrenFromData(e),t}return null}addChild(e){this.children.push(e),e.setParent(this)}addChildAtPosition(e,t){this.children.splice(t,0,e),e.setParent(this)}addNodeToIndex(e){null!=e.id&&this.idMapping.set(e.id,e)}addParent(e){if(this.parent){const t=this.createNode(e);this.tree&&t.setParent(this.tree);const o=this.parent;for(const e of o.children)t.addChild(e);return o.children=[],o.addChild(t),t}return null}append(e){const t=this.createNode(e);return this.addChild(t),t.loadChildrenFromData(e),t}filter(e){const t=[];return this.iterate(o=>(e(o)&&t.push(o),!0)),t}getChildIndex(e){return this.children.indexOf(e)}getData(e=!1){const t=e=>e.map(e=>{const o={};for(const t in e)if(-1===[\"parent\",\"children\",\"element\",\"idMapping\",\"load_on_demand\",\"nodeClass\",\"tree\",\"isEmptyFolder\"].indexOf(t)&&Object.prototype.hasOwnProperty.call(e,t)){const n=e[t];o[t]=n}return e.hasChildren()&&(o.children=t(e.children)),o});return t(e?[this]:this.children)}getLastChild(){if(this.hasChildren()){const e=this.children[this.children.length-1];return e.hasChildren()&&e.is_open?e.getLastChild():e}return null}getLevel(){let e=0,t=this;for(;t.parent;)e+=1,t=t.parent;return e}getNextNode(e=!0){if(e&&this.hasChildren())return this.children[0]??null;if(this.parent){const e=this.getNextSibling();return e||this.parent.getNextNode(!1)}return null}getNextSibling(){if(this.parent){const e=this.parent.getChildIndex(this)+1;return e<this.parent.children.length?this.parent.children[e]??null:null}return null}getNextVisibleNode(){if(this.hasChildren()&&this.is_open)return this.children[0]??null;if(this.parent){const e=this.getNextSibling();return e||this.parent.getNextNode(!1)}return null}getNodeByCallback(e){let t=null;return this.iterate(o=>!t&&(!e(o)||(t=o,!1))),t}getNodeById(e){return this.idMapping.get(e)??null}getNodeByName(e){return this.getNodeByCallback(t=>t.name===e)}getNodeByNameMustExist(e){const t=this.getNodeByCallback(t=>t.name===e);if(!t)throw new Error(`Node with name ${e} not found`);return t}getNodesByProperty(e,t){return this.filter(o=>o[e]===t)}getParent(){return this.parent&&this.parent.parent?this.parent:null}getPreviousNode(){if(this.parent){const e=this.getPreviousSibling();return e?e.hasChildren()?e.getLastChild():e:this.getParent()}return null}getPreviousSibling(){if(this.parent){const e=this.parent.getChildIndex(this)-1;return e>=0?this.parent.children[e]??null:null}return null}getPreviousVisibleNode(){if(this.parent){const e=this.getPreviousSibling();return e?e.hasChildren()&&e.is_open?e.getLastChild():e:this.getParent()}return null}hasChildren(){return 0!==this.children.length}initFromData(e){const t=e=>{for(const t of e){const e=this.createNode();e.initFromData(t),this.addChild(e)}};(e=>{this.setData(e),g(e)&&e.children.length&&t(e.children)})(e)}isFolder(){return this.hasChildren()||this.load_on_demand}isParentOf(e){let t=e.parent;for(;t;){if(t===this)return!0;t=t.parent}return!1}iterate(e){const t=(o,n)=>{for(const s of o.children){e(s,n)&&s.hasChildren()&&t(s,n+1)}};t(this,0)}loadFromData(e){this.removeChildren();for(const t of e){const e=this.createNode(t);this.addChild(e),g(t)&&e.loadFromData(t.children)}return this}moveNode(e,t,o){if(!e.parent||e.isParentOf(t))return!1;switch(e.parent.doRemoveChild(e),o){case\"after\":return!!t.parent&&(t.parent.addChildAtPosition(e,t.parent.getChildIndex(t)+1),!0);case\"before\":return!!t.parent&&(t.parent.addChildAtPosition(e,t.parent.getChildIndex(t)),!0);case\"inside\":return t.addChildAtPosition(e,0),!0}}prepend(e){const t=this.createNode(e);return this.addChildAtPosition(t,0),t.loadChildrenFromData(e),t}remove(){this.parent&&(this.parent.removeChild(this),this.parent=null)}removeChild(e){e.removeChildren(),this.doRemoveChild(e)}removeChildren(){this.iterate(e=>(this.tree?.removeNodeFromIndex(e),!0)),this.children=[]}removeNodeFromIndex(e){null!=e.id&&this.idMapping.delete(e.id)}setData(e){if(e)if(\"string\"==typeof e)this.name=e;else if(\"object\"==typeof e)for(const t in e)if(Object.prototype.hasOwnProperty.call(e,t)){const o=e[t];\"label\"===t||\"name\"===t?\"string\"==typeof o&&(this.name=o):\"children\"!==t&&\"parent\"!==t&&(this[t]=o)}}createNode(e){return new(this.getNodeClass())(e)}doRemoveChild(e){this.children.splice(this.getChildIndex(e),1),this.tree?.removeNodeFromIndex(e)}getNodeClass(){return this.nodeClass??this.tree?.nodeClass??p}loadChildrenFromData(e){g(e)&&e.children.length&&this.loadFromData(e.children)}setParent(e){this.parent=e,this.tree=e.tree,this.tree?.addNodeToIndex(this)}}class f{constructor(e,t){const o=e.querySelector(\":scope > .jqtree-element\");if(!o)return void(this.hint=void 0);const n=Math.max(e.offsetWidth+t-4,0),s=Math.max(e.clientHeight-4,0),r=document.createElement(\"span\");r.className=\"jqtree-border\",r.style.width=`${n}px`,r.style.height=`${s}px`,this.hint=r,o.append(this.hint)}remove(){this.hint?.remove()}}class S{constructor(e,t,o){switch(this.element=t,this.node=e,this.ghost=this.createGhostElement(),o){case\"after\":this.moveAfter();break;case\"before\":this.moveBefore();break;case\"inside\":e.isFolder()&&e.is_open?this.moveInsideOpenFolder():this.moveInside()}}remove(){this.ghost.remove()}createGhostElement(){const e=document.createElement(\"li\");e.className=\"jqtree_common jqtree-ghost\";const t=document.createElement(\"span\");t.className=\"jqtree_common jqtree-circle\",e.append(t);const o=document.createElement(\"span\");return o.className=\"jqtree_common jqtree-line\",e.append(o),e}moveAfter(){this.element.after(this.ghost)}moveBefore(){this.element.before(this.ghost)}moveInside(){this.element.after(this.ghost),this.ghost.classList.add(\"jqtree-inside\")}moveInsideOpenFolder(){const e=this.node.children[0]?.element;e&&e.before(this.ghost)}}class v{constructor({getScrollLeft:e,node:t,tabIndex:o,treeElement:n}){this.getScrollLeft=e,this.tabIndex=o,this.treeElement=n,this.init(t)}addDropHint(e){return this.mustShowBorderDropHint(e)?new f(this.element,this.getScrollLeft()):new S(this.node,this.element,e)}deselect(){this.element.classList.remove(\"jqtree-selected\");const e=this.getTitleSpan();e.removeAttribute(\"tabindex\"),e.setAttribute(\"aria-selected\",\"false\"),e.blur()}init(e){this.node=e,e.element??=this.treeElement,this.element=e.element}select(e){this.element.classList.add(\"jqtree-selected\");const t=this.getTitleSpan(),o=this.tabIndex;null!=o&&t.setAttribute(\"tabindex\",o.toString()),t.setAttribute(\"aria-selected\",\"true\"),e&&t.focus()}getTitleSpan(){return this.element.querySelector(\":scope > .jqtree-element > span.jqtree-title\")}getUl(){return this.element.querySelector(\":scope > ul\")}mustShowBorderDropHint(e){return\"inside\"===e}}class N extends v{constructor({closedIconElement:e,getScrollLeft:t,node:o,openedIconElement:n,tabIndex:s,treeElement:r,triggerEvent:i}){super({getScrollLeft:t,node:o,tabIndex:s,treeElement:r}),this.closedIconElement=e,this.openedIconElement=n,this.triggerEvent=i}close(e,t){if(!this.node.is_open)return;this.node.is_open=!1;const o=this.getButton();o.classList.add(\"jqtree-closed\"),o.innerHTML=\"\";const n=this.closedIconElement;if(n){const e=n.cloneNode(!0);o.appendChild(e)}const s=()=>{this.element.classList.add(\"jqtree-closed\");this.getTitleSpan().setAttribute(\"aria-expanded\",\"false\"),this.triggerEvent(\"tree.close\",{node:this.node})};e?jQuery(this.getUl()).slideUp(t,s):(jQuery(this.getUl()).hide(),s())}open(e,t,o){if(this.node.is_open)return;this.node.is_open=!0;const n=this.getButton();n.classList.remove(\"jqtree-closed\"),n.innerHTML=\"\";const s=this.openedIconElement;if(s){const e=s.cloneNode(!0);n.appendChild(e)}const r=()=>{this.element.classList.remove(\"jqtree-closed\");this.getTitleSpan().setAttribute(\"aria-expanded\",\"true\"),e&&e(this.node),this.triggerEvent(\"tree.open\",{node:this.node})};t?jQuery(this.getUl()).slideDown(o,r):(jQuery(this.getUl()).show(),r())}mustShowBorderDropHint(e){return!this.node.is_open&&\"inside\"===e}getButton(){return this.element.querySelector(\":scope > .jqtree-element > a.jqtree-toggler\")}}class E{constructor({addToSelection:e,getNodeById:t,getSelectedNodes:o,getTree:n,onGetStateFromStorage:s,onSetStateFromStorage:r,openNode:i,refreshElements:l,removeFromSelection:d,saveState:a}){this.addToSelection=e,this.getNodeById=t,this.getSelectedNodes=o,this.getTree=n,this.onGetStateFromStorage=s,this.onSetStateFromStorage=r,this.openNode=i,this.refreshElements=l,this.removeFromSelection=d,this.saveStateOption=a}getNodeIdToBeSelected(){const e=this.getStateFromStorage();return e?.selected_node?e.selected_node[0]??null:null}getState(){return{open_nodes:(()=>{const e=[];return this.getTree()?.iterate(t=>(t.is_open&&t.id&&t.hasChildren()&&e.push(t.id),!0)),e})(),selected_node:(()=>{const e=[];return this.getSelectedNodes().forEach(t=>{null!=t.id&&e.push(t.id)}),e})()}}getStateFromStorage(){const e=this.loadFromStorage();return e?this.parseState(e):null}saveState(){const e=JSON.stringify(this.getState());this.onSetStateFromStorage?this.onSetStateFromStorage(e):localStorage.setItem(this.getKeyName(),e)}setInitialState(e){let t=!1;return e.open_nodes&&(t=this.openInitialNodes(e.open_nodes)),this.resetSelection(),e.selected_node&&this.selectInitialNodes(e.selected_node),t}setInitialStateOnDemand(e,t){let o=0,n=e.open_nodes;const s=()=>{if(!n)return;const s=[];for(const e of n){const t=this.getNodeById(e);t?t.is_loading||(t.load_on_demand?r(t):this.openNode(t,!1)):s.push(e)}n=s,e.selected_node&&this.selectInitialNodes(e.selected_node)&&this.refreshElements(null),0===o&&t()},r=e=>{o+=1,this.openNode(e,!1,()=>{o-=1,s()})};s()}getKeyName(){return\"string\"==typeof this.saveStateOption?this.saveStateOption:\"tree\"}loadFromStorage(){return this.onGetStateFromStorage?this.onGetStateFromStorage():localStorage.getItem(this.getKeyName())}openInitialNodes(e){let t=!1;for(const o of e){const e=this.getNodeById(o);e&&(e.load_on_demand?t=!0:e.is_open=!0)}return t}parseState(e){const t=JSON.parse(e);var o;return t.selected_node&&(\"number\"==typeof(o=t.selected_node)&&o%1==0)&&(t.selected_node=[t.selected_node]),t}resetSelection(){this.getSelectedNodes().forEach(e=>{this.removeFromSelection(e)})}selectInitialNodes(e){let t=0;for(const o of e){const e=this.getNodeById(o);e&&(t+=1,this.addToSelection(e))}return 0!==t}}class D{constructor({container:e,refreshHitAreas:t}){this.container=e,this.refreshHitAreas=t}checkHorizontalScrolling(e){const t=this.getNewHorizontalScrollDirection(e);this.horizontalScrollDirection!==t&&(this.horizontalScrollDirection=t,null!=this.horizontalScrollTimeout&&window.clearTimeout(this.horizontalScrollTimeout),t&&(this.horizontalScrollTimeout=window.setTimeout(this.scrollHorizontally.bind(this),40)))}checkVerticalScrolling(e){const t=this.getNewVerticalScrollDirection(e);this.verticalScrollDirection!==t&&(this.verticalScrollDirection=t,null!=this.verticalScrollTimeout&&(window.clearTimeout(this.verticalScrollTimeout),this.verticalScrollTimeout=void 0),t&&(this.verticalScrollTimeout=window.setTimeout(this.scrollVertically.bind(this),40)))}getScrollLeft(){return this.container.scrollLeft}scrollToY(e){this.container.scrollTop=e}stopScrolling(){this.horizontalScrollDirection=void 0,this.verticalScrollDirection=void 0}scrollHorizontally(){if(!this.horizontalScrollDirection)return;const e=\"left\"===this.horizontalScrollDirection?-20:20;this.container.scrollBy({behavior:\"instant\",left:e,top:0}),this.refreshHitAreas(),setTimeout(this.scrollHorizontally.bind(this),40)}scrollVertically(){if(!this.verticalScrollDirection)return;const e=\"top\"===this.verticalScrollDirection?-20:20;this.container.scrollBy({behavior:\"instant\",left:0,top:e}),this.refreshHitAreas(),setTimeout(this.scrollVertically.bind(this),40)}}class y extends D{stopScrolling(){super.stopScrolling(),this.horizontalScrollDirection=void 0,this.verticalScrollDirection=void 0}getNewHorizontalScrollDirection(e){const t=s(this.container),o=this.container.getBoundingClientRect().width,n=t.left+o,r=t.left;return e>n-20?\"right\":e<r+20?\"left\":void 0}getNewVerticalScrollDirection(e){return e<this.getScrollParentTop()?\"top\":e>this.getScrollParentBottom()?\"bottom\":void 0}getScrollParentBottom(){if(null==this.scrollParentBottom){const e=this.container.getBoundingClientRect().height;this.scrollParentBottom=this.getScrollParentTop()+e}return this.scrollParentBottom}getScrollParentTop(){return this.scrollParentTop??=n(this.container),this.scrollParentTop}}class b extends D{constructor({refreshHitAreas:e,treeElement:t}){super({container:document.documentElement,refreshHitAreas:e}),this.treeElement=t}scrollToY(e){const t=n(this.treeElement);super.scrollToY(e+t)}stopScrolling(){super.stopScrolling(),this.documentScrollHeight=void 0,this.documentScrollWidth=void 0}getNewHorizontalScrollDirection(e){const t=e-this.container.scrollLeft<20;return e>window.innerWidth-20&&this.canScrollRight()?\"right\":t?\"left\":void 0}getNewVerticalScrollDirection(e){const t=this.container.scrollTop;if(e-t<20)return\"top\";return window.innerHeight-(e-t)<20&&this.canScrollDown()?\"bottom\":void 0}canScrollDown(){return this.container.scrollTop+this.container.clientHeight<this.getDocumentScrollHeight()}canScrollRight(){return this.container.scrollLeft+this.container.clientWidth<this.getDocumentScrollWidth()}getDocumentScrollHeight(){return this.documentScrollHeight??=this.container.scrollHeight,this.documentScrollHeight}getDocumentScrollWidth(){return this.documentScrollWidth??=this.container.scrollWidth,this.documentScrollWidth}}const C=e=>\"auto\"===e||\"scroll\"===e,F=e=>{const t=getComputedStyle(e);return C(t.overflowX)||C(t.overflowY)},I=(e,t)=>{const o=(e=>{if(F(e))return e;let t=e.parentElement;for(;t;){if(F(t))return t;t=t.parentElement}return null})(e);return o&&\"HTML\"!==o.tagName?new y({container:o,refreshHitAreas:t}):new b({refreshHitAreas:t,treeElement:e})};class T{constructor({refreshHitAreas:e,treeElement:t}){this.refreshHitAreas=e,this.scrollParent=void 0,this.treeElement=t}checkScrolling(e){this.checkVerticalScrolling(e),this.checkHorizontalScrolling(e)}getScrollLeft(){return this.getScrollParent().getScrollLeft()}scrollToY(e){this.getScrollParent().scrollToY(e)}stopScrolling(){this.getScrollParent().stopScrolling()}checkHorizontalScrolling(e){this.getScrollParent().checkHorizontalScrolling(e.pageX)}checkVerticalScrolling(e){this.getScrollParent().checkVerticalScrolling(e.pageY)}getScrollParent(){return this.scrollParent??=I(this.treeElement,this.refreshHitAreas),this.scrollParent}}class L{constructor({getNodeById:e}){this.getNodeById=e,this.selectedNodes=new Set,this.clear()}addToSelection(e){null!=e.id?this.selectedNodes.add(e.id):this.selectedSingleNode=e}clear(){this.selectedNodes.clear(),this.selectedSingleNode=null}getSelectedNode(){const e=this.getSelectedNodes();return!!e.length&&(e[0]??!1)}getSelectedNodes(){if(this.selectedSingleNode)return[this.selectedSingleNode];{const e=[];return this.selectedNodes.forEach(t=>{const o=this.getNodeById(t);o&&e.push(o)}),e}}getSelectedNodesUnder(e){if(this.selectedSingleNode)return e.isParentOf(this.selectedSingleNode)?[this.selectedSingleNode]:[];{const t=[];return this.selectedNodes.forEach(o=>{const n=this.getNodeById(o);n&&e.isParentOf(n)&&t.push(n)}),t}}isNodeSelected(e){return null!=e.id?this.selectedNodes.has(e.id):!!this.selectedSingleNode&&this.selectedSingleNode.element===e.element}removeFromSelection(e,t=!1){null==e.id?this.selectedSingleNode&&e.element===this.selectedSingleNode.element&&(this.selectedSingleNode=null):(this.selectedNodes.delete(e.id),t&&e.iterate(()=>(null!=e.id&&this.selectedNodes.delete(e.id),!0)))}}const M=(e,t)=>{const o=()=>`simple_widget_${t}`,n=(e,t)=>{const o=jQuery.data(e,t);return o&&o instanceof H?o:null},s=(t,s)=>{const r=o();for(const o of t.get()){if(!n(o,r)){const t=new e(o,s);jQuery.data(o,r)||jQuery.data(o,r,t),t.init()}}return t};jQuery.fn[t]=function(e,...t){if(!e)return s(this,null);if(\"object\"==typeof e){return s(this,e)}if(\"string\"==typeof e&&\"_\"!==e[0]){const s=e;return\"destroy\"===e?void(e=>{const t=o();for(const o of e.get()){const e=n(o,t);e&&e.destroy(),jQuery.removeData(o,t)}})(this):((e,t,n)=>{let s=null;for(const r of e.get()){const e=jQuery.data(r,o());if(e&&e instanceof H){const o=e[t];o&&\"function\"==typeof o&&(s=o.apply(e,n))}}return s})(this,s,t)}}};class H{static defaults={};constructor(e,t){this.$el=jQuery(e);const o=this.constructor.defaults;this.options={...o,...t}}static register(e,t){M(e,t)}deinit(){}destroy(){this.deinit()}init(){}}const w=\"Node parameter is empty\",A=\"Parameter is empty: \";class _ extends H{static defaults={animationSpeed:\"fast\",autoEscape:!0,autoOpen:!1,buttonLeft:!0,closedIcon:void 0,data:void 0,dataFilter:void 0,dataUrl:void 0,dragAndDrop:!1,keyboardSupport:!0,nodeClass:p,onCanMove:void 0,onCanMoveTo:void 0,onCanSelectNode:void 0,onCreateLi:void 0,onDragMove:void 0,onDragStop:void 0,onGetStateFromStorage:void 0,onIsMoveHandle:void 0,onLoadFailed:void 0,onLoading:void 0,onSetStateFromStorage:void 0,openedIcon:\"&#x25bc;\",openFolderDelay:500,rtl:void 0,saveState:!1,selectable:!0,showEmptyFolder:!1,slide:!0,startDndDelay:300,tabIndex:0,useContextMenu:!0};addNodeAfter(e,t){const o=t.addAfter(e);return o&&this.refreshElements(t.parent),o}addNodeBefore(e,t){if(!t)throw Error(A+\"existingNode\");const o=t.addBefore(e);return o&&this.refreshElements(t.parent),o}addParentNode(e,t){if(!t)throw Error(A+\"existingNode\");const o=t.addParent(e);return o&&this.refreshElements(o.parent),o}addToSelection(e,t){if(!e)throw Error(w);return this.selectNodeHandler.addToSelection(e),this.openParents(e),this.getNodeElementForNode(e).select(t??!0),this.saveState(),this.element}appendNode(e,t){const o=t??this.tree,n=o.append(e);return this.refreshElements(o),n}closeNode(e,t){if(!e)throw Error(w);const o=t??this.options.slide;return(e.isFolder()||e.isEmptyFolder)&&(this.createFolderElement(e).close(o,this.options.animationSpeed),this.saveState()),this.element}deinit(){this.element.empty(),this.element.off(),this.keyHandler.deinit(),this.mouseHandler.deinit(),this.tree=new p({},!0),super.deinit()}getNodeByCallback(e){return this.tree.getNodeByCallback(e)}getNodeByHtmlElement(e){const t=e instanceof HTMLElement?e:e.get(0);return t?this.getNode(t):null}getNodeById(e){return this.tree.getNodeById(e)}getNodeByName(e){return this.tree.getNodeByName(e)}getNodeByNameMustExist(e){return this.tree.getNodeByNameMustExist(e)}getNodesByProperty(e,t){return this.tree.getNodesByProperty(e,t)}getSelectedNode(){return this.selectNodeHandler.getSelectedNode()}getSelectedNodes(){return this.selectNodeHandler.getSelectedNodes()}getState(){return this.saveStateHandler.getState()}getStateFromStorage(){return this.saveStateHandler.getStateFromStorage()}getTree(){return this.tree}getVersion(){return\"1.8.11\"}init(){super.init(),this.element=this.$el,this.isInitialized=!1,this.options.rtl=this.getRtlOption(),this.options.closedIcon??=this.getDefaultClosedIcon(),this.connectHandlers(),this.initData()}isDragging(){return this.dndHandler.isDragging}isNodeSelected(e){if(!e)throw Error(w);return this.selectNodeHandler.isNodeSelected(e)}loadData(e,t){return this.doLoadData(e,t),this.element}loadDataFromUrl(e,t,o){return\"string\"==typeof e?this.doLoadDataFromUrl(e,t,o??null):this.doLoadDataFromUrl(null,e,t),this.element}moveDown(){const e=this.getSelectedNode();return e&&this.keyHandler.moveDown(e),this.element}moveNode(e,t,o){if(!e)throw Error(w);if(!t)throw Error(A+\"targetNode\");if(!o)throw Error(A+\"position\");return this.tree.moveNode(e,t,o),this.refreshElements(null),this.element}moveUp(){const e=this.getSelectedNode();return e&&this.keyHandler.moveUp(e),this.element}openNode(e,t,o){if(!e)throw Error(w);const[n,s]=(()=>{let e,n;return\"function\"==typeof t?(e=t,n=null):(n=t,e=o),n??=this.options.slide,[n,e]})();return this.openNodeInternal(e,n,s),this.element}prependNode(e,t){const o=t??this.tree,n=o.prepend(e);return this.refreshElements(o),n}refresh(){return this.refreshElements(null),this.element}refreshHitAreas(){return this.dndHandler.refresh(),this.element}reload(e){return this.doLoadDataFromUrl(null,null,e),this.element}removeFromSelection(e){if(!e)throw Error(w);return this.selectNodeHandler.removeFromSelection(e),this.getNodeElementForNode(e).deselect(),this.saveState(),this.element}removeNode(e){if(!e)throw Error(w);if(!e.parent)throw Error(\"Node has no parent\");this.selectNodeHandler.removeFromSelection(e,!0);const t=e.parent;return e.remove(),this.refreshElements(t),this.element}scrollToNode(e){if(!e)throw Error(w);if(!e.element)return this.element;const t=n(e.element)-n(this.$el.get(0));return this.scrollHandler.scrollToY(t),this.element}selectNode(e,t){return this.doSelectNode(e,t),this.element}setOption(e,t){return this.options[e]=t,this.element}setState(e){return e&&(this.saveStateHandler.setInitialState(e),this.refreshElements(null)),this.element}toggle(e,t=null){if(!e)throw Error(w);const o=t??this.options.slide;return e.is_open?this.closeNode(e,o):this.openNode(e,o),this.element}toJson(){return JSON.stringify(this.tree.getData())}updateNode(e,t){if(!e)throw Error(w);if(!t)return this.element;const o=\"object\"==typeof t&&t.id&&t.id!==e.id;return o&&this.tree.removeNodeFromIndex(e),e.setData(t),o&&this.tree.addNodeToIndex(e),\"object\"==typeof t&&t.children&&t.children instanceof Array&&(e.removeChildren(),t.children.length&&e.loadFromData(t.children)),this.refreshElements(e),this.element}connectHandlers(){const{autoEscape:e,buttonLeft:o,closedIcon:n,dataFilter:s,dragAndDrop:r,keyboardSupport:i,onCanMove:l,onCanMoveTo:c,onCreateLi:u,onDragMove:g,onDragStop:p,onGetStateFromStorage:f,onIsMoveHandle:S,onLoadFailed:v,onLoading:N,onSetStateFromStorage:D,openedIcon:y,openFolderDelay:b,rtl:C,saveState:F,showEmptyFolder:I,slide:M,tabIndex:H}=this.options,w=this.closeNode.bind(this),A=this.getNodeElement.bind(this),_=this.getNodeElementForNode.bind(this),j=this.getNodeById.bind(this),x=this.getSelectedNode.bind(this),B=this.getTree.bind(this),P=this.isFocusOnTree.bind(this),q=this.loadData.bind(this),k=this.openNodeInternal.bind(this),O=this.refreshElements.bind(this),U=this.refreshHitAreas.bind(this),z=this.selectNode.bind(this),Q=this.element,Y=this.element.get(0),R=this.triggerEvent.bind(this),$=new L({getNodeById:j}),V=$.addToSelection.bind($),X=$.getSelectedNodes.bind($),G=$.isNodeSelected.bind($),W=$.removeFromSelection.bind($),K=new t({dataFilter:s,loadData:q,onLoadFailed:v,onLoading:N,treeElement:Y,triggerEvent:R}),J=new E({addToSelection:V,getNodeById:j,getSelectedNodes:X,getTree:B,onGetStateFromStorage:f,onSetStateFromStorage:D,openNode:k,refreshElements:O,removeFromSelection:W,saveState:F}),Z=new T({refreshHitAreas:U,treeElement:Y}),ee=Z.getScrollLeft.bind(Z),te=new d({autoEscape:e,getNodeElement:A,getNodeElementForNode:_,getScrollLeft:ee,getTree:B,onCanMove:l,onCanMoveTo:c,onDragMove:g,onDragStop:p,onIsMoveHandle:S,openFolderDelay:b,openNode:k,refreshElements:O,slide:M,treeElement:Y,triggerEvent:R}),oe=new h({closeNode:w,getSelectedNode:x,isFocusOnTree:P,keyboardSupport:i,openNode:k,selectNode:z}),ne=new a({$element:Q,autoEscape:e,buttonLeft:o,closedIcon:n,dragAndDrop:r,getTree:B,isNodeSelected:G,onCreateLi:u,openedIcon:y,rtl:C,showEmptyFolder:I,tabIndex:H}),se=this.getNode.bind(this),re=this.mouseCapture.bind(this),ie=this.mouseDrag.bind(this),le=this.mouseStart.bind(this),de=this.mouseStop.bind(this),ae=new m({element:Y,getMouseDelay:()=>this.options.startDndDelay??0,getNode:se,onClickButton:this.toggle.bind(this),onClickTitle:this.doSelectNode.bind(this),onMouseCapture:re,onMouseDrag:ie,onMouseStart:le,onMouseStop:de,triggerEvent:R,useContextMenu:this.options.useContextMenu});this.dataLoader=K,this.dndHandler=te,this.keyHandler=oe,this.mouseHandler=ae,this.renderer=ne,this.saveStateHandler=J,this.scrollHandler=Z,this.selectNodeHandler=$}containsElement(e){const t=this.getNode(e);return t?.tree===this.tree}createFolderElement(e){const t=this.renderer.closedIconElement,o=this.scrollHandler.getScrollLeft.bind(this.scrollHandler),n=this.renderer.openedIconElement,s=this.options.tabIndex,r=this.element.get(0),i=this.triggerEvent.bind(this);return new N({closedIconElement:t,getScrollLeft:o,node:e,openedIconElement:n,tabIndex:s,treeElement:r,triggerEvent:i})}createNodeElement(e){const t=this.scrollHandler.getScrollLeft.bind(this.scrollHandler),o=this.options.tabIndex,n=this.element.get(0);return new v({getScrollLeft:t,node:e,tabIndex:o,treeElement:n})}deselectCurrentNode(){const e=this.getSelectedNode();e&&this.removeFromSelection(e)}deselectNodes(e){const t=this.selectNodeHandler.getSelectedNodesUnder(e);for(const e of t)this.selectNodeHandler.removeFromSelection(e)}doLoadData(e,t){e&&(t?(this.deselectNodes(t),this.loadSubtree(e,t)):this.initTree(e),this.isDragging()&&this.dndHandler.refresh()),this.triggerEvent(\"tree.load_data\",{parent_node:t,tree_data:e})}doLoadDataFromUrl(e,t,o){const n=e??this.getDataUrlInfo(t);this.dataLoader.loadFromUrl(n,t,o)}doSelectNode(e,t){const o=()=>{this.options.saveState&&this.saveStateHandler.saveState()};if(!e)return this.deselectCurrentNode(),void o();const n={mustSetFocus:!0,mustToggle:!0,...t??{}};if((()=>this.options.onCanSelectNode?this.options.selectable&&this.options.onCanSelectNode(e):this.options.selectable)()){if(this.selectNodeHandler.isNodeSelected(e))n.mustToggle&&(this.deselectCurrentNode(),this.triggerEvent(\"tree.select\",{node:null,previous_node:e}));else{const t=this.getSelectedNode()||null;this.deselectCurrentNode(),this.addToSelection(e,n.mustSetFocus),this.triggerEvent(\"tree.select\",{deselected_node:t,node:e}),this.openParents(e)}o()}}getAutoOpenMaxLevel(){return!0===this.options.autoOpen?-1:\"number\"==typeof this.options.autoOpen?this.options.autoOpen:\"string\"==typeof this.options.autoOpen?parseInt(this.options.autoOpen,10):0}getDataUrlInfo(e){const t=this.options.dataUrl??this.element.data(\"url\"),o=t=>{if(e?.id){const o={node:e.id};t.data=o}else{const e=this.getNodeIdToBeSelected();if(e){const o={selected_node:e};t.data=o}}};return\"function\"==typeof t?t(e):\"string\"==typeof t?(e=>{const t={url:e};return o(t),t})(t):t&&\"object\"==typeof t?(o(t),t):null}getDefaultClosedIcon(){return this.options.rtl?\"&#x25c0;\":\"&#x25ba;\"}getNode(e){const t=e.closest(\"li.jqtree_common\");return t?jQuery(t).data(\"node\"):null}getNodeElement(e){const t=this.getNode(e);return t?this.getNodeElementForNode(t):null}getNodeElementForNode(e){return e.isFolder()?this.createFolderElement(e):this.createNodeElement(e)}getNodeIdToBeSelected(){return this.options.saveState?this.saveStateHandler.getNodeIdToBeSelected():null}getRtlOption(){if(null!=this.options.rtl)return this.options.rtl;{const e=this.element.data(\"rtl\");return null!==e&&!1!==e&&void 0!==e}}initData(){if(this.options.data)this.doLoadData(this.options.data,null);else{this.getDataUrlInfo(null)?this.doLoadDataFromUrl(null,null,null):this.doLoadData([],null)}}initTree(e){const t=()=>{this.isInitialized||(this.isInitialized=!0,this.triggerEvent(\"tree.init\"))};this.tree=new this.options.nodeClass(null,!0,this.options.nodeClass),this.selectNodeHandler.clear(),this.tree.loadFromData(e);const o=this.setInitialState();this.refreshElements(null),o?this.setInitialStateOnDemand(t):t()}isFocusOnTree(){const e=document.activeElement;return\"SPAN\"===e?.tagName&&this.containsElement(e)}isSelectedNodeInSubtree(e){const t=this.getSelectedNode();return!!t&&(e===t||e.isParentOf(t))}loadFolderOnDemand(e,t=!0,o){e.is_loading=!0,this.doLoadDataFromUrl(null,e,()=>{this.openNodeInternal(e,t,o)})}loadSubtree(e,t){t.loadFromData(e),t.load_on_demand=!1,t.is_loading=!1,this.refreshElements(t)}mouseCapture(e){return!!this.options.dragAndDrop&&this.dndHandler.mouseCapture(e)}mouseDrag(e){if(this.options.dragAndDrop){const t=this.dndHandler.mouseDrag(e);return this.scrollHandler.checkScrolling(e),t}return!1}mouseStart(e){return!!this.options.dragAndDrop&&this.dndHandler.mouseStart(e)}mouseStop(e){return!!this.options.dragAndDrop&&(this.scrollHandler.stopScrolling(),this.dndHandler.mouseStop(e))}openNodeInternal(e,t=!0,o){const n=(t,o,n)=>{if(!e.children.length)return;this.createFolderElement(t).open(n,o,this.options.animationSpeed)};if(e.isFolder()||e.isEmptyFolder)if(e.load_on_demand)this.loadFolderOnDemand(e,t,o);else{let s=e.parent;for(;s;)s.parent&&n(s,!1),s=s.parent;n(e,t,o),this.saveState()}}openParents(e){const t=e.parent;t?.parent&&!t.is_open&&this.openNode(t,!1)}refreshElements(e){const t=this.isFocusOnTree(),o=!!e&&this.isSelectedNodeInSubtree(e);this.renderer.render(e),o&&this.selectCurrentNode(t),this.triggerEvent(\"tree.refresh\")}saveState(){this.options.saveState&&this.saveStateHandler.saveState()}selectCurrentNode(e){const t=this.getSelectedNode();if(t){this.getNodeElementForNode(t).select(e)}}setInitialState(){const e=()=>{if(!1===this.options.autoOpen)return!1;const e=this.getAutoOpenMaxLevel();let t=!1;return this.tree.iterate((o,n)=>o.load_on_demand?(t=!0,!1):!!o.hasChildren()&&(o.is_open=!0,n!==e)),t};let[t,o]=(()=>{if(this.options.saveState){const e=this.saveStateHandler.getStateFromStorage();if(e){return[!0,this.saveStateHandler.setInitialState(e)]}return[!1,!1]}return[!1,!1]})();return t||(o=e()),o}setInitialStateOnDemand(e){const t=()=>{const t=this.getAutoOpenMaxLevel();let o=0;const n=e=>{o+=1,this.openNodeInternal(e,!1,()=>{o-=1,s()})},s=()=>{this.tree.iterate((e,o)=>e.load_on_demand?(e.is_loading||n(e),!1):(this.openNodeInternal(e,!1),o!==t)),0===o&&e()};s()};(()=>{if(this.options.saveState){const t=this.saveStateHandler.getStateFromStorage();return!!t&&(this.saveStateHandler.setInitialStateOnDemand(t,e),!0)}return!1})()||t()}triggerEvent(e,t){const o=jQuery.Event(e,t);return this.element.trigger(o),o}}return H.register(_,\"tree\"),e.JqTreeWidget=_,e}({});\n//# sourceMappingURL=tree.jquery.js.map\n\n\n/***/ }\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tvar cachedModule = __webpack_module_cache__[moduleId];\n/******/ \t\tif (cachedModule !== undefined) {\n/******/ \t\t\treturn cachedModule.exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\nvar __webpack_exports__ = {};\n// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.\n(() => {\n\"use strict\";\n\n// EXTERNAL MODULE: ./node_modules/.pnpm/cookie@1.1.1/node_modules/cookie/dist/index.js\nvar dist = __webpack_require__(163);\n// EXTERNAL MODULE: ./node_modules/.pnpm/jqtree@1.8.11_jquery@4.0.0/node_modules/jqtree/tree.jquery.js\nvar tree_jquery = __webpack_require__(751);\n;// ./src/initTree.ts\n\n\nfunction initTree($tree, {\n  animationSpeed,\n  autoEscape,\n  autoOpen,\n  csrfCookieName,\n  dragAndDrop,\n  hasAddPermission,\n  hasChangePermission,\n  mouseDelay,\n  rtl\n}) {\n  let errorNode = null;\n  const baseUrl = \"http://example.com\";\n  const insertAtUrl = new URL($tree.data(\"insert_at_url\"), baseUrl);\n  function createLi(node, $li, isSelected) {\n    if (node.id == null) {\n      return;\n    }\n\n    // Create edit link\n    const $title = $li.find(\".jqtree-title\");\n    insertAtUrl.searchParams.set(\"insert_at\", node.id.toString());\n    const insertUrlString = insertAtUrl.toString().substring(baseUrl.length);\n    const tabindex = isSelected ? \"0\" : \"-1\";\n    const editCaption = hasChangePermission ? gettext(\"edit\") : gettext(\"view\");\n    $title.after(`<a href=\"${node.url}\" class=\"edit\" tabindex=\"${tabindex}\">(${editCaption})</a>`, hasAddPermission ? `<a href=\"${insertUrlString}\" class=\"edit\" tabindex=\"${tabindex}\">(${gettext(\"add\")})</a>` : \"\");\n  }\n  function getCsrfToken() {\n    function getFromMiddleware() {\n      const inputElement = document.querySelector('[name=\"csrfmiddlewaretoken\"]');\n      return inputElement?.value;\n    }\n    function getFromCookie() {\n      if (!csrfCookieName) {\n        return null;\n      } else {\n        return dist/* parse */.qg(document.cookie)[csrfCookieName];\n      }\n    }\n    return getFromCookie() ?? getFromMiddleware() ?? \"\";\n  }\n  function handleMove(eventParam) {\n    const e = eventParam;\n    const info = e.move_info;\n    if (!info.moved_node.element) {\n      return;\n    }\n    const $el = jQuery(info.moved_node.element);\n    const data = {\n      position: info.position,\n      target_id: info.target_node.id\n    };\n    handleLoading(null);\n    removeErrorMessage();\n    e.preventDefault();\n    void jQuery.ajax({\n      beforeSend: xhr => {\n        // Set Django csrf token\n        xhr.setRequestHeader(\"X-CSRFToken\", getCsrfToken());\n      },\n      data,\n      error: () => {\n        handleLoaded(null);\n        const $node = $el.find(\".jqtree-element\");\n        $node.append(`<span class=\"mptt-admin-error\">${gettext(\"move failed\")}</span>`);\n        errorNode = info.moved_node;\n      },\n      success: () => {\n        info.do_move();\n        handleLoaded(null);\n      },\n      type: \"POST\",\n      url: info.moved_node.move_url\n    });\n    function removeErrorMessage() {\n      if (errorNode?.element) {\n        jQuery(errorNode.element).find(\".mptt-admin-error\").remove();\n        errorNode = null;\n      }\n    }\n  }\n  function handleLoadFailed() {\n    $tree.html(gettext(\"Error while loading the data from the server\"));\n  }\n  const spinners = {};\n  function getSpinnerId(node) {\n    if (!node) {\n      return \"__root__\";\n    } else {\n      if (node.id == null) {\n        return null;\n      } else {\n        return node.id;\n      }\n    }\n  }\n  function handleLoading(node) {\n    function getContainer() {\n      if (node) {\n        return node.element;\n      } else {\n        return $tree.get(0);\n      }\n    }\n    const container = getContainer();\n    const spinnerId = getSpinnerId(node);\n    if (!container || spinnerId == null) {\n      return;\n    }\n    const spinner = document.createElement(\"span\");\n    spinner.className = \"jqtree-spin\";\n    container.append(spinner);\n    spinners[spinnerId] = spinner;\n  }\n  function handleLoaded(node) {\n    const spinnerId = getSpinnerId(node);\n    if (spinnerId == null) {\n      return;\n    }\n    const spinner = spinners[spinnerId];\n    if (spinner) {\n      spinner.remove();\n    }\n  }\n  function handleSelect(eventParam) {\n    const e = eventParam;\n    const {\n      deselected_node,\n      node\n    } = e;\n    if (deselected_node?.element) {\n      // deselected node: remove tabindex\n      jQuery(deselected_node.element).find(\".edit\").attr(\"tabindex\", -1);\n    }\n\n    // selected: add tabindex\n    if (node.element) {\n      jQuery(node.element).find(\".edit\").attr(\"tabindex\", 0);\n    }\n  }\n  function handleLoadingEvent(e) {\n    const {\n      isLoading,\n      node\n    } = e;\n    if (isLoading) {\n      handleLoading(node);\n    }\n  }\n  function handleLoadDataEvent(e) {\n    const {\n      parent_node\n    } = e;\n    handleLoaded(parent_node);\n  }\n  const treeOptions = {\n    autoEscape,\n    autoOpen,\n    buttonLeft: rtl,\n    closedIcon: rtl ? \"&#x25c0;\" : \"&#x25ba;\",\n    dragAndDrop: dragAndDrop && hasChangePermission,\n    onCreateLi: createLi,\n    onLoadFailed: handleLoadFailed,\n    saveState: $tree.data(\"save_state\"),\n    useContextMenu: Boolean($tree.data(\"use_context_menu\"))\n  };\n  if (animationSpeed !== null) {\n    treeOptions.animationSpeed = animationSpeed;\n  }\n  if (mouseDelay != null) {\n    treeOptions.startDndDelay = mouseDelay;\n  }\n  $tree.on(\"tree.loading_data\", handleLoadingEvent);\n  $tree.on(\"tree.load_data\", handleLoadDataEvent);\n  $tree.on(\"tree.move\", handleMove);\n  $tree.on(\"tree.select\", handleSelect);\n  $tree.tree(treeOptions);\n}\n/* harmony default export */ const src_initTree = (initTree);\n;// ./src/djangoMpttAdmin.ts\n\njQuery(() => {\n  const $tree = jQuery(\"#tree\");\n  if ($tree.length) {\n    const animationSpeed = $tree.data(\"tree-animation-speed\");\n    const autoOpen = $tree.data(\"auto_open\");\n    const autoEscape = Boolean($tree.data(\"autoescape\"));\n    const hasAddPermission = Boolean($tree.data(\"has-add-permission\"));\n    const hasChangePermission = Boolean($tree.data(\"has-change-permission\"));\n    const mouseDelay = $tree.data(\"tree-mouse-delay\");\n    const dragAndDrop = $tree.data(\"drag-and-drop\");\n    const rtl = $tree.data(\"rtl\") === \"1\";\n    const csrfCookieName = $tree.data(\"csrf-cookie-name\");\n    src_initTree($tree, {\n      animationSpeed,\n      autoEscape,\n      autoOpen,\n      csrfCookieName,\n      dragAndDrop,\n      hasAddPermission,\n      hasChangePermission,\n      mouseDelay,\n      rtl\n    });\n  }\n});\n})();\n\n/******/ })()\n;\n//# sourceMappingURL=django_mptt_admin.debug.js.map"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.debug.js.LICENSE.txt",
    "content": "/*\nJqTree 1.8.10\n\nCopyright 2025 Marco Braak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n@license\n\n*/\n"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js",
    "content": "/*! For license information please see django_mptt_admin.js.LICENSE.txt */\n(()=>{var e={163(e,t){\"use strict\";t.qg=function(e,t){const l=new o,a=e.length;if(a<2)return l;const d=t?.decode||i;let h=0;do{const t=s(e,h,a);if(-1===t)break;const o=n(e,h,a);if(t>o){h=e.lastIndexOf(\";\",t-1)+1;continue}const i=r(e,h,t);void 0===l[i]&&(l[i]=d(r(e,t+1,o))),h=o+1}while(h<a);return l};Object.prototype.toString;const o=(()=>{const e=function(){};return e.prototype=Object.create(null),e})();function n(e,t,o){const n=e.indexOf(\";\",t);return-1===n?o:n}function s(e,t,o){const n=e.indexOf(\"=\",t);return n<o?n:-1}function r(e,t,o){let n=t,s=o;do{const t=e.charCodeAt(n);if(32!==t&&9!==t)break}while(++n<s);for(;s>n;){const t=e.charCodeAt(s-1);if(32!==t&&9!==t)break;s--}return e.slice(n,s)}function i(e){if(-1===e.indexOf(\"%\"))return e;try{return decodeURIComponent(e)}catch(t){return e}}},751(){!function(){\"use strict\";class e{constructor({dataFilter:e,loadData:t,onLoadFailed:o,onLoading:n,treeElement:s,triggerEvent:r}){this.dataFilter=e,this.loadData=t,this.onLoadFailed=o,this.onLoading=n,this.treeElement=s,this.triggerEvent=r}loadFromUrl(e,t,o){if(!e)return;const n=this.getDomElement(t);this.addLoadingClass(n),this.notifyLoading(!0,t,n);const s=()=>{this.removeLoadingClass(n),this.notifyLoading(!1,t,n)};this.submitRequest(e,e=>{s(),this.loadData(this.parseData(e),t),o&&\"function\"==typeof o&&o()},e=>{s(),this.onLoadFailed&&this.onLoadFailed(e)})}addLoadingClass(e){e.classList.add(\"jqtree-loading\")}getDomElement(e){return e?.element?e.element:this.treeElement}notifyLoading(e,t,o){const n=jQuery(o);this.onLoading&&this.onLoading(e,t,n),this.triggerEvent(\"tree.loading_data\",{$el:n,isLoading:e,node:t})}parseData(e){const t=\"string\"==typeof e?JSON.parse(e):e;return this.dataFilter?this.dataFilter(t):t}removeLoadingClass(e){e.classList.remove(\"jqtree-loading\")}submitRequest(e,t,o){const n={cache:!1,dataType:\"json\",error:o,method:\"GET\",success:t,...\"string\"==typeof e?{url:e}:e};n.method=n.method?.toUpperCase()??\"GET\",jQuery.ajax(n)}}const t=e=>e?\"true\":\"false\",o=e=>n(e).top,n=e=>{const t=e.getBoundingClientRect();return{left:t.x+window.scrollX,top:t.y+window.scrollY}};class s{constructor({autoEscape:e,nodeName:t,offsetX:o,offsetY:n,treeElement:s}){this.offsetX=o,this.offsetY=n,this.element=this.createElement(t,e),s.appendChild(this.element)}move(e,t){this.element.style.left=e-this.offsetX+\"px\",this.element.style.top=t-this.offsetY+\"px\"}remove(){this.element.remove()}createElement(e,t){const o=document.createElement(\"span\");return o.classList.add(\"jqtree-title\",\"jqtree-dragging\"),t?o.textContent=e:o.innerHTML=e,o.style.position=\"absolute\",o}}const r=(e,t,o,n)=>{const s=Math.min(t.length,4),r=Math.round((n-o)/s);let i=o;for(let o=0;o<s;o++){const n=t[o];n.position&&e.push({bottom:i+r,node:n.node,position:n.position,top:i}),i+=r}};class i{constructor({autoEscape:e,getNodeElement:t,getNodeElementForNode:o,getScrollLeft:n,getTree:s,onCanMove:r,onCanMoveTo:i,onDragMove:l,onDragStop:a,onIsMoveHandle:d,openFolderDelay:h,openNode:c,refreshElements:u,slide:m,treeElement:g,triggerEvent:p}){this.autoEscape=e,this.getNodeElement=t,this.getNodeElementForNode=o,this.getScrollLeft=n,this.getTree=s,this.onCanMove=r,this.onCanMoveTo=i,this.onDragMove=l,this.onDragStop=a,this.onIsMoveHandle=d,this.openFolderDelay=h,this.openNode=c,this.refreshElements=u,this.slide=m,this.treeElement=g,this.triggerEvent=p,this.hoveredArea=null,this.hitAreas=[],this.isDragging=!1,this.currentItem=null}mouseCapture(e){const t=e.target;if(!this.mustCaptureElement(t))return null;if(this.onIsMoveHandle&&!this.onIsMoveHandle(jQuery(t)))return null;let o=this.getNodeElement(t);return o&&this.onCanMove&&(this.onCanMove(o.node)||(o=null)),this.currentItem=o,null!=this.currentItem}mouseDrag(e){if(!this.currentItem||!this.dragElement)return!1;this.dragElement.move(e.pageX,e.pageY);const t=this.findHoveredArea(e.pageX,e.pageY);return t&&this.canMoveToArea(t,this.currentItem)?(t.node.isFolder()||this.stopOpenFolderTimer(),this.hoveredArea!==t&&(this.hoveredArea=t,this.mustOpenFolderTimer(t)?this.startOpenFolderTimer(t.node):this.stopOpenFolderTimer(),this.updateDropHint())):(this.removeDropHint(),this.stopOpenFolderTimer(),this.hoveredArea=t),t||this.onDragMove&&this.onDragMove(this.currentItem.node,e.originalEvent),!0}mouseStart(e){if(!this.currentItem)return!1;this.refresh();const{left:t,top:o}=n(e.target),r=this.currentItem.node;return this.dragElement=new s({autoEscape:this.autoEscape??!0,nodeName:r.name,offsetX:e.pageX-t,offsetY:e.pageY-o,treeElement:this.treeElement}),this.isDragging=!0,this.currentItem.element.classList.add(\"jqtree-moving\"),!0}mouseStop(e){this.moveItem(e),this.clear(),this.removeHover(),this.removeDropHint(),this.removeHitAreas();const t=this.currentItem;return this.currentItem&&(this.currentItem.element.classList.remove(\"jqtree-moving\"),this.currentItem=null),this.isDragging=!1,!this.hoveredArea&&t&&this.onDragStop&&this.onDragStop(t.node,e.originalEvent),!1}refresh(){if(this.removeHitAreas(),this.currentItem){const e=this.currentItem.node;this.generateHitAreas(e),this.currentItem=this.getNodeElementForNode(e),this.isDragging&&this.currentItem.element.classList.add(\"jqtree-moving\")}}canMoveToArea(e,t){return!this.onCanMoveTo||this.onCanMoveTo(t.node,e.node,e.position)}clear(){this.dragElement&&(this.dragElement.remove(),this.dragElement=null)}findHoveredArea(e,t){const o=this.getTreeDimensions();return e<o.left||t<o.top||e>o.right||t>o.bottom?null:function(e,t){let o=0,n=e.length;for(;o<n;){const s=o+n>>1,r=e[s];if(void 0===r)return null;const i=t(r);if(i>0)n=s;else{if(!(i<0))return r;o=s+1}}return null}(this.hitAreas,e=>t<e.top?1:t>e.bottom?-1:0)}generateHitAreas(e){const t=this.getTree();this.hitAreas=t?((e,t,n)=>((e,t)=>{if(!e.length)return[];let o=e[0].top,n=[];const s=[];for(const t of e)t.top!==o&&n.length&&(r(s,n,o,t.top),o=t.top,n=[]),n.push(t);return r(s,n,o,t),s})(((e,t)=>{const n=[];let s=0;const r=(e,t,o)=>{n.push({node:e,position:t,top:o}),s=o};return((e,{handleAfterOpenFolder:t,handleClosedFolder:o,handleFirstNode:n,handleNode:s,handleOpenFolder:r})=>{let i=!0;const l=(e,a)=>{let d=(e.is_open||!e.element)&&e.hasChildren(),h=null;if(e.element?.offsetParent&&(h=e.element,i&&(n(e),i=!1),e.hasChildren()?e.is_open?r(e,e.element)||(d=!1):o(e,a,h):s(e,a,e.element)),d){const o=e.children.length;e.children.forEach((t,n)=>{const s=e.children[n];if(s)if(n===o-1)l(s,null);else{const t=e.children[n+1];t&&l(s,t)}}),e.is_open&&h&&t(e,a)}};l(e,null)})(e,{handleAfterOpenFolder:(e,o)=>{r(e,e===t||o===t?null:\"after\",s)},handleClosedFolder:(e,n,s)=>{const i=o(s);e===t?r(e,null,i):(r(e,\"inside\",i),n!==t&&r(e,\"after\",i))},handleFirstNode:e=>{e!==t&&e.element&&r(e,\"before\",o(e.element))},handleNode:(e,n,s)=>{const i=o(s);r(e,e===t?null:\"inside\",i),r(e,n===t||e===t?null:\"after\",i)},handleOpenFolder:(e,n)=>{if(e===t){const t=o(n),s=n.clientHeight;return r(e,null,t),s>5&&r(e,null,t+s-5),!1}return e.children[0]!==t&&r(e,\"inside\",o(n)),!0}}),n})(e,t),n))(t,e,this.getTreeDimensions().bottom):[]}getTreeDimensions(){const e=n(this.treeElement),t=e.left+this.getScrollLeft(),o=e.top;return{bottom:o+this.treeElement.clientHeight+16,left:t,right:t+this.treeElement.clientWidth,top:o}}moveItem(e){if(this.currentItem&&this.hoveredArea?.position&&this.canMoveToArea(this.hoveredArea,this.currentItem)){const t=this.currentItem.node,o=this.hoveredArea.node,n=this.hoveredArea.position,s=t.parent;\"inside\"===n&&(this.hoveredArea.node.is_open=!0);const r=()=>{const e=this.getTree();e&&(e.moveNode(t,o,n),this.treeElement.textContent=\"\",this.refreshElements(null))};this.triggerEvent(\"tree.move\",{move_info:{do_move:r,moved_node:t,original_event:e.originalEvent,position:n,previous_parent:s,target_node:o}}).isDefaultPrevented()||r()}}mustCaptureElement(e){const t=e.nodeName;return\"INPUT\"!==t&&\"SELECT\"!==t&&\"TEXTAREA\"!==t}mustOpenFolderTimer(e){const t=e.node;return t.isFolder()&&!t.is_open&&\"inside\"===e.position}removeDropHint(){this.previousGhost&&this.previousGhost.remove()}removeHitAreas(){this.hitAreas=[]}removeHover(){this.hoveredArea=null}startOpenFolderTimer(e){this.stopOpenFolderTimer();const t=this.openFolderDelay;!1!==t&&(this.openFolderTimer=window.setTimeout(()=>{this.openNode(e,this.slide,()=>{this.refresh(),this.updateDropHint()})},t))}stopOpenFolderTimer(){this.openFolderTimer&&(clearTimeout(this.openFolderTimer),this.openFolderTimer=null)}updateDropHint(){if(!this.hoveredArea)return;this.removeDropHint();const e=this.getNodeElementForNode(this.hoveredArea.node);this.previousGhost=e.addDropHint(this.hoveredArea.position)}}class l{constructor({$element:e,autoEscape:t,buttonLeft:o,closedIcon:n,dragAndDrop:s,getTree:r,isNodeSelected:i,onCreateLi:l,openedIcon:a,rtl:d,showEmptyFolder:h,tabIndex:c}){this.autoEscape=t,this.buttonLeft=o,this.dragAndDrop=s,this.$element=e,this.getTree=r,this.isNodeSelected=i,this.onCreateLi=l,this.rtl=d,this.showEmptyFolder=h,this.tabIndex=c,this.openedIconElement=this.createButtonElement(a??\"+\"),this.closedIconElement=this.createButtonElement(n??\"-\")}render(e){e?.parent?this.renderFromNode(e):this.renderFromRoot()}renderFromNode(e){if(!e.element)return;const t=jQuery(e.element),o=this.createLi(e,e.getLevel());t.after(o),t.remove(),this.createDomElements(o,e.children,!1,e.getLevel()+1)}renderFromRoot(){this.$element.empty();const e=this.getTree();this.$element[0]&&e&&this.createDomElements(this.$element[0],e.children,!0,1)}attachNodeData(e,t){e.element=t,jQuery(t).data(\"node\",e)}createButtonElement(e){if(\"string\"==typeof e){const t=document.createElement(\"div\");return t.innerHTML=e,document.createTextNode(t.innerHTML)}return e.nodeType?e:jQuery(e)[0]}createDomElements(e,t,o,n){const s=this.createUl(o);e.appendChild(s);for(const e of t){const t=this.createLi(e,n);s.appendChild(t),e.hasChildren()&&this.createDomElements(t,e.children,!1,n+1)}}createFolderLi(e,o,n){const s=this.getButtonClasses(e),r=this.getFolderClasses(e,n),i=e.is_open?this.openedIconElement:this.closedIconElement,l=document.createElement(\"li\");l.className=`jqtree_common ${r}`,l.setAttribute(\"role\",\"none\");const a=document.createElement(\"div\");a.className=\"jqtree-element jqtree_common\",a.setAttribute(\"role\",\"none\"),l.appendChild(a);const d=document.createElement(\"a\");d.className=s,i&&d.appendChild(i.cloneNode(!0)),this.buttonLeft&&a.appendChild(d);const h=this.createTitleSpan(e.name,n,!0,o);return h.setAttribute(\"aria-expanded\",t(e.is_open)),a.appendChild(h),this.buttonLeft||a.appendChild(d),l}createLi(e,t){const o=this.isNodeSelected(e),n=e.isFolder()||e.isEmptyFolder&&this.showEmptyFolder?this.createFolderLi(e,t,o):this.createNodeLi(e,t,o);return this.attachNodeData(e,n),this.onCreateLi&&this.onCreateLi(e,jQuery(n),o),n}createNodeLi(e,t,o){const n=[\"jqtree_common\"];o&&n.push(\"jqtree-selected\");const s=n.join(\" \"),r=document.createElement(\"li\");r.className=s,r.setAttribute(\"role\",\"none\");const i=document.createElement(\"div\");i.className=\"jqtree-element jqtree_common\",i.setAttribute(\"role\",\"none\"),r.appendChild(i);const l=this.createTitleSpan(e.name,o,!1,t);return i.appendChild(l),r}createTitleSpan(e,t,o,n){const s=document.createElement(\"span\");let r=\"jqtree-title jqtree_common\";if(o&&(r+=\" jqtree-title-folder\"),r+=\" jqtree-title-button-\"+(this.buttonLeft?\"left\":\"right\"),s.className=r,t){const e=this.tabIndex;void 0!==e&&s.setAttribute(\"tabindex\",`${e}`)}return this.setTreeItemAriaAttributes(s,e,n,t),this.autoEscape?s.textContent=e:s.innerHTML=e,s}createUl(e){let t,o;e?(t=\"jqtree-tree\",o=\"tree\",this.rtl&&(t+=\" jqtree-rtl\")):(t=\"\",o=\"group\"),this.dragAndDrop&&(t+=\" jqtree-dnd\");const n=document.createElement(\"ul\");return n.className=`jqtree_common ${t}`,n.setAttribute(\"role\",o),n}getButtonClasses(e){const t=[\"jqtree-toggler\",\"jqtree_common\"];return e.is_open||t.push(\"jqtree-closed\"),this.buttonLeft?t.push(\"jqtree-toggler-left\"):t.push(\"jqtree-toggler-right\"),t.join(\" \")}getFolderClasses(e,t){const o=[\"jqtree-folder\"];return e.is_open||o.push(\"jqtree-closed\"),t&&o.push(\"jqtree-selected\"),e.is_loading&&o.push(\"jqtree-loading\"),o.join(\" \")}setTreeItemAriaAttributes(e,o,n,s){e.setAttribute(\"aria-label\",o),e.setAttribute(\"aria-level\",`${n}`),e.setAttribute(\"aria-selected\",t(s)),e.setAttribute(\"role\",\"treeitem\")}}class a{constructor({closeNode:e,getSelectedNode:t,isFocusOnTree:o,keyboardSupport:n,openNode:s,selectNode:r}){this.closeNode=e,this.getSelectedNode=t,this.isFocusOnTree=o,this.keyboardSupport=n,this.openNode=s,this.originalSelectNode=r,n&&document.addEventListener(\"keydown\",this.handleKeyDown)}deinit(){this.keyboardSupport&&document.removeEventListener(\"keydown\",this.handleKeyDown)}moveDown(e){return this.selectNode(e.getNextVisibleNode())}moveUp(e){return this.selectNode(e.getPreviousVisibleNode())}canHandleKeyboard(){return this.keyboardSupport&&this.isFocusOnTree()}handleKeyDown=e=>{if(!this.canHandleKeyboard())return;let t=!1;const o=this.getSelectedNode();if(o)switch(e.key){case\"ArrowDown\":t=this.moveDown(o);break;case\"ArrowLeft\":t=this.moveLeft(o);break;case\"ArrowRight\":t=this.moveRight(o);break;case\"ArrowUp\":t=this.moveUp(o)}t&&e.preventDefault()};moveLeft(e){return e.isFolder()&&e.is_open?(this.closeNode(e),!0):this.selectNode(e.getParent())}moveRight(e){return!!e.isFolder()&&(e.is_open?this.selectNode(e.getNextVisibleNode()):(this.openNode(e),!0))}selectNode(e){return!!e&&(this.originalSelectNode(e),!0)}}const d=e=>({originalEvent:e,pageX:e.pageX,pageY:e.pageY,target:e.target}),h=(e,t)=>({originalEvent:t,pageX:e.pageX,pageY:e.pageY,target:e.target});class c{constructor({element:e,getMouseDelay:t,getNode:o,onClickButton:n,onClickTitle:s,onMouseCapture:r,onMouseDrag:i,onMouseStart:l,onMouseStop:a,triggerEvent:d,useContextMenu:h}){this.element=e,this.getMouseDelay=t,this.getNode=o,this.onClickButton=n,this.onClickTitle=s,this.onMouseCapture=r,this.onMouseDrag=i,this.onMouseStart=l,this.onMouseStop=a,this.triggerEvent=d,this.useContextMenu=h,e.addEventListener(\"click\",this.handleClick),e.addEventListener(\"dblclick\",this.handleDblclick),e.addEventListener(\"mousedown\",this.mouseDown,{passive:!1}),e.addEventListener(\"touchstart\",this.touchStart,{passive:!1}),h&&e.addEventListener(\"contextmenu\",this.handleContextmenu),this.isMouseStarted=!1,this.mouseDelayTimer=null,this.isMouseDelayMet=!1,this.mouseDownInfo=null}deinit(){this.element.removeEventListener(\"click\",this.handleClick),this.element.removeEventListener(\"dblclick\",this.handleDblclick),this.useContextMenu&&this.element.removeEventListener(\"contextmenu\",this.handleContextmenu),this.element.removeEventListener(\"mousedown\",this.mouseDown),this.element.removeEventListener(\"touchstart\",this.touchStart),this.removeMouseMoveEventListeners()}getClickTarget(e){const t=e.closest(\".jqtree-toggler\");if(t){const e=this.getNode(t);if(e)return{node:e,type:\"button\"}}else{const t=e.closest(\".jqtree-element\");if(t){const e=this.getNode(t);if(e)return{node:e,type:\"label\"}}}return null}handleClick=e=>{if(!e.target)return;const t=this.getClickTarget(e.target);if(t)switch(t.type){case\"button\":this.onClickButton(t.node),e.preventDefault(),e.stopPropagation();break;case\"label\":this.triggerEvent(\"tree.click\",{click_event:e,node:t.node}).isDefaultPrevented()||this.onClickTitle(t.node)}};handleContextmenu=e=>{if(!e.target)return;const t=e.target.closest(\"ul.jqtree-tree .jqtree-element\");if(t){const o=this.getNode(t);if(o)return e.preventDefault(),e.stopPropagation(),this.triggerEvent(\"tree.contextmenu\",{click_event:e,node:o}),!1}return null};handleDblclick=e=>{if(!e.target)return;const t=this.getClickTarget(e.target);\"label\"===t?.type&&this.triggerEvent(\"tree.dblclick\",{click_event:e,node:t.node})};handleMouseDown(e){return this.isMouseStarted&&this.handleMouseUp(e),this.mouseDownInfo=e,!!this.onMouseCapture(e)&&(this.handleStartMouse(),!0)}handleMouseMove(e,t){if(this.isMouseStarted)return this.onMouseDrag(t),void(e.cancelable&&e.preventDefault());this.isMouseDelayMet&&(this.mouseDownInfo&&(this.isMouseStarted=this.onMouseStart(this.mouseDownInfo)),this.isMouseStarted?(this.onMouseDrag(t),e.cancelable&&e.preventDefault()):this.handleMouseUp(t))}handleMouseUp(e){this.removeMouseMoveEventListeners(),this.isMouseDelayMet=!1,this.mouseDownInfo=null,this.isMouseStarted&&(this.isMouseStarted=!1,this.onMouseStop(e))}handleStartMouse(){document.addEventListener(\"mousemove\",this.mouseMove,{passive:!1}),document.addEventListener(\"touchmove\",this.touchMove,{passive:!1}),document.addEventListener(\"mouseup\",this.mouseUp,{passive:!1}),document.addEventListener(\"touchend\",this.touchEnd,{passive:!1});const e=this.getMouseDelay();e?this.startMouseDelayTimer(e):this.isMouseDelayMet=!0}mouseDown=e=>{0===e.button&&this.handleMouseDown(d(e))&&e.cancelable&&e.preventDefault()};mouseMove=e=>{this.handleMouseMove(e,d(e))};mouseUp=e=>{this.handleMouseUp(d(e))};removeMouseMoveEventListeners(){document.removeEventListener(\"mousemove\",this.mouseMove),document.removeEventListener(\"touchmove\",this.touchMove),document.removeEventListener(\"mouseup\",this.mouseUp),document.removeEventListener(\"touchend\",this.touchEnd)}startMouseDelayTimer(e){this.mouseDelayTimer&&clearTimeout(this.mouseDelayTimer),this.mouseDelayTimer=window.setTimeout(()=>{this.mouseDownInfo&&(this.isMouseDelayMet=!0)},e),this.isMouseDelayMet=!1}touchEnd=e=>{if(e.touches.length>1)return;const t=e.touches[0];t&&this.handleMouseUp(h(t,e))};touchMove=e=>{if(e.touches.length>1)return;const t=e.touches[0];t&&this.handleMouseMove(e,h(t,e))};touchStart=e=>{if(e.touches.length>1)return;const t=e.touches[0];t&&this.handleMouseDown(h(t,e))}}const u=e=>\"object\"==typeof e&&\"children\"in e&&e.children instanceof Array;class m{constructor(e=null,t=!1,o=m){this.name=\"\",this.load_on_demand=!1,this.isEmptyFolder=null!=e&&u(e)&&0===e.children.length,this.setData(e),this.children=[],this.parent=null,t&&(this.idMapping=new Map,this.tree=this,this.nodeClass=o)}addAfter(e){if(this.parent){const t=this.createNode(e),o=this.parent.getChildIndex(this);return this.parent.addChildAtPosition(t,o+1),t.loadChildrenFromData(e),t}return null}addBefore(e){if(this.parent){const t=this.createNode(e),o=this.parent.getChildIndex(this);return this.parent.addChildAtPosition(t,o),t.loadChildrenFromData(e),t}return null}addChild(e){this.children.push(e),e.setParent(this)}addChildAtPosition(e,t){this.children.splice(t,0,e),e.setParent(this)}addNodeToIndex(e){null!=e.id&&this.idMapping.set(e.id,e)}addParent(e){if(this.parent){const t=this.createNode(e);this.tree&&t.setParent(this.tree);const o=this.parent;for(const e of o.children)t.addChild(e);return o.children=[],o.addChild(t),t}return null}append(e){const t=this.createNode(e);return this.addChild(t),t.loadChildrenFromData(e),t}filter(e){const t=[];return this.iterate(o=>(e(o)&&t.push(o),!0)),t}getChildIndex(e){return this.children.indexOf(e)}getData(e=!1){const t=e=>e.map(e=>{const o={};for(const t in e)if(-1===[\"parent\",\"children\",\"element\",\"idMapping\",\"load_on_demand\",\"nodeClass\",\"tree\",\"isEmptyFolder\"].indexOf(t)&&Object.prototype.hasOwnProperty.call(e,t)){const n=e[t];o[t]=n}return e.hasChildren()&&(o.children=t(e.children)),o});return t(e?[this]:this.children)}getLastChild(){if(this.hasChildren()){const e=this.children[this.children.length-1];return e.hasChildren()&&e.is_open?e.getLastChild():e}return null}getLevel(){let e=0,t=this;for(;t.parent;)e+=1,t=t.parent;return e}getNextNode(e=!0){return e&&this.hasChildren()?this.children[0]??null:this.parent?this.getNextSibling()||this.parent.getNextNode(!1):null}getNextSibling(){if(this.parent){const e=this.parent.getChildIndex(this)+1;return e<this.parent.children.length?this.parent.children[e]??null:null}return null}getNextVisibleNode(){return this.hasChildren()&&this.is_open?this.children[0]??null:this.parent?this.getNextSibling()||this.parent.getNextNode(!1):null}getNodeByCallback(e){let t=null;return this.iterate(o=>!(t||e(o)&&(t=o,1))),t}getNodeById(e){return this.idMapping.get(e)??null}getNodeByName(e){return this.getNodeByCallback(t=>t.name===e)}getNodeByNameMustExist(e){const t=this.getNodeByCallback(t=>t.name===e);if(!t)throw new Error(`Node with name ${e} not found`);return t}getNodesByProperty(e,t){return this.filter(o=>o[e]===t)}getParent(){return this.parent&&this.parent.parent?this.parent:null}getPreviousNode(){if(this.parent){const e=this.getPreviousSibling();return e?e.hasChildren()?e.getLastChild():e:this.getParent()}return null}getPreviousSibling(){if(this.parent){const e=this.parent.getChildIndex(this)-1;return e>=0?this.parent.children[e]??null:null}return null}getPreviousVisibleNode(){if(this.parent){const e=this.getPreviousSibling();return e?e.hasChildren()&&e.is_open?e.getLastChild():e:this.getParent()}return null}hasChildren(){return 0!==this.children.length}initFromData(e){const t=e=>{for(const t of e){const e=this.createNode();e.initFromData(t),this.addChild(e)}};(e=>{this.setData(e),u(e)&&e.children.length&&t(e.children)})(e)}isFolder(){return this.hasChildren()||this.load_on_demand}isParentOf(e){let t=e.parent;for(;t;){if(t===this)return!0;t=t.parent}return!1}iterate(e){const t=(o,n)=>{for(const s of o.children)e(s,n)&&s.hasChildren()&&t(s,n+1)};t(this,0)}loadFromData(e){this.removeChildren();for(const t of e){const e=this.createNode(t);this.addChild(e),u(t)&&e.loadFromData(t.children)}return this}moveNode(e,t,o){if(!e.parent||e.isParentOf(t))return!1;switch(e.parent.doRemoveChild(e),o){case\"after\":return!!t.parent&&(t.parent.addChildAtPosition(e,t.parent.getChildIndex(t)+1),!0);case\"before\":return!!t.parent&&(t.parent.addChildAtPosition(e,t.parent.getChildIndex(t)),!0);case\"inside\":return t.addChildAtPosition(e,0),!0}}prepend(e){const t=this.createNode(e);return this.addChildAtPosition(t,0),t.loadChildrenFromData(e),t}remove(){this.parent&&(this.parent.removeChild(this),this.parent=null)}removeChild(e){e.removeChildren(),this.doRemoveChild(e)}removeChildren(){this.iterate(e=>(this.tree?.removeNodeFromIndex(e),!0)),this.children=[]}removeNodeFromIndex(e){null!=e.id&&this.idMapping.delete(e.id)}setData(e){if(e)if(\"string\"==typeof e)this.name=e;else if(\"object\"==typeof e)for(const t in e)if(Object.prototype.hasOwnProperty.call(e,t)){const o=e[t];\"label\"===t||\"name\"===t?\"string\"==typeof o&&(this.name=o):\"children\"!==t&&\"parent\"!==t&&(this[t]=o)}}createNode(e){return new(this.getNodeClass())(e)}doRemoveChild(e){this.children.splice(this.getChildIndex(e),1),this.tree?.removeNodeFromIndex(e)}getNodeClass(){return this.nodeClass??this.tree?.nodeClass??m}loadChildrenFromData(e){u(e)&&e.children.length&&this.loadFromData(e.children)}setParent(e){this.parent=e,this.tree=e.tree,this.tree?.addNodeToIndex(this)}}class g{constructor(e,t){const o=e.querySelector(\":scope > .jqtree-element\");if(!o)return void(this.hint=void 0);const n=Math.max(e.offsetWidth+t-4,0),s=Math.max(e.clientHeight-4,0),r=document.createElement(\"span\");r.className=\"jqtree-border\",r.style.width=`${n}px`,r.style.height=`${s}px`,this.hint=r,o.append(this.hint)}remove(){this.hint?.remove()}}class p{constructor(e,t,o){switch(this.element=t,this.node=e,this.ghost=this.createGhostElement(),o){case\"after\":this.moveAfter();break;case\"before\":this.moveBefore();break;case\"inside\":e.isFolder()&&e.is_open?this.moveInsideOpenFolder():this.moveInside()}}remove(){this.ghost.remove()}createGhostElement(){const e=document.createElement(\"li\");e.className=\"jqtree_common jqtree-ghost\";const t=document.createElement(\"span\");t.className=\"jqtree_common jqtree-circle\",e.append(t);const o=document.createElement(\"span\");return o.className=\"jqtree_common jqtree-line\",e.append(o),e}moveAfter(){this.element.after(this.ghost)}moveBefore(){this.element.before(this.ghost)}moveInside(){this.element.after(this.ghost),this.ghost.classList.add(\"jqtree-inside\")}moveInsideOpenFolder(){const e=this.node.children[0]?.element;e&&e.before(this.ghost)}}class f{constructor({getScrollLeft:e,node:t,tabIndex:o,treeElement:n}){this.getScrollLeft=e,this.tabIndex=o,this.treeElement=n,this.init(t)}addDropHint(e){return this.mustShowBorderDropHint(e)?new g(this.element,this.getScrollLeft()):new p(this.node,this.element,e)}deselect(){this.element.classList.remove(\"jqtree-selected\");const e=this.getTitleSpan();e.removeAttribute(\"tabindex\"),e.setAttribute(\"aria-selected\",\"false\"),e.blur()}init(e){this.node=e,e.element??=this.treeElement,this.element=e.element}select(e){this.element.classList.add(\"jqtree-selected\");const t=this.getTitleSpan(),o=this.tabIndex;null!=o&&t.setAttribute(\"tabindex\",o.toString()),t.setAttribute(\"aria-selected\",\"true\"),e&&t.focus()}getTitleSpan(){return this.element.querySelector(\":scope > .jqtree-element > span.jqtree-title\")}getUl(){return this.element.querySelector(\":scope > ul\")}mustShowBorderDropHint(e){return\"inside\"===e}}class v extends f{constructor({closedIconElement:e,getScrollLeft:t,node:o,openedIconElement:n,tabIndex:s,treeElement:r,triggerEvent:i}){super({getScrollLeft:t,node:o,tabIndex:s,treeElement:r}),this.closedIconElement=e,this.openedIconElement=n,this.triggerEvent=i}close(e,t){if(!this.node.is_open)return;this.node.is_open=!1;const o=this.getButton();o.classList.add(\"jqtree-closed\"),o.innerHTML=\"\";const n=this.closedIconElement;if(n){const e=n.cloneNode(!0);o.appendChild(e)}const s=()=>{this.element.classList.add(\"jqtree-closed\"),this.getTitleSpan().setAttribute(\"aria-expanded\",\"false\"),this.triggerEvent(\"tree.close\",{node:this.node})};e?jQuery(this.getUl()).slideUp(t,s):(jQuery(this.getUl()).hide(),s())}open(e,t,o){if(this.node.is_open)return;this.node.is_open=!0;const n=this.getButton();n.classList.remove(\"jqtree-closed\"),n.innerHTML=\"\";const s=this.openedIconElement;if(s){const e=s.cloneNode(!0);n.appendChild(e)}const r=()=>{this.element.classList.remove(\"jqtree-closed\"),this.getTitleSpan().setAttribute(\"aria-expanded\",\"true\"),e&&e(this.node),this.triggerEvent(\"tree.open\",{node:this.node})};t?jQuery(this.getUl()).slideDown(o,r):(jQuery(this.getUl()).show(),r())}mustShowBorderDropHint(e){return!this.node.is_open&&\"inside\"===e}getButton(){return this.element.querySelector(\":scope > .jqtree-element > a.jqtree-toggler\")}}class S{constructor({addToSelection:e,getNodeById:t,getSelectedNodes:o,getTree:n,onGetStateFromStorage:s,onSetStateFromStorage:r,openNode:i,refreshElements:l,removeFromSelection:a,saveState:d}){this.addToSelection=e,this.getNodeById=t,this.getSelectedNodes=o,this.getTree=n,this.onGetStateFromStorage=s,this.onSetStateFromStorage=r,this.openNode=i,this.refreshElements=l,this.removeFromSelection=a,this.saveStateOption=d}getNodeIdToBeSelected(){const e=this.getStateFromStorage();return e?.selected_node?e.selected_node[0]??null:null}getState(){return{open_nodes:(()=>{const e=[];return this.getTree()?.iterate(t=>(t.is_open&&t.id&&t.hasChildren()&&e.push(t.id),!0)),e})(),selected_node:(()=>{const e=[];return this.getSelectedNodes().forEach(t=>{null!=t.id&&e.push(t.id)}),e})()}}getStateFromStorage(){const e=this.loadFromStorage();return e?this.parseState(e):null}saveState(){const e=JSON.stringify(this.getState());this.onSetStateFromStorage?this.onSetStateFromStorage(e):localStorage.setItem(this.getKeyName(),e)}setInitialState(e){let t=!1;return e.open_nodes&&(t=this.openInitialNodes(e.open_nodes)),this.resetSelection(),e.selected_node&&this.selectInitialNodes(e.selected_node),t}setInitialStateOnDemand(e,t){let o=0,n=e.open_nodes;const s=()=>{if(!n)return;const s=[];for(const e of n){const t=this.getNodeById(e);t?t.is_loading||(t.load_on_demand?r(t):this.openNode(t,!1)):s.push(e)}n=s,e.selected_node&&this.selectInitialNodes(e.selected_node)&&this.refreshElements(null),0===o&&t()},r=e=>{o+=1,this.openNode(e,!1,()=>{o-=1,s()})};s()}getKeyName(){return\"string\"==typeof this.saveStateOption?this.saveStateOption:\"tree\"}loadFromStorage(){return this.onGetStateFromStorage?this.onGetStateFromStorage():localStorage.getItem(this.getKeyName())}openInitialNodes(e){let t=!1;for(const o of e){const e=this.getNodeById(o);e&&(e.load_on_demand?t=!0:e.is_open=!0)}return t}parseState(e){const t=JSON.parse(e);var o;return t.selected_node&&\"number\"==typeof(o=t.selected_node)&&o%1==0&&(t.selected_node=[t.selected_node]),t}resetSelection(){this.getSelectedNodes().forEach(e=>{this.removeFromSelection(e)})}selectInitialNodes(e){let t=0;for(const o of e){const e=this.getNodeById(o);e&&(t+=1,this.addToSelection(e))}return 0!==t}}class N{constructor({container:e,refreshHitAreas:t}){this.container=e,this.refreshHitAreas=t}checkHorizontalScrolling(e){const t=this.getNewHorizontalScrollDirection(e);this.horizontalScrollDirection!==t&&(this.horizontalScrollDirection=t,null!=this.horizontalScrollTimeout&&window.clearTimeout(this.horizontalScrollTimeout),t&&(this.horizontalScrollTimeout=window.setTimeout(this.scrollHorizontally.bind(this),40)))}checkVerticalScrolling(e){const t=this.getNewVerticalScrollDirection(e);this.verticalScrollDirection!==t&&(this.verticalScrollDirection=t,null!=this.verticalScrollTimeout&&(window.clearTimeout(this.verticalScrollTimeout),this.verticalScrollTimeout=void 0),t&&(this.verticalScrollTimeout=window.setTimeout(this.scrollVertically.bind(this),40)))}getScrollLeft(){return this.container.scrollLeft}scrollToY(e){this.container.scrollTop=e}stopScrolling(){this.horizontalScrollDirection=void 0,this.verticalScrollDirection=void 0}scrollHorizontally(){if(!this.horizontalScrollDirection)return;const e=\"left\"===this.horizontalScrollDirection?-20:20;this.container.scrollBy({behavior:\"instant\",left:e,top:0}),this.refreshHitAreas(),setTimeout(this.scrollHorizontally.bind(this),40)}scrollVertically(){if(!this.verticalScrollDirection)return;const e=\"top\"===this.verticalScrollDirection?-20:20;this.container.scrollBy({behavior:\"instant\",left:0,top:e}),this.refreshHitAreas(),setTimeout(this.scrollVertically.bind(this),40)}}class E extends N{stopScrolling(){super.stopScrolling(),this.horizontalScrollDirection=void 0,this.verticalScrollDirection=void 0}getNewHorizontalScrollDirection(e){const t=n(this.container),o=this.container.getBoundingClientRect().width,s=t.left+o,r=t.left;return e>s-20?\"right\":e<r+20?\"left\":void 0}getNewVerticalScrollDirection(e){return e<this.getScrollParentTop()?\"top\":e>this.getScrollParentBottom()?\"bottom\":void 0}getScrollParentBottom(){if(null==this.scrollParentBottom){const e=this.container.getBoundingClientRect().height;this.scrollParentBottom=this.getScrollParentTop()+e}return this.scrollParentBottom}getScrollParentTop(){return this.scrollParentTop??=o(this.container),this.scrollParentTop}}class D extends N{constructor({refreshHitAreas:e,treeElement:t}){super({container:document.documentElement,refreshHitAreas:e}),this.treeElement=t}scrollToY(e){const t=o(this.treeElement);super.scrollToY(e+t)}stopScrolling(){super.stopScrolling(),this.documentScrollHeight=void 0,this.documentScrollWidth=void 0}getNewHorizontalScrollDirection(e){const t=e-this.container.scrollLeft<20;return e>window.innerWidth-20&&this.canScrollRight()?\"right\":t?\"left\":void 0}getNewVerticalScrollDirection(e){const t=this.container.scrollTop;return e-t<20?\"top\":window.innerHeight-(e-t)<20&&this.canScrollDown()?\"bottom\":void 0}canScrollDown(){return this.container.scrollTop+this.container.clientHeight<this.getDocumentScrollHeight()}canScrollRight(){return this.container.scrollLeft+this.container.clientWidth<this.getDocumentScrollWidth()}getDocumentScrollHeight(){return this.documentScrollHeight??=this.container.scrollHeight,this.documentScrollHeight}getDocumentScrollWidth(){return this.documentScrollWidth??=this.container.scrollWidth,this.documentScrollWidth}}const y=e=>\"auto\"===e||\"scroll\"===e,b=e=>{const t=getComputedStyle(e);return y(t.overflowX)||y(t.overflowY)};class C{constructor({refreshHitAreas:e,treeElement:t}){this.refreshHitAreas=e,this.scrollParent=void 0,this.treeElement=t}checkScrolling(e){this.checkVerticalScrolling(e),this.checkHorizontalScrolling(e)}getScrollLeft(){return this.getScrollParent().getScrollLeft()}scrollToY(e){this.getScrollParent().scrollToY(e)}stopScrolling(){this.getScrollParent().stopScrolling()}checkHorizontalScrolling(e){this.getScrollParent().checkHorizontalScrolling(e.pageX)}checkVerticalScrolling(e){this.getScrollParent().checkVerticalScrolling(e.pageY)}getScrollParent(){return this.scrollParent??=((e,t)=>{const o=(e=>{if(b(e))return e;let t=e.parentElement;for(;t;){if(b(t))return t;t=t.parentElement}return null})(e);return o&&\"HTML\"!==o.tagName?new E({container:o,refreshHitAreas:t}):new D({refreshHitAreas:t,treeElement:e})})(this.treeElement,this.refreshHitAreas),this.scrollParent}}class F{constructor({getNodeById:e}){this.getNodeById=e,this.selectedNodes=new Set,this.clear()}addToSelection(e){null!=e.id?this.selectedNodes.add(e.id):this.selectedSingleNode=e}clear(){this.selectedNodes.clear(),this.selectedSingleNode=null}getSelectedNode(){const e=this.getSelectedNodes();return!!e.length&&(e[0]??!1)}getSelectedNodes(){if(this.selectedSingleNode)return[this.selectedSingleNode];{const e=[];return this.selectedNodes.forEach(t=>{const o=this.getNodeById(t);o&&e.push(o)}),e}}getSelectedNodesUnder(e){if(this.selectedSingleNode)return e.isParentOf(this.selectedSingleNode)?[this.selectedSingleNode]:[];{const t=[];return this.selectedNodes.forEach(o=>{const n=this.getNodeById(o);n&&e.isParentOf(n)&&t.push(n)}),t}}isNodeSelected(e){return null!=e.id?this.selectedNodes.has(e.id):!!this.selectedSingleNode&&this.selectedSingleNode.element===e.element}removeFromSelection(e,t=!1){null==e.id?this.selectedSingleNode&&e.element===this.selectedSingleNode.element&&(this.selectedSingleNode=null):(this.selectedNodes.delete(e.id),t&&e.iterate(()=>(null!=e.id&&this.selectedNodes.delete(e.id),!0)))}}const I=(e,t)=>{const o=()=>`simple_widget_${t}`,n=(e,t)=>{const o=jQuery.data(e,t);return o&&o instanceof T?o:null},s=(t,s)=>{const r=o();for(const o of t.get())if(!n(o,r)){const t=new e(o,s);jQuery.data(o,r)||jQuery.data(o,r,t),t.init()}return t};jQuery.fn[t]=function(e,...t){if(!e)return s(this,null);if(\"object\"==typeof e)return s(this,e);if(\"string\"==typeof e&&\"_\"!==e[0]){const s=e;return\"destroy\"===e?void(e=>{const t=o();for(const o of e.get()){const e=n(o,t);e&&e.destroy(),jQuery.removeData(o,t)}})(this):((e,t,n)=>{let s=null;for(const r of e.get()){const e=jQuery.data(r,o());if(e&&e instanceof T){const o=e[t];o&&\"function\"==typeof o&&(s=o.apply(e,n))}}return s})(this,s,t)}}};class T{static defaults={};constructor(e,t){this.$el=jQuery(e);const o=this.constructor.defaults;this.options={...o,...t}}static register(e,t){I(e,t)}deinit(){}destroy(){this.deinit()}init(){}}const L=\"Node parameter is empty\",M=\"Parameter is empty: \";class w extends T{static defaults={animationSpeed:\"fast\",autoEscape:!0,autoOpen:!1,buttonLeft:!0,closedIcon:void 0,data:void 0,dataFilter:void 0,dataUrl:void 0,dragAndDrop:!1,keyboardSupport:!0,nodeClass:m,onCanMove:void 0,onCanMoveTo:void 0,onCanSelectNode:void 0,onCreateLi:void 0,onDragMove:void 0,onDragStop:void 0,onGetStateFromStorage:void 0,onIsMoveHandle:void 0,onLoadFailed:void 0,onLoading:void 0,onSetStateFromStorage:void 0,openedIcon:\"&#x25bc;\",openFolderDelay:500,rtl:void 0,saveState:!1,selectable:!0,showEmptyFolder:!1,slide:!0,startDndDelay:300,tabIndex:0,useContextMenu:!0};addNodeAfter(e,t){const o=t.addAfter(e);return o&&this.refreshElements(t.parent),o}addNodeBefore(e,t){if(!t)throw Error(M+\"existingNode\");const o=t.addBefore(e);return o&&this.refreshElements(t.parent),o}addParentNode(e,t){if(!t)throw Error(M+\"existingNode\");const o=t.addParent(e);return o&&this.refreshElements(o.parent),o}addToSelection(e,t){if(!e)throw Error(L);return this.selectNodeHandler.addToSelection(e),this.openParents(e),this.getNodeElementForNode(e).select(t??!0),this.saveState(),this.element}appendNode(e,t){const o=t??this.tree,n=o.append(e);return this.refreshElements(o),n}closeNode(e,t){if(!e)throw Error(L);const o=t??this.options.slide;return(e.isFolder()||e.isEmptyFolder)&&(this.createFolderElement(e).close(o,this.options.animationSpeed),this.saveState()),this.element}deinit(){this.element.empty(),this.element.off(),this.keyHandler.deinit(),this.mouseHandler.deinit(),this.tree=new m({},!0),super.deinit()}getNodeByCallback(e){return this.tree.getNodeByCallback(e)}getNodeByHtmlElement(e){const t=e instanceof HTMLElement?e:e.get(0);return t?this.getNode(t):null}getNodeById(e){return this.tree.getNodeById(e)}getNodeByName(e){return this.tree.getNodeByName(e)}getNodeByNameMustExist(e){return this.tree.getNodeByNameMustExist(e)}getNodesByProperty(e,t){return this.tree.getNodesByProperty(e,t)}getSelectedNode(){return this.selectNodeHandler.getSelectedNode()}getSelectedNodes(){return this.selectNodeHandler.getSelectedNodes()}getState(){return this.saveStateHandler.getState()}getStateFromStorage(){return this.saveStateHandler.getStateFromStorage()}getTree(){return this.tree}getVersion(){return\"1.8.11\"}init(){super.init(),this.element=this.$el,this.isInitialized=!1,this.options.rtl=this.getRtlOption(),this.options.closedIcon??=this.getDefaultClosedIcon(),this.connectHandlers(),this.initData()}isDragging(){return this.dndHandler.isDragging}isNodeSelected(e){if(!e)throw Error(L);return this.selectNodeHandler.isNodeSelected(e)}loadData(e,t){return this.doLoadData(e,t),this.element}loadDataFromUrl(e,t,o){return\"string\"==typeof e?this.doLoadDataFromUrl(e,t,o??null):this.doLoadDataFromUrl(null,e,t),this.element}moveDown(){const e=this.getSelectedNode();return e&&this.keyHandler.moveDown(e),this.element}moveNode(e,t,o){if(!e)throw Error(L);if(!t)throw Error(M+\"targetNode\");if(!o)throw Error(M+\"position\");return this.tree.moveNode(e,t,o),this.refreshElements(null),this.element}moveUp(){const e=this.getSelectedNode();return e&&this.keyHandler.moveUp(e),this.element}openNode(e,t,o){if(!e)throw Error(L);const[n,s]=(()=>{let e,n;return\"function\"==typeof t?(e=t,n=null):(n=t,e=o),n??=this.options.slide,[n,e]})();return this.openNodeInternal(e,n,s),this.element}prependNode(e,t){const o=t??this.tree,n=o.prepend(e);return this.refreshElements(o),n}refresh(){return this.refreshElements(null),this.element}refreshHitAreas(){return this.dndHandler.refresh(),this.element}reload(e){return this.doLoadDataFromUrl(null,null,e),this.element}removeFromSelection(e){if(!e)throw Error(L);return this.selectNodeHandler.removeFromSelection(e),this.getNodeElementForNode(e).deselect(),this.saveState(),this.element}removeNode(e){if(!e)throw Error(L);if(!e.parent)throw Error(\"Node has no parent\");this.selectNodeHandler.removeFromSelection(e,!0);const t=e.parent;return e.remove(),this.refreshElements(t),this.element}scrollToNode(e){if(!e)throw Error(L);if(!e.element)return this.element;const t=o(e.element)-o(this.$el.get(0));return this.scrollHandler.scrollToY(t),this.element}selectNode(e,t){return this.doSelectNode(e,t),this.element}setOption(e,t){return this.options[e]=t,this.element}setState(e){return e&&(this.saveStateHandler.setInitialState(e),this.refreshElements(null)),this.element}toggle(e,t=null){if(!e)throw Error(L);const o=t??this.options.slide;return e.is_open?this.closeNode(e,o):this.openNode(e,o),this.element}toJson(){return JSON.stringify(this.tree.getData())}updateNode(e,t){if(!e)throw Error(L);if(!t)return this.element;const o=\"object\"==typeof t&&t.id&&t.id!==e.id;return o&&this.tree.removeNodeFromIndex(e),e.setData(t),o&&this.tree.addNodeToIndex(e),\"object\"==typeof t&&t.children&&t.children instanceof Array&&(e.removeChildren(),t.children.length&&e.loadFromData(t.children)),this.refreshElements(e),this.element}connectHandlers(){const{autoEscape:t,buttonLeft:o,closedIcon:n,dataFilter:s,dragAndDrop:r,keyboardSupport:d,onCanMove:h,onCanMoveTo:u,onCreateLi:m,onDragMove:g,onDragStop:p,onGetStateFromStorage:f,onIsMoveHandle:v,onLoadFailed:N,onLoading:E,onSetStateFromStorage:D,openedIcon:y,openFolderDelay:b,rtl:I,saveState:T,showEmptyFolder:L,slide:M,tabIndex:w}=this.options,H=this.closeNode.bind(this),_=this.getNodeElement.bind(this),x=this.getNodeElementForNode.bind(this),A=this.getNodeById.bind(this),j=this.getSelectedNode.bind(this),k=this.getTree.bind(this),P=this.isFocusOnTree.bind(this),O=this.loadData.bind(this),q=this.openNodeInternal.bind(this),B=this.refreshElements.bind(this),U=this.refreshHitAreas.bind(this),Q=this.selectNode.bind(this),$=this.element,z=this.element.get(0),R=this.triggerEvent.bind(this),Y=new F({getNodeById:A}),V=Y.addToSelection.bind(Y),X=Y.getSelectedNodes.bind(Y),G=Y.isNodeSelected.bind(Y),W=Y.removeFromSelection.bind(Y),K=new e({dataFilter:s,loadData:O,onLoadFailed:N,onLoading:E,treeElement:z,triggerEvent:R}),J=new S({addToSelection:V,getNodeById:A,getSelectedNodes:X,getTree:k,onGetStateFromStorage:f,onSetStateFromStorage:D,openNode:q,refreshElements:B,removeFromSelection:W,saveState:T}),Z=new C({refreshHitAreas:U,treeElement:z}),ee=Z.getScrollLeft.bind(Z),te=new i({autoEscape:t,getNodeElement:_,getNodeElementForNode:x,getScrollLeft:ee,getTree:k,onCanMove:h,onCanMoveTo:u,onDragMove:g,onDragStop:p,onIsMoveHandle:v,openFolderDelay:b,openNode:q,refreshElements:B,slide:M,treeElement:z,triggerEvent:R}),oe=new a({closeNode:H,getSelectedNode:j,isFocusOnTree:P,keyboardSupport:d,openNode:q,selectNode:Q}),ne=new l({$element:$,autoEscape:t,buttonLeft:o,closedIcon:n,dragAndDrop:r,getTree:k,isNodeSelected:G,onCreateLi:m,openedIcon:y,rtl:I,showEmptyFolder:L,tabIndex:w}),se=this.getNode.bind(this),re=this.mouseCapture.bind(this),ie=this.mouseDrag.bind(this),le=this.mouseStart.bind(this),ae=this.mouseStop.bind(this),de=new c({element:z,getMouseDelay:()=>this.options.startDndDelay??0,getNode:se,onClickButton:this.toggle.bind(this),onClickTitle:this.doSelectNode.bind(this),onMouseCapture:re,onMouseDrag:ie,onMouseStart:le,onMouseStop:ae,triggerEvent:R,useContextMenu:this.options.useContextMenu});this.dataLoader=K,this.dndHandler=te,this.keyHandler=oe,this.mouseHandler=de,this.renderer=ne,this.saveStateHandler=J,this.scrollHandler=Z,this.selectNodeHandler=Y}containsElement(e){const t=this.getNode(e);return t?.tree===this.tree}createFolderElement(e){const t=this.renderer.closedIconElement,o=this.scrollHandler.getScrollLeft.bind(this.scrollHandler),n=this.renderer.openedIconElement,s=this.options.tabIndex,r=this.element.get(0),i=this.triggerEvent.bind(this);return new v({closedIconElement:t,getScrollLeft:o,node:e,openedIconElement:n,tabIndex:s,treeElement:r,triggerEvent:i})}createNodeElement(e){const t=this.scrollHandler.getScrollLeft.bind(this.scrollHandler),o=this.options.tabIndex,n=this.element.get(0);return new f({getScrollLeft:t,node:e,tabIndex:o,treeElement:n})}deselectCurrentNode(){const e=this.getSelectedNode();e&&this.removeFromSelection(e)}deselectNodes(e){const t=this.selectNodeHandler.getSelectedNodesUnder(e);for(const e of t)this.selectNodeHandler.removeFromSelection(e)}doLoadData(e,t){e&&(t?(this.deselectNodes(t),this.loadSubtree(e,t)):this.initTree(e),this.isDragging()&&this.dndHandler.refresh()),this.triggerEvent(\"tree.load_data\",{parent_node:t,tree_data:e})}doLoadDataFromUrl(e,t,o){const n=e??this.getDataUrlInfo(t);this.dataLoader.loadFromUrl(n,t,o)}doSelectNode(e,t){const o=()=>{this.options.saveState&&this.saveStateHandler.saveState()};if(!e)return this.deselectCurrentNode(),void o();const n={mustSetFocus:!0,mustToggle:!0,...t??{}};if((()=>this.options.onCanSelectNode?this.options.selectable&&this.options.onCanSelectNode(e):this.options.selectable)()){if(this.selectNodeHandler.isNodeSelected(e))n.mustToggle&&(this.deselectCurrentNode(),this.triggerEvent(\"tree.select\",{node:null,previous_node:e}));else{const t=this.getSelectedNode()||null;this.deselectCurrentNode(),this.addToSelection(e,n.mustSetFocus),this.triggerEvent(\"tree.select\",{deselected_node:t,node:e}),this.openParents(e)}o()}}getAutoOpenMaxLevel(){return!0===this.options.autoOpen?-1:\"number\"==typeof this.options.autoOpen?this.options.autoOpen:\"string\"==typeof this.options.autoOpen?parseInt(this.options.autoOpen,10):0}getDataUrlInfo(e){const t=this.options.dataUrl??this.element.data(\"url\"),o=t=>{if(e?.id){const o={node:e.id};t.data=o}else{const e=this.getNodeIdToBeSelected();if(e){const o={selected_node:e};t.data=o}}};return\"function\"==typeof t?t(e):\"string\"==typeof t?(e=>{const t={url:e};return o(t),t})(t):t&&\"object\"==typeof t?(o(t),t):null}getDefaultClosedIcon(){return this.options.rtl?\"&#x25c0;\":\"&#x25ba;\"}getNode(e){const t=e.closest(\"li.jqtree_common\");return t?jQuery(t).data(\"node\"):null}getNodeElement(e){const t=this.getNode(e);return t?this.getNodeElementForNode(t):null}getNodeElementForNode(e){return e.isFolder()?this.createFolderElement(e):this.createNodeElement(e)}getNodeIdToBeSelected(){return this.options.saveState?this.saveStateHandler.getNodeIdToBeSelected():null}getRtlOption(){if(null!=this.options.rtl)return this.options.rtl;{const e=this.element.data(\"rtl\");return null!==e&&!1!==e&&void 0!==e}}initData(){this.options.data?this.doLoadData(this.options.data,null):this.getDataUrlInfo(null)?this.doLoadDataFromUrl(null,null,null):this.doLoadData([],null)}initTree(e){const t=()=>{this.isInitialized||(this.isInitialized=!0,this.triggerEvent(\"tree.init\"))};this.tree=new this.options.nodeClass(null,!0,this.options.nodeClass),this.selectNodeHandler.clear(),this.tree.loadFromData(e);const o=this.setInitialState();this.refreshElements(null),o?this.setInitialStateOnDemand(t):t()}isFocusOnTree(){const e=document.activeElement;return\"SPAN\"===e?.tagName&&this.containsElement(e)}isSelectedNodeInSubtree(e){const t=this.getSelectedNode();return!!t&&(e===t||e.isParentOf(t))}loadFolderOnDemand(e,t=!0,o){e.is_loading=!0,this.doLoadDataFromUrl(null,e,()=>{this.openNodeInternal(e,t,o)})}loadSubtree(e,t){t.loadFromData(e),t.load_on_demand=!1,t.is_loading=!1,this.refreshElements(t)}mouseCapture(e){return!!this.options.dragAndDrop&&this.dndHandler.mouseCapture(e)}mouseDrag(e){if(this.options.dragAndDrop){const t=this.dndHandler.mouseDrag(e);return this.scrollHandler.checkScrolling(e),t}return!1}mouseStart(e){return!!this.options.dragAndDrop&&this.dndHandler.mouseStart(e)}mouseStop(e){return!!this.options.dragAndDrop&&(this.scrollHandler.stopScrolling(),this.dndHandler.mouseStop(e))}openNodeInternal(e,t=!0,o){const n=(t,o,n)=>{e.children.length&&this.createFolderElement(t).open(n,o,this.options.animationSpeed)};if(e.isFolder()||e.isEmptyFolder)if(e.load_on_demand)this.loadFolderOnDemand(e,t,o);else{let s=e.parent;for(;s;)s.parent&&n(s,!1),s=s.parent;n(e,t,o),this.saveState()}}openParents(e){const t=e.parent;t?.parent&&!t.is_open&&this.openNode(t,!1)}refreshElements(e){const t=this.isFocusOnTree(),o=!!e&&this.isSelectedNodeInSubtree(e);this.renderer.render(e),o&&this.selectCurrentNode(t),this.triggerEvent(\"tree.refresh\")}saveState(){this.options.saveState&&this.saveStateHandler.saveState()}selectCurrentNode(e){const t=this.getSelectedNode();t&&this.getNodeElementForNode(t).select(e)}setInitialState(){let[e,t]=(()=>{if(this.options.saveState){const e=this.saveStateHandler.getStateFromStorage();return e?[!0,this.saveStateHandler.setInitialState(e)]:[!1,!1]}return[!1,!1]})();return e||(t=(()=>{if(!1===this.options.autoOpen)return!1;const e=this.getAutoOpenMaxLevel();let t=!1;return this.tree.iterate((o,n)=>o.load_on_demand?(t=!0,!1):!!o.hasChildren()&&(o.is_open=!0,n!==e)),t})()),t}setInitialStateOnDemand(e){(()=>{if(this.options.saveState){const t=this.saveStateHandler.getStateFromStorage();return!!t&&(this.saveStateHandler.setInitialStateOnDemand(t,e),!0)}return!1})()||(()=>{const t=this.getAutoOpenMaxLevel();let o=0;const n=e=>{o+=1,this.openNodeInternal(e,!1,()=>{o-=1,s()})},s=()=>{this.tree.iterate((e,o)=>e.load_on_demand?(e.is_loading||n(e),!1):(this.openNodeInternal(e,!1),o!==t)),0===o&&e()};s()})()}triggerEvent(e,t){const o=jQuery.Event(e,t);return this.element.trigger(o),o}}T.register(w,\"tree\")}()}},t={};function o(n){var s=t[n];if(void 0!==s)return s.exports;var r=t[n]={exports:{}};return e[n](r,r.exports,o),r.exports}(()=>{\"use strict\";var e=o(163);o(751);jQuery(()=>{const t=jQuery(\"#tree\");if(t.length){const o=t.data(\"tree-animation-speed\"),n=t.data(\"auto_open\"),s=Boolean(t.data(\"autoescape\")),r=Boolean(t.data(\"has-add-permission\")),i=Boolean(t.data(\"has-change-permission\")),l=t.data(\"tree-mouse-delay\"),a=t.data(\"drag-and-drop\"),d=\"1\"===t.data(\"rtl\"),h=t.data(\"csrf-cookie-name\");!function(t,{animationSpeed:o,autoEscape:n,autoOpen:s,csrfCookieName:r,dragAndDrop:i,hasAddPermission:l,hasChangePermission:a,mouseDelay:d,rtl:h}){let c=null;const u=new URL(t.data(\"insert_at_url\"),\"http://example.com\"),m={};function g(e){return e?null==e.id?null:e.id:\"__root__\"}function p(e){const o=e?e.element:t.get(0),n=g(e);if(!o||null==n)return;const s=document.createElement(\"span\");s.className=\"jqtree-spin\",o.append(s),m[n]=s}function f(e){const t=g(e);if(null==t)return;const o=m[t];o&&o.remove()}const v={autoEscape:n,autoOpen:s,buttonLeft:h,closedIcon:h?\"&#x25c0;\":\"&#x25ba;\",dragAndDrop:i&&a,onCreateLi:function(e,t,o){if(null==e.id)return;const n=t.find(\".jqtree-title\");u.searchParams.set(\"insert_at\",e.id.toString());const s=u.toString().substring(18),r=o?\"0\":\"-1\",i=a?gettext(\"edit\"):gettext(\"view\");n.after(`<a href=\"${e.url}\" class=\"edit\" tabindex=\"${r}\">(${i})</a>`,l?`<a href=\"${s}\" class=\"edit\" tabindex=\"${r}\">(${gettext(\"add\")})</a>`:\"\")},onLoadFailed:function(){t.html(gettext(\"Error while loading the data from the server\"))},saveState:t.data(\"save_state\"),useContextMenu:Boolean(t.data(\"use_context_menu\"))};null!==o&&(v.animationSpeed=o),null!=d&&(v.startDndDelay=d),t.on(\"tree.loading_data\",function(e){const{isLoading:t,node:o}=e;t&&p(o)}),t.on(\"tree.load_data\",function(e){const{parent_node:t}=e;f(t)}),t.on(\"tree.move\",function(t){const o=t,n=o.move_info;if(!n.moved_node.element)return;const s=jQuery(n.moved_node.element),i={position:n.position,target_id:n.target_node.id};p(null),c?.element&&(jQuery(c.element).find(\".mptt-admin-error\").remove(),c=null),o.preventDefault(),jQuery.ajax({beforeSend:t=>{t.setRequestHeader(\"X-CSRFToken\",(r?e.qg(document.cookie)[r]:null)??function(){const e=document.querySelector('[name=\"csrfmiddlewaretoken\"]');return e?.value}()??\"\")},data:i,error:()=>{f(null),s.find(\".jqtree-element\").append(`<span class=\"mptt-admin-error\">${gettext(\"move failed\")}</span>`),c=n.moved_node},success:()=>{n.do_move(),f(null)},type:\"POST\",url:n.moved_node.move_url})}),t.on(\"tree.select\",function(e){const t=e,{deselected_node:o,node:n}=t;o?.element&&jQuery(o.element).find(\".edit\").attr(\"tabindex\",-1),n.element&&jQuery(n.element).find(\".edit\").attr(\"tabindex\",0)}),t.tree(v)}(t,{animationSpeed:o,autoEscape:s,autoOpen:n,csrfCookieName:h,dragAndDrop:a,hasAddPermission:r,hasChangePermission:i,mouseDelay:l,rtl:d})}})})()})();\n//# sourceMappingURL=django_mptt_admin.js.map"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js.LICENSE.txt",
    "content": "/*\nJqTree 1.8.11\n\nCopyright 2026 Marco Braak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n@license\n\n*/\n"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/jquery_namespace.js",
    "content": "window.$ = django.jQuery;\nwindow.jQuery = django.jQuery;\n"
  },
  {
    "path": "django_mptt_admin/templates/django_mptt_admin/change_list.html",
    "content": "{% extends 'admin/change_list.html' %}\n{% load i18n admin_list static javascript_value %}\n\n{% block extrastyle %}\n    {{ block.super }}\n    <script type=\"text/javascript\" src=\"{{ jsi18n_url }}\"></script>\n{% endblock %}\n\n{% block extrahead %}\n    {{ block.super }}\n    {% if django_major_version >= 4 %}\n        <script src=\"{% static 'admin/js/filters.js' %}\" defer></script>\n    {% endif %}\n{% endblock %}\n\n{% block search %}{% endblock %}\n\n{% block result_list %}\n    <div\n        id=\"tree\"\n        class=\"block-style\"\n        data-auto_open=\"{{ tree_auto_open|javascript_value }}\"\n        data-autoescape=\"{{ autoescape|javascript_value }}\"\n        data-csrf-cookie-name=\"{{ csrf_cookie_name }}\"\n        data-insert_at_url=\"{{ insert_at_url }}\"\n        data-drag-and-drop=\"{{ drag_and_drop|javascript_value }}\"\n        data-has-add-permission=\"{{ has_add_permission|javascript_value }}\"\n        data-has-change-permission=\"{{ has_change_permission|javascript_value }}\"\n        {% if LANGUAGE_BIDI %}\n            data-rtl\n        {% endif %}\n        data-save_state=\"{{ app_label }}_{{ model_name }}\"\n        {% if tree_animation_speed is not None %}\n            data-tree-animation-speed=\"{{ tree_animation_speed|javascript_value }}\"\n        {% endif %}\n        {% if tree_mouse_delay is not None %}\n            data-tree-mouse-delay=\"{{ tree_mouse_delay|javascript_value }}\"\n        {% endif %}\n        data-url=\"{{ tree_json_url }}\"\n        data-use_context_menu=\"{{ use_context_menu|javascript_value }}\"\n    ></div>\n{% endblock %}\n\n{% block pagination %}{% endblock %}\n\n{% block object-tools-items %}\n    {{ block.super }}\n    <li>\n        <a href=\"{{ grid_url }}\">{% trans \"Grid view\" %}</a>\n    </li>\n{% endblock %}\n"
  },
  {
    "path": "django_mptt_admin/templates/django_mptt_admin/grid_view.html",
    "content": "{% extends 'admin/change_list.html' %}\n{% load i18n %}\n\n{% block object-tools-items %}\n{{ block.super }}\n<li>\n    <a href=\"{{ tree_url }}\">{% trans \"Tree view\" %}</a>\n</li>\n{% endblock %}\n"
  },
  {
    "path": "django_mptt_admin/templatetags/__init__.py",
    "content": ""
  },
  {
    "path": "django_mptt_admin/templatetags/javascript_value.py",
    "content": "import json\nfrom django import template\n\nregister = template.Library()\n\n\n@register.filter\ndef javascript_value(value):\n    \"\"\"\n    Get javascript value for python value.\n\n    >>> get_javascript_value(True)\n    true\n    >>> get_javascript_value(10)\n    10\n    \"\"\"\n    if isinstance(value, bool):\n        if value:\n            return \"true\"\n        else:\n            return \"false\"\n    else:\n        return json.dumps(value)\n"
  },
  {
    "path": "django_mptt_admin/tree_change_list.py",
    "content": "from django.contrib.admin.views.main import ChangeList\nimport django\n\nfrom . import util\n\n\nclass TreeChangeList(ChangeList):\n    TREE_IGNORED_PARAMS = (\"_\", \"node\", \"selected_node\")\n\n    def __init__(self, request, model, model_admin, list_filter, node_id, max_level):\n        self.node_id = node_id\n        self.max_level = max_level\n\n        params = dict(\n            request=request,\n            model=model,\n            list_display=(),\n            list_display_links=(),\n            list_filter=list_filter,\n            date_hierarchy=None,\n            search_fields=(),\n            list_select_related=(),\n            list_per_page=100,\n            list_max_show_all=200,\n            list_editable=(),\n            model_admin=model_admin,\n            sortable_by=[],\n        )\n\n        if django.VERSION >= (4, 0):\n            params[\"search_help_text\"] = \"\"\n\n        super().__init__(**params)\n\n    def get_filters_params(self, params=None):\n        params = super().get_filters_params()\n\n        lookup_params = params.copy()\n\n        for ignored in self.TREE_IGNORED_PARAMS:\n            if ignored in lookup_params:\n                del lookup_params[ignored]\n\n        return lookup_params\n\n    def get_queryset(self, request, exclude_parameters=None):\n        (\n            self.filter_specs,\n            self.has_filters,\n            remaining_lookup_params,\n            filters_may_have_duplicates,\n            self.has_active_filters,\n        ) = self.get_filters(request)\n\n        qs = util.get_tree_queryset(\n            model=self.model,\n            node_id=self.node_id,\n            max_level=self.max_level,\n        )\n\n        for filter_spec in self.filter_specs:\n            new_qs = filter_spec.queryset(request, qs)\n            if new_qs is not None:\n                qs = new_qs\n\n        self.clear_all_filters_qs = self.get_query_string(\n            new_params=remaining_lookup_params,\n            remove=self.get_filters_params(),\n        )\n\n        return qs\n"
  },
  {
    "path": "django_mptt_admin/util.py",
    "content": "def serialize_id(pk):\n    if isinstance(pk, (int, str)):\n        return pk\n    else:\n        # Nb. special case for uuid field\n        return str(pk)\n\n\ndef get_tree_from_queryset(\n    queryset, on_create_node=None, max_level=None, item_label_field_name=None\n):\n    \"\"\"\n    Return tree data that is suitable for jqTree.\n    The queryset must be sorted by 'tree_id' and 'left' fields.\n    \"\"\"\n    pk_attname = queryset.model._meta.pk.attname\n\n    # Result tree\n    tree = []\n\n    # Dict of all nodes; used for building the tree\n    # - key is node id\n    # - value is node info (label, id)\n    node_dict = dict()\n\n    # The lowest level of the tree; used for building the tree\n    # - Initial value is None; set later\n    # - For the whole tree this is 0, for a subtree this is higher\n    min_level = None\n\n    for instance in queryset:\n        if min_level is None or instance.level < min_level:\n            min_level = instance.level\n\n        pk = getattr(instance, pk_attname)\n\n        if item_label_field_name:\n            label = getattr(instance, item_label_field_name)\n        else:\n            label = str(instance)\n\n        node_info = dict(name=label, id=serialize_id(pk))\n        if on_create_node:\n            on_create_node(instance, node_info)\n\n        if max_level is not None and not instance.is_leaf_node():\n            # If there is a maximum level and this node has children, then initially set property 'load_on_demand' to true.\n            node_info[\"load_on_demand\"] = True\n\n        if instance.level == min_level:\n            # This is the lowest level. Skip finding a parent.\n            # Add node to the tree\n            tree.append(node_info)\n        else:\n            # NB: use instance's local value for parent attribute - consistent values for uuid\n            parent_field = instance._meta.get_field(instance._mptt_meta.parent_attr)\n            parent_attname = parent_field.get_attname()\n            parent_id = getattr(instance, parent_attname)\n\n            # Get parent from node dict\n            parent_info = node_dict.get(parent_id)\n\n            # Check for corner case: parent is deleted.\n            if parent_info:\n                if \"children\" not in parent_info:\n                    parent_info[\"children\"] = []\n\n                # Add node to the tree\n                parent_info[\"children\"].append(node_info)\n\n                # If there is a maximum level, then reset property 'load_on_demand' for parent\n                if max_level is not None:\n                    parent_info[\"load_on_demand\"] = False\n\n        # Update node dict\n        node_dict[pk] = node_info\n\n    return tree\n\n\ndef get_tree_queryset(model, node_id=None, max_level=None, include_root=True):\n    if node_id:\n        node = model.objects.get(pk=node_id)\n\n        if max_level is None:\n            max_level = node.level + 1\n\n        qs = node.get_descendants().filter(level__lte=max_level)\n    else:\n        qs = model._default_manager.all()\n\n        if max_level is True:\n            max_level = 1\n\n        if isinstance(max_level, int) and max_level is not False:\n            qs = qs.filter(level__lte=max_level)\n\n        if not include_root:\n            qs = qs.exclude(level=0)\n\n    return qs.order_by(\"tree_id\", \"lft\")\n\n\ndef get_model_name(model):\n    \"\"\"\n    Get the name of a Django model\n\n    >>> get_model_name(Country)\n    country\n    \"\"\"\n    return model._meta.model_name\n"
  },
  {
    "path": "docs/index.md",
    "content": "# Django Mptt Admin\n\n_Django-mptt-admin_ provides a nice Django Admin interface for [django-mptt models](http://django-mptt.github.io/django-mptt/).\n\n- The source is available on [https://github.com/mbraak/django-mptt-admin](https://github.com/mbraak/django-mptt-admin).\n- Documentation is available on [https://mbraak.github.io/django-mptt-admin/](https://mbraak.github.io/django-mptt-admin/).\n\n![Screenshot](https://raw.github.com/mbraak/django-mptt-admin/master/screenshot.png)\n\n## Requirements\n\nThe package is tested with Django (4.2, 5.2 and 6.0), and django-mptt (0.18). Also with Python 3.10 - 3.14.\n\nOlder versions:\n\n- Version 2.5.x supports Django 4.1.\n- Version 2.7.x supports Django 5.0.\n- Version 2.8.x supports Django 5.1.\n\n## Installation\n\nInstall the package:\n\n```\n$ pip install django-mptt-admin\n```\n\nAdd **django_mptt_admin** to your installed apps in **settings.py**.\n\n```python\n  INSTALLED_APPS = (\n      ..\n      'django_mptt_admin',\n  )\n```\n\nUse the DjangoMpttAdmin class in admin.py:\n\n```python\n    from django.contrib import admin\n    from django_mptt_admin.admin import DjangoMpttAdmin\n    from models import Country\n\n    class CountryAdmin(DjangoMpttAdmin):\n        pass\n\n    admin.site.register(Country, CountryAdmin)\n```\n\n## Options\n\n**tree_animation_speed**\n\nThe speed of the open/close animation in milliseconds. The default is 200 milliseconds.\n\n**tree_auto_open**\n\nAuto-open node. Default value is 1.\n\nValues:\n\n- **True**: autopen all nodes\n- **False**: do not autoopen\n- **integer**: autopen until this level\n\n**tree_load_on_demand**\n\nLoad on demand (True / False / level). Default is True.\n\n- **True**: load nodes on demand\n- **False**: do not load nodes on demand\n- **int**: load nodes on demand until this level\n\n**autoescape**\n\nAutoescape (True / False). Default is True.\n\nAutoescape titles in tree.\n\n**filter_tree_queryset**\n\nOverride the **filter_tree_queryset** method to filter the queyset for the tree.\n\n```python\nclass CountryAdmin(DjangoMpttAdmin):\n  def filter_tree_queryset(self, queryset):\n    return queryset.filter(name='abc')\n```\n\n**is_drag_and_drop_enabled**\n\nOverride the **is_drag_and_drop_enabled** method to disable drag-and-drop. By default drag-and-drop is enabled.\n\n```python\nclass CountryAdmin(DjangoMpttAdmin):\n  def is_drag_and_drop_enabled(self):\n    return False\n```\n\n**use_context_menu**\n\nCapture the contextmenu event. NB: the contextmenu event is triggered when you click with the right mouse button.\n\n- True: Capture the contextmenu event.\n  - This is useful if you want to write custom javascript to catch the `tree.contextmenu` event.\n  - Also see https://mbraak.github.io/jqTree/#usecontextmenu and https://mbraak.github.io/jqTree/#event-tree-contextmenu\n- False (default): do not capture the contextmenu event.\n\n**item_label_field_name**\n\nDefine which field of the model should be the label for tree items.\n\nPossible values are:\n\n- string: name of the model field or model property method to use as tree items label\n- None (default): model unicode used ad tree item label\n\nExample:\n\n```python\nclass MyMpttModel(MPTTModel):\n    title = models.CharField(......\n\n    @property\n    def title_for_admin(self):\n          return '%s %s' % (self.pk, self.title)\n\nclass MyMpttModelAdminClass(MPTTModelAdmin):\n    item_label_field_name = 'title_for_admin'\n```\n\n## Filters\n\nIf you want to use filters, then you can set the `list_filter` option. See the [Django docs](https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter).\n\n```python\nfrom django_mptt_admin.admin import DjangoMpttAdmin\n\nclass CountryAdmin(DjangoMpttAdmin):\n    list_filter = ('continent',)\n```\n\nAlso see the example project for a complete continent filter.\n\n## Changelog\n\n**2.9.0** (december 2025)\n\n- Support Django 6.0; drop support for Django 5.1\n\n**2.8.0** (april 7 2025)\n\n- Support Django 5.2; drop support for Django 5.0\n\n**2.7.2** (january 9 2025)\n\n- Issue #605: fix missing map file\n\n**2.7.1** (january 8 2025)\n\n- Issue #604: delay before opening a folder during drag and drop\n\n**2.7.0** (august 13 2024)\n\n- Issue #557: support Django 5.1; drop support for Django 3.2\n\n**2.6.2** (april 13 2024)\n\n- Issue #509: use css for the loading spinner. Support dark mode.\n- Issue #541: fix javascript import error in Django 3.2 (thanks to scottp-dpaw)\n\n**2.6.1** (december 9 2023)\n\n- Issue #505: fix collectstatic error\n\n**2.6.0** (december 7 2023)\n\n- Issue #495: support Django 5.0\n\n**2.5.1** (may 6 2023)\n\n- Support dark mode (thanks to Sumit Kumar)\n\n**2.5.0** (april 4 2023)\n\n- Support Django 4.2\n\n**2.4.1** (february 1 2023)\n\n- Issue #431: fix get_tree_mouse_delay error\n\n**2.4.0** (january 31 2023)\n\n- Issue #426: handle permissions:\n  - 'Add' link: only display it if the admin user has the 'Add' permission\n  - 'Edit' link: only display it if the admin user has the 'Edit' permission\n    - Otherwise: still display it but change the text to 'view'\n  - Drag and drop: only enable it if the admin user has the 'Edit' permission\n    - It's also possible to disable drag and drop by overriding the 'is_drag_and_drop_enabled' method.\n\n**2.3.0** (august 4 2022)\n\n- Update jqtree to 1.6.2. This fixes an issue with the keyboard focus when using on demand loading.\n- Support Django 4.1\n\n**2.2.0** (december 8 2021)\n\n- Support Django 4.0\n\n**2.1.0** (april 6 2021)\n\n- Issue #353: support Django 3.2\n\n**2.0.3** (march 1 2021)\n\n- Issue #341: update jqtree to 1.6.0\n- Issue #345: add option to disable drag-and-drop (thanks to Maxim Popov)\n\n**2.0.2** (october 27 2020)\n\n- Issue #328: fix DJANGO_MPTT_ADMIN_COVERAGE_JS (thanks to Andrew Kh)\n\n**2.0.1** (october 26 2020)\n\n- Issue #309: add option for animation speed\n- Issue #325: update jqtree to 1.5.2\n\n**2.0.0** (august 7 2020)\n\n- Support Django 3.1\n\n**1.0.2** (june 26 2020)\n\n- Issue #287: add Catalan and Spanish translations (thanks to Joan Marc Soler)\n\n**1.0.1** (february 14 2020)\n\n- Issue #282: add German translations (thanks to Christian Wiegand)\n- Issue #284: add Polish translations (thanks to Paweł Chojnowski)\n\n**1.0.0** (december 5 2019)\n\n- Issue #271: support Django 3\n- Issue #276: fix movement during drag-and-drop\n\n**0.7.2** (october 19 2019)\n\n- Issue #270: support media class (thanks to Sencer H.)\n\n**0.7.1** (april 23 2019)\n\n- Issue #254: upgrade jqtree to 1.4.10\n- Issue #255: test with django-mptt 0.10\n- Issue #258: include jqtree.css in django_mptt_admin.css\n\n**0.7.0** (april 5 2019)\n\n- Issue #242: minified build\n- Issue #243: upgrade jqTree to 1.4.9\n- Issue #252: support Django 2.2\n\n**0.6.0** (august 4 2018)\n\n- Issue #232: support Django 2.1\n- Issue #233: upgrade jqTree to 1.4.7\n\n**0.5.1** (april 8 2018)\n\n- Issue #220: upgrade jqTree to 1.4.5\n- Issue #224: add a spinner for the move action (thanks to Riccardo Magliocchetti)\n\n**0.5.0** (december 7 2017)\n\n- Issue #217: Support Django 2.0\n\n**0.4.7** (september 29 2017)\n\n- Issue #212: Fix unsafe reference to instance.parent (thanks to John D'Ambrosio)\n- Issue #211: Make ChangeList configurable using `change_list_tree_class` (thanks to Riccardo Magliocchetti)\n\n**0.4.6** (june 7 2017)\n\n- Issue #200: Upgrade to jqtree 1.4.1\n- Issue #201: Make 'edit' and 'add' buttons not focusable\n- Issue #203: 'Add' url path must end with '/'\n\n**0.4.5** (april 5 2017)\n\n- Issue #188: Handle CSRF_COOKIE_NAME option\n- Issue #189: Handle Django CSRF_USE_SESSIONS option (new option in Django 1.11)\n- Issue #191: Only initialize the tree on the tree page (thanks to Stanislav Zholudev)\n- Issue #197: Support Django 1.11\n\n**0.4.4** (january 30 2017)\n\n- Issue #185: Support preserved filters (thanks to Riccardo Magliocchetti)\n- Issue #186: Move list_filter option to DjangoMpttAdmin class\n\n**0.4.3** (january 18 2017)\n\n- Issue 178: Added Hungarian translations (thanks to roodie)\n- Issue 182: Add option to configure node label (thanks to Claudio Bartolini)\n- Issue 183: Update jqtree to 1.3.7\n\n**0.4.2** (november 10 2016)\n\n- Issue 170: Added FilterableDjangoMpttAdmin (thanks to Riccardo Magliocchetti)\n- Issue 172: Update jqtree to 1.3.6\n- Issue 173: Move translations to djangojs domain\n- Issue 174: Added French translations (thanks to Vhotz)\n- Issue 175: Fixed: can't move items in tree view with CSRF_COOKIE_HTTPONLY = True (thanks to Vhotz)\n\n**0.4.1** (september 21 2016)\n\n- Issue 162: Add request parameter to filter_tree_queryset signature (thanks to Max Perreault)\n- Issue 163: Update to jqtree 1.3.5\n\n**0.4.0** (august 3 2016)\n\n- Issue 152: Django 1.10 support.\n  - Drop support for Django 1.7\n\n**0.3.8** (july 27 2016)\n\n- Issue 142: use the Django admin static tag for CSS / Javascript (thanks to Alex Tomkins)\n- Issue 143: update jqtree to 1.3.4\n\n**0.3.7** (june 1 2016)\n\n- Issue 132: use MPTTModelAdmin for DjangoMpttAdmin (thanks to Alex Tomkins)\n  - MPTTModelAdmin contains fixes for mass deletions and TreeForeignKey\n- Issue 139: update to jqtree 1.3.3\n\n**0.3.6** (march 28 2016)\n\n- Issue 125: fix jQuery.cookie error (thanks to Patrick Colmant)\n\n**0.3.5** (march 28 2016)\n\n- Issue 126: add missing jqtree-circle.png (thanks to Generalov)\n\n**0.3.4** (march 25 2016)\n\n- Issue 115: implemented 'add' button (thanks to Andrew Dodd)\n- Issue 116: fix block-style layout for right-to-left-languages\n- Issue 119: display transparent loading image\n\n**0.3.3** (february 10 2016)\n\n- Issue 112: correctly override media (thanks to Generalov)\n\n**0.3.2** (january 29 2016)\n\n- Issue 103: use jquery from django admin itself\n- Issue 105: added Turkish translation (thanks to Tagmat)\n- Issue 106: use the same colors as the Django admin\n- Issue 109: include locale files in package\n\n**0.3.1** (december 2 2015)\n\n- Issue 82: make admin views easily extendable (thanks to Vsevolod Novikov)\n- Issue 93: flat styling\n- Issue 95: update jqtree to 1.3.0\n- Issue 96: cannot move to the top of the tree\n- Issue 97: support Django 1.9\n\n**0.3.0** (august 21 2015)\n\n- Issue 67: update jqtree to 1.2.1\n- Issue 68: drop support for Django 1.6 and older\n  - Note that version 0.2.1 supports these versions.\n- Issue 71: added use_context_menu option (thanks to ITCase)\n- Issue 75: added Russian translation (thanks to Mike Silonov)\n- Issue 80: fix wrong url resolving with multiple admin sites (thanks to Hubert Bielenia)\n\n**0.2.1** (march 29 2015)\n\n- Issue 65: support Django 1.8\n\n**0.2.0** (january 12 2015)\n\n- Issue 23: fixed save-state for load-on-demand\n- Issue 35: fixed auto-open for load-on-demand\n- Issue 40: use jqtree 1.0.0\n- Issue 45: added i18n support and Hebrew translation (thanks to Udi Oron)\n- Issue 47: added filter_tree_queryset method\n\n**0.1.10** (september 24 2014)\n\n- Issue 31: added autoescape option\n- Issue 34: use the default change list in popup mode (thanks to hstanev)\n- Issue 36: the option tree_load_on_demand = False does not work\n\n**0.1.9** (july 12 2014)\n\n- Issue 25: update jqtree to 0.21.0\n- Issue 28: fixing problems related to working with model's pk-field, named other than \"id\" (thanks to Igor Gai)\n- Issue 29: fix path to spinner.gif (thanks to Igor Gai)\n\n**0.1.8** (februari 2 2014)\n\n- Issue 17: handle error when moving node\n- Issue 18: do not use inline javascript\n- Issue 19: support Django 1.7 alpha\n\n**0.1.7** (january 3 2014)\n\n- Issue 16: moving a node fails if the node id is a uuid\n\n**0.1.6** (october 10 2013)\n\n- Issue 8: removing node from the tree causes the tree view to crash\n\n**0.1.5** (august 27 2013)\n\n- Issue 6: save the tree state\n- Issue 7: do not handle the right mouse click\n\n**0.1.4** (august 8 2013)\n\n- Issue 5: Support for uuid ids\n\n**0.1.3** (may 2 2013)\n\n_This version drops support for Django 1.3.7_\n\n- Issue 2: Posting a screenshot in the readme would be really useful (thanks to Andy Baker)\n- Issue 3: Use static templatetag for CDN-compatible file paths (thanks to Alex Holmes)\n- Added [Coveralls](https://coveralls.io/r/mbraak/django-mptt-admin) support\n\n**0.1.2** (march 12 2013)\n\n- Issue 1: Grid view doesn't link correctly to object change pages (thanks to Kris Fields)\n\n**0.1.1** (februari 25 2013)\n\n- Added experimental Python 3 support\n\n**0.1** (februari 7 2013)\n\n- Initial version\n\n[![Code Issues](https://www.quantifiedcode.com/api/v1/project/dd888e7a1804465798821f28717af384/badge.svg)](https://www.quantifiedcode.com/app/project/dd888e7a1804465798821f28717af384)\n"
  },
  {
    "path": "example_project/django_mptt_example/__init__.py",
    "content": ""
  },
  {
    "path": "example_project/django_mptt_example/admin.py",
    "content": "from django.contrib import admin\nfrom django.conf import settings\n\nfrom django_mptt_admin.admin import DjangoMpttAdmin\n\nfrom .models import Country\n\n\nclass ContinentFilter(admin.SimpleListFilter):\n    title = \"continent\"\n    parameter_name = \"continent\"\n\n    def lookups(self, request, model_admin):\n        continents = Country.objects.filter(level=1).order_by(\"name\")\n\n        return [(c.name, c.name) for c in continents]\n\n    def queryset(self, request, queryset):\n        value = self.value()\n\n        if not value:\n            return queryset\n        else:\n            continent = Country.objects.get(name=value, level=1)\n\n            return continent.get_descendants(include_self=True)\n\n\nclass CountryAdmin(DjangoMpttAdmin):\n    tree_auto_open = 0\n    list_display = (\"code\", \"name\")\n    ordering = (\"name\",)\n    list_filter = (ContinentFilter,)\n\n    def has_change_permission(self, request, obj=None):\n        return request.user.is_superuser\n\n    def get_tree_mouse_delay(self):\n        if getattr(settings, \"DJANGO_TESTING\", False):\n            return 0\n        else:\n            return None\n\n\n# Display the code for countries instead of the name.\nclass CountryCodeAdmin(CountryAdmin):\n    item_label_field_name = \"code_or_name\"\n\n\n# Display a title with html\nclass CountryWithHtmlAdmin(CountryAdmin):\n    autoescape = False\n    item_label_field_name = \"html_code_and_name\"\n\n\nclass CountryCode(Country):\n    class Meta:\n        proxy = True\n\n\nclass CountryCodeAndName(Country):\n    class Meta:\n        proxy = True\n\n\nadmin.site.register(Country, CountryAdmin)\nadmin.site.register(CountryCode, CountryCodeAdmin)\nadmin.site.register(CountryCodeAndName, CountryWithHtmlAdmin)\n"
  },
  {
    "path": "example_project/django_mptt_example/fixtures/countries.json",
    "content": "[{\"model\": \"django_mptt_example.country\", \"pk\": 1, \"fields\": {\"code\": null, \"name\": \"root\", \"parent\": null, \"lft\": 1, \"rght\": 516, \"tree_id\": 1, \"level\": 0}}, {\"model\": \"django_mptt_example.country\", \"pk\": 2, \"fields\": {\"code\": null, \"name\": \"Africa\", \"parent\": 1, \"lft\": 2, \"rght\": 119, \"tree_id\": 1, \"level\": 1}}, {\"model\": \"django_mptt_example.country\", \"pk\": 3, \"fields\": {\"code\": null, \"name\": \"Antarctica\", \"parent\": 1, \"lft\": 120, \"rght\": 131, \"tree_id\": 1, \"level\": 1}}, {\"model\": \"django_mptt_example.country\", \"pk\": 4, \"fields\": {\"code\": null, \"name\": \"Asia\", \"parent\": 1, \"lft\": 132, \"rght\": 243, \"tree_id\": 1, \"level\": 1}}, {\"model\": \"django_mptt_example.country\", \"pk\": 5, \"fields\": {\"code\": null, \"name\": \"Europe\", \"parent\": 1, \"lft\": 244, \"rght\": 345, \"tree_id\": 1, \"level\": 1}}, {\"model\": \"django_mptt_example.country\", \"pk\": 6, \"fields\": {\"code\": null, \"name\": \"North America\", \"parent\": 1, \"lft\": 346, \"rght\": 431, \"tree_id\": 1, \"level\": 1}}, {\"model\": \"django_mptt_example.country\", \"pk\": 7, \"fields\": {\"code\": null, \"name\": \"Oceania\", \"parent\": 1, \"lft\": 432, \"rght\": 485, \"tree_id\": 1, \"level\": 1}}, {\"model\": \"django_mptt_example.country\", \"pk\": 8, \"fields\": {\"code\": null, \"name\": \"South America\", \"parent\": 1, \"lft\": 486, \"rght\": 515, \"tree_id\": 1, \"level\": 1}}, {\"model\": \"django_mptt_example.country\", \"pk\": 9, \"fields\": {\"code\": \"AF\", \"name\": \"Afghanistan\", \"parent\": 4, \"lft\": 133, \"rght\": 134, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 10, \"fields\": {\"code\": \"AX\", \"name\": \"Åland Islands\", \"parent\": 5, \"lft\": 245, \"rght\": 246, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 11, \"fields\": {\"code\": \"AL\", \"name\": \"Albania\", \"parent\": 5, \"lft\": 247, \"rght\": 248, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 12, \"fields\": {\"code\": \"DZ\", \"name\": \"Algeria\", \"parent\": 2, \"lft\": 3, \"rght\": 4, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 13, \"fields\": {\"code\": \"AS\", \"name\": \"American Samoa\", \"parent\": 7, \"lft\": 433, \"rght\": 434, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 14, \"fields\": {\"code\": \"AD\", \"name\": \"Andorra\", \"parent\": 5, \"lft\": 249, \"rght\": 250, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 15, \"fields\": {\"code\": \"AO\", \"name\": \"Angola\", \"parent\": 2, \"lft\": 5, \"rght\": 6, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 16, \"fields\": {\"code\": \"AI\", \"name\": \"Anguilla\", \"parent\": 6, \"lft\": 347, \"rght\": 348, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 17, \"fields\": {\"code\": \"AQ\", \"name\": \"Antarctica\", \"parent\": 3, \"lft\": 121, \"rght\": 122, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 18, \"fields\": {\"code\": \"AG\", \"name\": \"Antigua and Barbuda\", \"parent\": 6, \"lft\": 349, \"rght\": 350, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 19, \"fields\": {\"code\": \"AR\", \"name\": \"Argentina\", \"parent\": 8, \"lft\": 487, \"rght\": 488, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 20, \"fields\": {\"code\": \"AM\", \"name\": \"Armenia\", \"parent\": 4, \"lft\": 135, \"rght\": 136, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 21, \"fields\": {\"code\": \"AW\", \"name\": \"Aruba\", \"parent\": 6, \"lft\": 351, \"rght\": 352, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 22, \"fields\": {\"code\": \"AU\", \"name\": \"Australia\", \"parent\": 7, \"lft\": 435, \"rght\": 436, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 23, \"fields\": {\"code\": \"AT\", \"name\": \"Austria\", \"parent\": 5, \"lft\": 251, \"rght\": 252, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 24, \"fields\": {\"code\": \"AZ\", \"name\": \"Azerbaijan\", \"parent\": 4, \"lft\": 137, \"rght\": 138, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 25, \"fields\": {\"code\": \"BS\", \"name\": \"Bahamas\", \"parent\": 6, \"lft\": 353, \"rght\": 354, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 26, \"fields\": {\"code\": \"BH\", \"name\": \"Bahrain\", \"parent\": 4, \"lft\": 139, \"rght\": 140, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 27, \"fields\": {\"code\": \"BD\", \"name\": \"Bangladesh\", \"parent\": 4, \"lft\": 141, \"rght\": 142, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 28, \"fields\": {\"code\": \"BB\", \"name\": \"Barbados\", \"parent\": 6, \"lft\": 355, \"rght\": 356, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 29, \"fields\": {\"code\": \"BY\", \"name\": \"Belarus\", \"parent\": 5, \"lft\": 253, \"rght\": 254, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 30, \"fields\": {\"code\": \"BE\", \"name\": \"Belgium\", \"parent\": 5, \"lft\": 255, \"rght\": 256, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 31, \"fields\": {\"code\": \"BZ\", \"name\": \"Belize\", \"parent\": 6, \"lft\": 357, \"rght\": 358, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 32, \"fields\": {\"code\": \"BJ\", \"name\": \"Benin\", \"parent\": 2, \"lft\": 7, \"rght\": 8, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 33, \"fields\": {\"code\": \"BM\", \"name\": \"Bermuda\", \"parent\": 6, \"lft\": 359, \"rght\": 360, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 34, \"fields\": {\"code\": \"BT\", \"name\": \"Bhutan\", \"parent\": 4, \"lft\": 143, \"rght\": 144, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 35, \"fields\": {\"code\": \"BO\", \"name\": \"Bolivia, Plurinational State of\", \"parent\": 8, \"lft\": 489, \"rght\": 490, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 36, \"fields\": {\"code\": \"BQ\", \"name\": \"Bonaire, Sint Eustatius and Saba\", \"parent\": 6, \"lft\": 361, \"rght\": 362, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 37, \"fields\": {\"code\": \"BA\", \"name\": \"Bosnia and Herzegovina\", \"parent\": 5, \"lft\": 257, \"rght\": 258, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 38, \"fields\": {\"code\": \"BW\", \"name\": \"Botswana\", \"parent\": 2, \"lft\": 9, \"rght\": 10, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 39, \"fields\": {\"code\": \"BV\", \"name\": \"Bouvet Island\", \"parent\": 3, \"lft\": 123, \"rght\": 124, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 40, \"fields\": {\"code\": \"BR\", \"name\": \"Brazil\", \"parent\": 8, \"lft\": 491, \"rght\": 492, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 41, \"fields\": {\"code\": \"IO\", \"name\": \"British Indian Ocean Territory\", \"parent\": 4, \"lft\": 145, \"rght\": 146, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 42, \"fields\": {\"code\": \"BN\", \"name\": \"Brunei Darussalam\", \"parent\": 4, \"lft\": 147, \"rght\": 148, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 43, \"fields\": {\"code\": \"BG\", \"name\": \"Bulgaria\", \"parent\": 5, \"lft\": 259, \"rght\": 260, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 44, \"fields\": {\"code\": \"BF\", \"name\": \"Burkina Faso\", \"parent\": 2, \"lft\": 11, \"rght\": 12, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 45, \"fields\": {\"code\": \"BI\", \"name\": \"Burundi\", \"parent\": 2, \"lft\": 13, \"rght\": 14, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 46, \"fields\": {\"code\": \"KH\", \"name\": \"Cambodia\", \"parent\": 4, \"lft\": 149, \"rght\": 150, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 47, \"fields\": {\"code\": \"CM\", \"name\": \"Cameroon\", \"parent\": 2, \"lft\": 15, \"rght\": 16, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 48, \"fields\": {\"code\": \"CA\", \"name\": \"Canada\", \"parent\": 6, \"lft\": 363, \"rght\": 364, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 49, \"fields\": {\"code\": \"CV\", \"name\": \"Cape Verde\", \"parent\": 2, \"lft\": 17, \"rght\": 18, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 50, \"fields\": {\"code\": \"KY\", \"name\": \"Cayman Islands\", \"parent\": 6, \"lft\": 365, \"rght\": 366, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 51, \"fields\": {\"code\": \"CF\", \"name\": \"Central African Republic\", \"parent\": 2, \"lft\": 19, \"rght\": 20, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 52, \"fields\": {\"code\": \"TD\", \"name\": \"Chad\", \"parent\": 2, \"lft\": 21, \"rght\": 22, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 53, \"fields\": {\"code\": \"CL\", \"name\": \"Chile\", \"parent\": 8, \"lft\": 493, \"rght\": 494, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 54, \"fields\": {\"code\": \"CN\", \"name\": \"China\", \"parent\": 4, \"lft\": 151, \"rght\": 152, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 55, \"fields\": {\"code\": \"CX\", \"name\": \"Christmas Island\", \"parent\": 4, \"lft\": 153, \"rght\": 154, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 56, \"fields\": {\"code\": \"CC\", \"name\": \"Cocos (Keeling) Islands\", \"parent\": 4, \"lft\": 155, \"rght\": 156, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 57, \"fields\": {\"code\": \"CO\", \"name\": \"Colombia\", \"parent\": 8, \"lft\": 495, \"rght\": 496, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 58, \"fields\": {\"code\": \"KM\", \"name\": \"Comoros\", \"parent\": 2, \"lft\": 23, \"rght\": 24, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 59, \"fields\": {\"code\": \"CG\", \"name\": \"Congo\", \"parent\": 2, \"lft\": 25, \"rght\": 26, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 60, \"fields\": {\"code\": \"CD\", \"name\": \"Congo, The Democratic Republic of the\", \"parent\": 2, \"lft\": 27, \"rght\": 28, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 61, \"fields\": {\"code\": \"CK\", \"name\": \"Cook Islands\", \"parent\": 7, \"lft\": 437, \"rght\": 438, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 62, \"fields\": {\"code\": \"CR\", \"name\": \"Costa Rica\", \"parent\": 6, \"lft\": 367, \"rght\": 368, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 63, \"fields\": {\"code\": \"CI\", \"name\": \"Côte d'Ivoire\", \"parent\": 2, \"lft\": 29, \"rght\": 30, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 64, \"fields\": {\"code\": \"HR\", \"name\": \"Croatia\", \"parent\": 5, \"lft\": 261, \"rght\": 262, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 65, \"fields\": {\"code\": \"CU\", \"name\": \"Cuba\", \"parent\": 6, \"lft\": 369, \"rght\": 370, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 66, \"fields\": {\"code\": \"CW\", \"name\": \"Curaçao\", \"parent\": 6, \"lft\": 371, \"rght\": 372, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 67, \"fields\": {\"code\": \"CY\", \"name\": \"Cyprus\", \"parent\": 4, \"lft\": 157, \"rght\": 158, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 68, \"fields\": {\"code\": \"CZ\", \"name\": \"Czech Republic\", \"parent\": 5, \"lft\": 263, \"rght\": 264, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 69, \"fields\": {\"code\": \"DK\", \"name\": \"Denmark\", \"parent\": 5, \"lft\": 265, \"rght\": 266, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 70, \"fields\": {\"code\": \"DJ\", \"name\": \"Djibouti\", \"parent\": 2, \"lft\": 31, \"rght\": 32, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 71, \"fields\": {\"code\": \"DM\", \"name\": \"Dominica\", \"parent\": 6, \"lft\": 373, \"rght\": 374, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 72, \"fields\": {\"code\": \"DO\", \"name\": \"Dominican Republic\", \"parent\": 6, \"lft\": 375, \"rght\": 376, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 73, \"fields\": {\"code\": \"EC\", \"name\": \"Ecuador\", \"parent\": 8, \"lft\": 497, \"rght\": 498, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 74, \"fields\": {\"code\": \"EG\", \"name\": \"Egypt\", \"parent\": 2, \"lft\": 33, \"rght\": 34, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 75, \"fields\": {\"code\": \"SV\", \"name\": \"El Salvador\", \"parent\": 6, \"lft\": 377, \"rght\": 378, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 76, \"fields\": {\"code\": \"GQ\", \"name\": \"Equatorial Guinea\", \"parent\": 2, \"lft\": 35, \"rght\": 36, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 77, \"fields\": {\"code\": \"ER\", \"name\": \"Eritrea\", \"parent\": 2, \"lft\": 37, \"rght\": 38, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 78, \"fields\": {\"code\": \"EE\", \"name\": \"Estonia\", \"parent\": 5, \"lft\": 267, \"rght\": 268, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 79, \"fields\": {\"code\": \"ET\", \"name\": \"Ethiopia\", \"parent\": 2, \"lft\": 39, \"rght\": 40, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 80, \"fields\": {\"code\": \"FK\", \"name\": \"Falkland Islands (Malvinas)\", \"parent\": 8, \"lft\": 499, \"rght\": 500, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 81, \"fields\": {\"code\": \"FO\", \"name\": \"Faroe Islands\", \"parent\": 5, \"lft\": 269, \"rght\": 270, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 82, \"fields\": {\"code\": \"FJ\", \"name\": \"Fiji\", \"parent\": 7, \"lft\": 439, \"rght\": 440, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 83, \"fields\": {\"code\": \"FI\", \"name\": \"Finland\", \"parent\": 5, \"lft\": 271, \"rght\": 272, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 84, \"fields\": {\"code\": \"FR\", \"name\": \"France\", \"parent\": 5, \"lft\": 273, \"rght\": 274, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 85, \"fields\": {\"code\": \"GF\", \"name\": \"French Guiana\", \"parent\": 8, \"lft\": 501, \"rght\": 502, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 86, \"fields\": {\"code\": \"PF\", \"name\": \"French Polynesia\", \"parent\": 7, \"lft\": 441, \"rght\": 442, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 87, \"fields\": {\"code\": \"TF\", \"name\": \"French Southern Territories\", \"parent\": 3, \"lft\": 125, \"rght\": 126, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 88, \"fields\": {\"code\": \"GA\", \"name\": \"Gabon\", \"parent\": 2, \"lft\": 41, \"rght\": 42, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 89, \"fields\": {\"code\": \"GM\", \"name\": \"Gambia\", \"parent\": 2, \"lft\": 43, \"rght\": 44, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 90, \"fields\": {\"code\": \"GE\", \"name\": \"Georgia\", \"parent\": 4, \"lft\": 159, \"rght\": 160, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 91, \"fields\": {\"code\": \"DE\", \"name\": \"Germany\", \"parent\": 5, \"lft\": 275, \"rght\": 276, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 92, \"fields\": {\"code\": \"GH\", \"name\": \"Ghana\", \"parent\": 2, \"lft\": 45, \"rght\": 46, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 93, \"fields\": {\"code\": \"GI\", \"name\": \"Gibraltar\", \"parent\": 5, \"lft\": 277, \"rght\": 278, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 94, \"fields\": {\"code\": \"GR\", \"name\": \"Greece\", \"parent\": 5, \"lft\": 279, \"rght\": 280, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 95, \"fields\": {\"code\": \"GL\", \"name\": \"Greenland\", \"parent\": 6, \"lft\": 379, \"rght\": 380, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 96, \"fields\": {\"code\": \"GD\", \"name\": \"Grenada\", \"parent\": 6, \"lft\": 381, \"rght\": 382, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 97, \"fields\": {\"code\": \"GP\", \"name\": \"Guadeloupe\", \"parent\": 6, \"lft\": 383, \"rght\": 384, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 98, \"fields\": {\"code\": \"GU\", \"name\": \"Guam\", \"parent\": 7, \"lft\": 443, \"rght\": 444, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 99, \"fields\": {\"code\": \"GT\", \"name\": \"Guatemala\", \"parent\": 6, \"lft\": 385, \"rght\": 386, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 100, \"fields\": {\"code\": \"GG\", \"name\": \"Guernsey\", \"parent\": 5, \"lft\": 281, \"rght\": 282, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 101, \"fields\": {\"code\": \"GN\", \"name\": \"Guinea\", \"parent\": 2, \"lft\": 47, \"rght\": 48, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 102, \"fields\": {\"code\": \"GW\", \"name\": \"Guinea-Bissau\", \"parent\": 2, \"lft\": 49, \"rght\": 50, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 103, \"fields\": {\"code\": \"GY\", \"name\": \"Guyana\", \"parent\": 8, \"lft\": 503, \"rght\": 504, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 104, \"fields\": {\"code\": \"HT\", \"name\": \"Haiti\", \"parent\": 6, \"lft\": 387, \"rght\": 388, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 105, \"fields\": {\"code\": \"HM\", \"name\": \"Heard Island and McDonald Islands\", \"parent\": 3, \"lft\": 127, \"rght\": 128, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 106, \"fields\": {\"code\": \"VA\", \"name\": \"Holy See (Vatican City State)\", \"parent\": 5, \"lft\": 283, \"rght\": 284, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 107, \"fields\": {\"code\": \"HN\", \"name\": \"Honduras\", \"parent\": 6, \"lft\": 389, \"rght\": 390, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 108, \"fields\": {\"code\": \"HK\", \"name\": \"Hong Kong\", \"parent\": 4, \"lft\": 161, \"rght\": 162, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 109, \"fields\": {\"code\": \"HU\", \"name\": \"Hungary\", \"parent\": 5, \"lft\": 285, \"rght\": 286, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 110, \"fields\": {\"code\": \"IS\", \"name\": \"Iceland\", \"parent\": 5, \"lft\": 287, \"rght\": 288, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 111, \"fields\": {\"code\": \"IN\", \"name\": \"India\", \"parent\": 4, \"lft\": 163, \"rght\": 164, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 112, \"fields\": {\"code\": \"ID\", \"name\": \"Indonesia\", \"parent\": 4, \"lft\": 165, \"rght\": 166, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 113, \"fields\": {\"code\": \"IR\", \"name\": \"Iran, Islamic Republic of\", \"parent\": 4, \"lft\": 167, \"rght\": 168, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 114, \"fields\": {\"code\": \"IQ\", \"name\": \"Iraq\", \"parent\": 4, \"lft\": 169, \"rght\": 170, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 115, \"fields\": {\"code\": \"IE\", \"name\": \"Ireland\", \"parent\": 5, \"lft\": 289, \"rght\": 290, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 116, \"fields\": {\"code\": \"IM\", \"name\": \"Isle of Man\", \"parent\": 5, \"lft\": 291, \"rght\": 292, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 117, \"fields\": {\"code\": \"IL\", \"name\": \"Israel\", \"parent\": 4, \"lft\": 171, \"rght\": 172, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 118, \"fields\": {\"code\": \"IT\", \"name\": \"Italy\", \"parent\": 5, \"lft\": 293, \"rght\": 294, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 119, \"fields\": {\"code\": \"JM\", \"name\": \"Jamaica\", \"parent\": 6, \"lft\": 391, \"rght\": 392, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 120, \"fields\": {\"code\": \"JP\", \"name\": \"Japan\", \"parent\": 4, \"lft\": 173, \"rght\": 174, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 121, \"fields\": {\"code\": \"JE\", \"name\": \"Jersey\", \"parent\": 5, \"lft\": 295, \"rght\": 296, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 122, \"fields\": {\"code\": \"JO\", \"name\": \"Jordan\", \"parent\": 4, \"lft\": 175, \"rght\": 176, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 123, \"fields\": {\"code\": \"KZ\", \"name\": \"Kazakhstan\", \"parent\": 4, \"lft\": 177, \"rght\": 178, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 124, \"fields\": {\"code\": \"KE\", \"name\": \"Kenya\", \"parent\": 2, \"lft\": 51, \"rght\": 52, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 125, \"fields\": {\"code\": \"KI\", \"name\": \"Kiribati\", \"parent\": 7, \"lft\": 445, \"rght\": 446, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 126, \"fields\": {\"code\": \"KP\", \"name\": \"Korea, Democratic People's Republic of\", \"parent\": 4, \"lft\": 179, \"rght\": 180, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 127, \"fields\": {\"code\": \"KR\", \"name\": \"Korea, Republic of\", \"parent\": 4, \"lft\": 181, \"rght\": 182, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 128, \"fields\": {\"code\": \"KW\", \"name\": \"Kuwait\", \"parent\": 4, \"lft\": 183, \"rght\": 184, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 129, \"fields\": {\"code\": \"KG\", \"name\": \"Kyrgyzstan\", \"parent\": 4, \"lft\": 185, \"rght\": 186, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 130, \"fields\": {\"code\": \"LA\", \"name\": \"Lao People's Democratic Republic\", \"parent\": 4, \"lft\": 187, \"rght\": 188, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 131, \"fields\": {\"code\": \"LV\", \"name\": \"Latvia\", \"parent\": 5, \"lft\": 297, \"rght\": 298, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 132, \"fields\": {\"code\": \"LB\", \"name\": \"Lebanon\", \"parent\": 4, \"lft\": 189, \"rght\": 190, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 133, \"fields\": {\"code\": \"LS\", \"name\": \"Lesotho\", \"parent\": 2, \"lft\": 53, \"rght\": 54, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 134, \"fields\": {\"code\": \"LR\", \"name\": \"Liberia\", \"parent\": 2, \"lft\": 55, \"rght\": 56, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 135, \"fields\": {\"code\": \"LY\", \"name\": \"Libya\", \"parent\": 2, \"lft\": 57, \"rght\": 58, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 136, \"fields\": {\"code\": \"LI\", \"name\": \"Liechtenstein\", \"parent\": 5, \"lft\": 299, \"rght\": 300, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 137, \"fields\": {\"code\": \"LT\", \"name\": \"Lithuania\", \"parent\": 5, \"lft\": 301, \"rght\": 302, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 138, \"fields\": {\"code\": \"LU\", \"name\": \"Luxembourg\", \"parent\": 5, \"lft\": 303, \"rght\": 304, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 139, \"fields\": {\"code\": \"MO\", \"name\": \"Macao\", \"parent\": 4, \"lft\": 191, \"rght\": 192, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 140, \"fields\": {\"code\": \"MK\", \"name\": \"Macedonia, Republic of\", \"parent\": 5, \"lft\": 305, \"rght\": 306, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 141, \"fields\": {\"code\": \"MG\", \"name\": \"Madagascar\", \"parent\": 2, \"lft\": 59, \"rght\": 60, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 142, \"fields\": {\"code\": \"MW\", \"name\": \"Malawi\", \"parent\": 2, \"lft\": 61, \"rght\": 62, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 143, \"fields\": {\"code\": \"MY\", \"name\": \"Malaysia\", \"parent\": 4, \"lft\": 193, \"rght\": 194, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 144, \"fields\": {\"code\": \"MV\", \"name\": \"Maldives\", \"parent\": 4, \"lft\": 195, \"rght\": 196, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 145, \"fields\": {\"code\": \"ML\", \"name\": \"Mali\", \"parent\": 2, \"lft\": 63, \"rght\": 64, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 146, \"fields\": {\"code\": \"MT\", \"name\": \"Malta\", \"parent\": 5, \"lft\": 307, \"rght\": 308, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 147, \"fields\": {\"code\": \"MH\", \"name\": \"Marshall Islands\", \"parent\": 7, \"lft\": 447, \"rght\": 448, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 148, \"fields\": {\"code\": \"MQ\", \"name\": \"Martinique\", \"parent\": 6, \"lft\": 393, \"rght\": 394, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 149, \"fields\": {\"code\": \"MR\", \"name\": \"Mauritania\", \"parent\": 2, \"lft\": 65, \"rght\": 66, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 150, \"fields\": {\"code\": \"MU\", \"name\": \"Mauritius\", \"parent\": 2, \"lft\": 67, \"rght\": 68, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 151, \"fields\": {\"code\": \"YT\", \"name\": \"Mayotte\", \"parent\": 2, \"lft\": 69, \"rght\": 70, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 152, \"fields\": {\"code\": \"MX\", \"name\": \"Mexico\", \"parent\": 6, \"lft\": 395, \"rght\": 396, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 153, \"fields\": {\"code\": \"FM\", \"name\": \"Micronesia, Federated States of\", \"parent\": 7, \"lft\": 449, \"rght\": 450, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 154, \"fields\": {\"code\": \"MD\", \"name\": \"Moldova, Republic of\", \"parent\": 5, \"lft\": 309, \"rght\": 310, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 155, \"fields\": {\"code\": \"MC\", \"name\": \"Monaco\", \"parent\": 5, \"lft\": 311, \"rght\": 312, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 156, \"fields\": {\"code\": \"MN\", \"name\": \"Mongolia\", \"parent\": 4, \"lft\": 197, \"rght\": 198, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 157, \"fields\": {\"code\": \"ME\", \"name\": \"Montenegro\", \"parent\": 5, \"lft\": 313, \"rght\": 314, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 158, \"fields\": {\"code\": \"MS\", \"name\": \"Montserrat\", \"parent\": 6, \"lft\": 397, \"rght\": 398, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 159, \"fields\": {\"code\": \"MA\", \"name\": \"Morocco\", \"parent\": 2, \"lft\": 71, \"rght\": 72, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 160, \"fields\": {\"code\": \"MZ\", \"name\": \"Mozambique\", \"parent\": 2, \"lft\": 73, \"rght\": 74, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 161, \"fields\": {\"code\": \"MM\", \"name\": \"Myanmar\", \"parent\": 4, \"lft\": 199, \"rght\": 200, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 162, \"fields\": {\"code\": \"NA\", \"name\": \"Namibia\", \"parent\": 2, \"lft\": 75, \"rght\": 76, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 163, \"fields\": {\"code\": \"NR\", \"name\": \"Nauru\", \"parent\": 7, \"lft\": 451, \"rght\": 452, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 164, \"fields\": {\"code\": \"NP\", \"name\": \"Nepal\", \"parent\": 4, \"lft\": 201, \"rght\": 202, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 165, \"fields\": {\"code\": \"NL\", \"name\": \"Netherlands\", \"parent\": 5, \"lft\": 315, \"rght\": 316, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 166, \"fields\": {\"code\": \"NC\", \"name\": \"New Caledonia\", \"parent\": 7, \"lft\": 453, \"rght\": 454, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 167, \"fields\": {\"code\": \"NZ\", \"name\": \"New Zealand\", \"parent\": 7, \"lft\": 455, \"rght\": 456, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 168, \"fields\": {\"code\": \"NI\", \"name\": \"Nicaragua\", \"parent\": 6, \"lft\": 399, \"rght\": 400, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 169, \"fields\": {\"code\": \"NE\", \"name\": \"Niger\", \"parent\": 2, \"lft\": 77, \"rght\": 78, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 170, \"fields\": {\"code\": \"NG\", \"name\": \"Nigeria\", \"parent\": 2, \"lft\": 79, \"rght\": 80, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 171, \"fields\": {\"code\": \"NU\", \"name\": \"Niue\", \"parent\": 7, \"lft\": 457, \"rght\": 458, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 172, \"fields\": {\"code\": \"NF\", \"name\": \"Norfolk Island\", \"parent\": 7, \"lft\": 459, \"rght\": 460, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 173, \"fields\": {\"code\": \"MP\", \"name\": \"Northern Mariana Islands\", \"parent\": 7, \"lft\": 461, \"rght\": 462, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 174, \"fields\": {\"code\": \"NO\", \"name\": \"Norway\", \"parent\": 5, \"lft\": 317, \"rght\": 318, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 175, \"fields\": {\"code\": \"OM\", \"name\": \"Oman\", \"parent\": 4, \"lft\": 203, \"rght\": 204, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 176, \"fields\": {\"code\": \"PK\", \"name\": \"Pakistan\", \"parent\": 4, \"lft\": 205, \"rght\": 206, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 177, \"fields\": {\"code\": \"PW\", \"name\": \"Palau\", \"parent\": 7, \"lft\": 463, \"rght\": 464, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 178, \"fields\": {\"code\": \"PS\", \"name\": \"Palestinian Territory, Occupied\", \"parent\": 4, \"lft\": 207, \"rght\": 208, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 179, \"fields\": {\"code\": \"PA\", \"name\": \"Panama\", \"parent\": 6, \"lft\": 401, \"rght\": 402, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 180, \"fields\": {\"code\": \"PG\", \"name\": \"Papua New Guinea\", \"parent\": 7, \"lft\": 465, \"rght\": 466, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 181, \"fields\": {\"code\": \"PY\", \"name\": \"Paraguay\", \"parent\": 8, \"lft\": 505, \"rght\": 506, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 182, \"fields\": {\"code\": \"PE\", \"name\": \"Peru\", \"parent\": 8, \"lft\": 507, \"rght\": 508, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 183, \"fields\": {\"code\": \"PH\", \"name\": \"Philippines\", \"parent\": 4, \"lft\": 209, \"rght\": 210, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 184, \"fields\": {\"code\": \"PN\", \"name\": \"Pitcairn\", \"parent\": 7, \"lft\": 467, \"rght\": 468, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 185, \"fields\": {\"code\": \"PL\", \"name\": \"Poland\", \"parent\": 5, \"lft\": 319, \"rght\": 320, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 186, \"fields\": {\"code\": \"PT\", \"name\": \"Portugal\", \"parent\": 5, \"lft\": 321, \"rght\": 322, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 187, \"fields\": {\"code\": \"PR\", \"name\": \"Puerto Rico\", \"parent\": 6, \"lft\": 403, \"rght\": 404, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 188, \"fields\": {\"code\": \"QA\", \"name\": \"Qatar\", \"parent\": 4, \"lft\": 211, \"rght\": 212, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 189, \"fields\": {\"code\": \"RE\", \"name\": \"Réunion\", \"parent\": 2, \"lft\": 81, \"rght\": 82, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 190, \"fields\": {\"code\": \"RO\", \"name\": \"Romania\", \"parent\": 5, \"lft\": 323, \"rght\": 324, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 191, \"fields\": {\"code\": \"RU\", \"name\": \"Russian Federation\", \"parent\": 4, \"lft\": 213, \"rght\": 214, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 192, \"fields\": {\"code\": \"RW\", \"name\": \"Rwanda\", \"parent\": 2, \"lft\": 83, \"rght\": 84, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 193, \"fields\": {\"code\": \"BL\", \"name\": \"Saint Barthélemy\", \"parent\": 6, \"lft\": 405, \"rght\": 406, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 194, \"fields\": {\"code\": \"SH\", \"name\": \"Saint Helena, Ascension and Tristan da Cunha\", \"parent\": 2, \"lft\": 85, \"rght\": 86, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 195, \"fields\": {\"code\": \"KN\", \"name\": \"Saint Kitts and Nevis\", \"parent\": 6, \"lft\": 407, \"rght\": 408, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 196, \"fields\": {\"code\": \"LC\", \"name\": \"Saint Lucia\", \"parent\": 6, \"lft\": 409, \"rght\": 410, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 197, \"fields\": {\"code\": \"MF\", \"name\": \"Saint Martin (French part)\", \"parent\": 6, \"lft\": 411, \"rght\": 412, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 198, \"fields\": {\"code\": \"PM\", \"name\": \"Saint Pierre and Miquelon\", \"parent\": 6, \"lft\": 413, \"rght\": 414, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 199, \"fields\": {\"code\": \"VC\", \"name\": \"Saint Vincent and the Grenadines\", \"parent\": 6, \"lft\": 415, \"rght\": 416, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 200, \"fields\": {\"code\": \"WS\", \"name\": \"Samoa\", \"parent\": 7, \"lft\": 469, \"rght\": 470, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 201, \"fields\": {\"code\": \"SM\", \"name\": \"San Marino\", \"parent\": 5, \"lft\": 325, \"rght\": 326, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 202, \"fields\": {\"code\": \"ST\", \"name\": \"Sao Tome and Principe\", \"parent\": 2, \"lft\": 87, \"rght\": 88, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 203, \"fields\": {\"code\": \"SA\", \"name\": \"Saudi Arabia\", \"parent\": 4, \"lft\": 215, \"rght\": 216, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 204, \"fields\": {\"code\": \"SN\", \"name\": \"Senegal\", \"parent\": 2, \"lft\": 89, \"rght\": 90, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 205, \"fields\": {\"code\": \"RS\", \"name\": \"Serbia\", \"parent\": 5, \"lft\": 327, \"rght\": 328, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 206, \"fields\": {\"code\": \"SC\", \"name\": \"Seychelles\", \"parent\": 2, \"lft\": 91, \"rght\": 92, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 207, \"fields\": {\"code\": \"SL\", \"name\": \"Sierra Leone\", \"parent\": 2, \"lft\": 93, \"rght\": 94, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 208, \"fields\": {\"code\": \"SG\", \"name\": \"Singapore\", \"parent\": 4, \"lft\": 217, \"rght\": 218, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 209, \"fields\": {\"code\": \"SX\", \"name\": \"Sint Maarten (Dutch part)\", \"parent\": 6, \"lft\": 417, \"rght\": 418, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 210, \"fields\": {\"code\": \"SK\", \"name\": \"Slovakia\", \"parent\": 5, \"lft\": 329, \"rght\": 330, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 211, \"fields\": {\"code\": \"SI\", \"name\": \"Slovenia\", \"parent\": 5, \"lft\": 331, \"rght\": 332, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 212, \"fields\": {\"code\": \"SB\", \"name\": \"Solomon Islands\", \"parent\": 7, \"lft\": 471, \"rght\": 472, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 213, \"fields\": {\"code\": \"SO\", \"name\": \"Somalia\", \"parent\": 2, \"lft\": 95, \"rght\": 96, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 214, \"fields\": {\"code\": \"ZA\", \"name\": \"South Africa\", \"parent\": 2, \"lft\": 97, \"rght\": 98, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 215, \"fields\": {\"code\": \"GS\", \"name\": \"South Georgia and the South Sandwich Islands\", \"parent\": 3, \"lft\": 129, \"rght\": 130, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 216, \"fields\": {\"code\": \"ES\", \"name\": \"Spain\", \"parent\": 5, \"lft\": 333, \"rght\": 334, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 217, \"fields\": {\"code\": \"LK\", \"name\": \"Sri Lanka\", \"parent\": 4, \"lft\": 219, \"rght\": 220, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 218, \"fields\": {\"code\": \"SD\", \"name\": \"Sudan\", \"parent\": 2, \"lft\": 99, \"rght\": 100, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 219, \"fields\": {\"code\": \"SR\", \"name\": \"Suriname\", \"parent\": 8, \"lft\": 509, \"rght\": 510, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 220, \"fields\": {\"code\": \"SS\", \"name\": \"South Sudan\", \"parent\": 2, \"lft\": 101, \"rght\": 102, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 221, \"fields\": {\"code\": \"SJ\", \"name\": \"Svalbard and Jan Mayen\", \"parent\": 5, \"lft\": 335, \"rght\": 336, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 222, \"fields\": {\"code\": \"SZ\", \"name\": \"Swaziland\", \"parent\": 2, \"lft\": 103, \"rght\": 104, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 223, \"fields\": {\"code\": \"SE\", \"name\": \"Sweden\", \"parent\": 5, \"lft\": 337, \"rght\": 338, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 224, \"fields\": {\"code\": \"CH\", \"name\": \"Switzerland\", \"parent\": 5, \"lft\": 339, \"rght\": 340, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 225, \"fields\": {\"code\": \"SY\", \"name\": \"Syrian Arab Republic\", \"parent\": 4, \"lft\": 221, \"rght\": 222, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 226, \"fields\": {\"code\": \"TW\", \"name\": \"Taiwan, Province of China\", \"parent\": 4, \"lft\": 223, \"rght\": 224, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 227, \"fields\": {\"code\": \"TJ\", \"name\": \"Tajikistan\", \"parent\": 4, \"lft\": 225, \"rght\": 226, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 228, \"fields\": {\"code\": \"TZ\", \"name\": \"Tanzania, United Republic of\", \"parent\": 2, \"lft\": 105, \"rght\": 106, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 229, \"fields\": {\"code\": \"TH\", \"name\": \"Thailand\", \"parent\": 4, \"lft\": 227, \"rght\": 228, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 230, \"fields\": {\"code\": \"TL\", \"name\": \"Timor-Leste\", \"parent\": 4, \"lft\": 229, \"rght\": 230, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 231, \"fields\": {\"code\": \"TG\", \"name\": \"Togo\", \"parent\": 2, \"lft\": 107, \"rght\": 108, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 232, \"fields\": {\"code\": \"TK\", \"name\": \"Tokelau\", \"parent\": 7, \"lft\": 473, \"rght\": 474, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 233, \"fields\": {\"code\": \"TO\", \"name\": \"Tonga\", \"parent\": 7, \"lft\": 475, \"rght\": 476, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 234, \"fields\": {\"code\": \"TT\", \"name\": \"Trinidad and Tobago\", \"parent\": 6, \"lft\": 419, \"rght\": 420, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 235, \"fields\": {\"code\": \"TN\", \"name\": \"Tunisia\", \"parent\": 2, \"lft\": 109, \"rght\": 110, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 236, \"fields\": {\"code\": \"TR\", \"name\": \"Turkey\", \"parent\": 4, \"lft\": 231, \"rght\": 232, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 237, \"fields\": {\"code\": \"TM\", \"name\": \"Turkmenistan\", \"parent\": 4, \"lft\": 233, \"rght\": 234, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 238, \"fields\": {\"code\": \"TC\", \"name\": \"Turks and Caicos Islands\", \"parent\": 6, \"lft\": 421, \"rght\": 422, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 239, \"fields\": {\"code\": \"TV\", \"name\": \"Tuvalu\", \"parent\": 7, \"lft\": 477, \"rght\": 478, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 240, \"fields\": {\"code\": \"UG\", \"name\": \"Uganda\", \"parent\": 2, \"lft\": 111, \"rght\": 112, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 241, \"fields\": {\"code\": \"UA\", \"name\": \"Ukraine\", \"parent\": 5, \"lft\": 341, \"rght\": 342, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 242, \"fields\": {\"code\": \"AE\", \"name\": \"United Arab Emirates\", \"parent\": 4, \"lft\": 235, \"rght\": 236, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 243, \"fields\": {\"code\": \"GB\", \"name\": \"United Kingdom\", \"parent\": 5, \"lft\": 343, \"rght\": 344, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 244, \"fields\": {\"code\": \"US\", \"name\": \"United States\", \"parent\": 6, \"lft\": 423, \"rght\": 424, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 245, \"fields\": {\"code\": \"UM\", \"name\": \"United States Minor Outlying Islands\", \"parent\": 6, \"lft\": 425, \"rght\": 426, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 246, \"fields\": {\"code\": \"UY\", \"name\": \"Uruguay\", \"parent\": 8, \"lft\": 511, \"rght\": 512, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 247, \"fields\": {\"code\": \"UZ\", \"name\": \"Uzbekistan\", \"parent\": 4, \"lft\": 237, \"rght\": 238, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 248, \"fields\": {\"code\": \"VU\", \"name\": \"Vanuatu\", \"parent\": 7, \"lft\": 479, \"rght\": 480, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 249, \"fields\": {\"code\": \"VE\", \"name\": \"Venezuela, Bolivarian Republic of\", \"parent\": 8, \"lft\": 513, \"rght\": 514, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 250, \"fields\": {\"code\": \"VN\", \"name\": \"Viet Nam\", \"parent\": 4, \"lft\": 239, \"rght\": 240, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 251, \"fields\": {\"code\": \"VG\", \"name\": \"Virgin Islands, British\", \"parent\": 6, \"lft\": 427, \"rght\": 428, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 252, \"fields\": {\"code\": \"VI\", \"name\": \"Virgin Islands, U.S.\", \"parent\": 6, \"lft\": 429, \"rght\": 430, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 253, \"fields\": {\"code\": \"WF\", \"name\": \"Wallis and Futuna\", \"parent\": 7, \"lft\": 481, \"rght\": 482, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 254, \"fields\": {\"code\": \"EH\", \"name\": \"Western Sahara\", \"parent\": 2, \"lft\": 113, \"rght\": 114, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 255, \"fields\": {\"code\": \"YE\", \"name\": \"Yemen\", \"parent\": 4, \"lft\": 241, \"rght\": 242, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 256, \"fields\": {\"code\": \"ZM\", \"name\": \"Zambia\", \"parent\": 2, \"lft\": 115, \"rght\": 116, \"tree_id\": 1, \"level\": 2}}, {\"model\": \"django_mptt_example.country\", \"pk\": 257, \"fields\": {\"code\": \"ZW\", \"name\": \"Zimbabwe\", \"parent\": 2, \"lft\": 117, \"rght\": 118, \"tree_id\": 1, \"level\": 2}}]"
  },
  {
    "path": "example_project/django_mptt_example/migrations/0001_initial.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.10 on 2016-10-22 06:22\nfrom __future__ import unicode_literals\n\nfrom django.db import migrations, models\nimport django.db.models.deletion\nimport mptt.fields\n\n\nclass Migration(migrations.Migration):\n\n    initial = True\n\n    dependencies = []\n\n    operations = [\n        migrations.CreateModel(\n            name=\"Country\",\n            fields=[\n                (\n                    \"id\",\n                    models.AutoField(\n                        auto_created=True,\n                        primary_key=True,\n                        serialize=False,\n                        verbose_name=\"ID\",\n                    ),\n                ),\n                (\"code\", models.CharField(blank=True, max_length=2, null=True)),\n                (\"name\", models.CharField(blank=True, max_length=50, null=True)),\n                (\"lft\", models.PositiveIntegerField(db_index=True, editable=False)),\n                (\"rght\", models.PositiveIntegerField(db_index=True, editable=False)),\n                (\"tree_id\", models.PositiveIntegerField(db_index=True, editable=False)),\n                (\"level\", models.PositiveIntegerField(db_index=True, editable=False)),\n                (\n                    \"parent\",\n                    mptt.fields.TreeForeignKey(\n                        blank=True,\n                        null=True,\n                        on_delete=django.db.models.deletion.CASCADE,\n                        related_name=\"children\",\n                        to=\"django_mptt_example.Country\",\n                    ),\n                ),\n            ],\n            options={\n                \"verbose_name_plural\": \"countries\",\n            },\n        ),\n    ]\n"
  },
  {
    "path": "example_project/django_mptt_example/migrations/0002_alter_country_level_alter_country_lft_and_more.py",
    "content": "# Generated by Django 4.0 on 2021-04-25 02:52\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Migration):\n\n    dependencies = [\n        (\"django_mptt_example\", \"0001_initial\"),\n    ]\n\n    operations = [\n        migrations.AlterField(\n            model_name=\"country\",\n            name=\"level\",\n            field=models.PositiveIntegerField(editable=False),\n        ),\n        migrations.AlterField(\n            model_name=\"country\",\n            name=\"lft\",\n            field=models.PositiveIntegerField(editable=False),\n        ),\n        migrations.AlterField(\n            model_name=\"country\",\n            name=\"rght\",\n            field=models.PositiveIntegerField(editable=False),\n        ),\n    ]\n"
  },
  {
    "path": "example_project/django_mptt_example/migrations/__init__.py",
    "content": ""
  },
  {
    "path": "example_project/django_mptt_example/models.py",
    "content": "from django.db import models\nfrom django.utils.html import format_html\n\nfrom mptt.models import TreeForeignKey, MPTTModel\n\n\nclass Country(MPTTModel):\n    class Meta:\n        verbose_name_plural = \"countries\"\n        app_label = \"django_mptt_example\"\n\n    code = models.CharField(max_length=2, blank=True, null=True)\n    name = models.CharField(max_length=50, blank=True, null=True)\n    parent = TreeForeignKey(\n        \"self\", null=True, blank=True, related_name=\"children\", on_delete=models.CASCADE\n    )\n\n    def __str__(self):\n        return self.name or self.code or \"\"\n\n    # Return the code if there is one, otherwise the name.\n    @property\n    def code_or_name(self):\n        return self.code or self.name\n\n    # Return the code and the name. Contains html.\n    # * Return only the name for continents.\n    @property\n    def html_code_and_name(self):\n        if self.code:\n            return format_html(\"<strong>{}</strong> {}\", self.code, self.name)\n        else:\n            return format_html(\"<strong>{}</strong>\", self.name)\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/__init__.py",
    "content": ""
  },
  {
    "path": "example_project/django_mptt_example/tests/base_playwright_testcase.py",
    "content": "from django.conf import settings\nfrom django.test import LiveServerTestCase\nfrom .playwright_page import PlaywrightPage\n\n\nclass BasePlaywrightTestCase(LiveServerTestCase):\n    def setUp(self):\n        super().setUp()\n\n        self.page = PlaywrightPage(self.live_server_url)\n        self.setup_page()\n\n    def tearDown(self):\n        try:\n            if getattr(settings, \"DJANGO_MPTT_ADMIN_COVERAGE_JS\", False):\n                self.page.save_coverage()\n\n            self.page.close()\n        finally:\n            super().tearDown()\n\n    def setup_page(self):\n        self.page.login(\"admin\", \"password\")\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/base_view_testcase.py",
    "content": "from django_webtest import WebTest\nfrom django.contrib.auth.models import User\n\n\nclass BaseViewTestCase(WebTest):\n    fixtures = [\"countries.json\"]\n\n    def create_test_user(self):\n        User.objects.create_superuser(\"admin\", \"admin@admin.com\", \"password\")\n\n    def setUp(self):\n        super().setUp()\n\n        self.create_test_user()\n        self.login()\n\n    def login(self):\n        login_page = self.app.get(\"/login/\")\n        form = login_page.form\n\n        form[\"username\"] = \"admin\"\n        form[\"password\"] = \"password\"\n\n        form.submit()\n\n        response = self.app.get(\"/\")\n        self.assertEqual(response.context[\"user\"].username, \"admin\")\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/playwright_page.py",
    "content": "from uuid import uuid4\nfrom playwright.sync_api import ElementHandle, sync_playwright\nfrom .utils import wait_until, write_json\n\n\nclass PlaywrightPage:\n    def __init__(self, live_server_url):\n        self.live_server_url = live_server_url\n\n        self.playwright = sync_playwright().start()\n        self.browser = self.playwright.chromium.launch(headless=True)\n        self.page = self.browser.new_page()\n\n    def abort_requests(self):\n        self.page.route(\"**\", lambda route, _request: route.abort())\n\n    def reset_abort_requests(self):\n        self.page.unroute(\"**\")\n\n    def add_node(self, parent_title):\n        self.find_edit_link(parent_title, \"(add)\").click()\n        self.wait_for_text(\"Add country\")\n\n    def close(self):\n        self.browser.close()\n        self.playwright.stop()\n\n    def close_node(self, title):\n        self.toggle_node(title)\n\n    def drag_and_drop(self, from_title, to_title):\n        from_rect = self.find_title_element(from_title).bounding_box()\n        to_rect = self.find_title_element(to_title).bounding_box()\n\n        self.page.mouse.move(\n            from_rect[\"x\"] + from_rect[\"width\"] / 2,\n            from_rect[\"y\"] + from_rect[\"height\"] / 2,\n        )\n        self.page.mouse.down()\n        self.page.wait_for_timeout(200)\n        self.page.mouse.move(\n            to_rect[\"x\"] + to_rect[\"width\"] / 2, to_rect[\"y\"] + to_rect[\"height\"] / 2\n        )\n        self.page.mouse.up()\n\n    def edit_node(self, title):\n        self.find_edit_link(title, \"(edit)\").click()\n        self.page.wait_for_selector('text=\"Change country\"')\n\n    def find_edit_link(self, node_title, link_title):\n        links = [\n            e\n            for e in self.find_node_element(node_title).query_selector_all(\"a.edit\")\n            if e.text_content() == link_title\n        ]\n        return links[0]\n\n    def find_input(self, name):\n        return self.page.query_selector(f\"input[name='{name}']\")\n\n    def find_link(self, label):\n        return self.page.query_selector(f'css=a >> text=\"{label}\"')\n\n    def find_node_element(self, title) -> ElementHandle:\n        node_element = self.find_title_element(title).evaluate_handle(\n            \"\"\"\n            function(el) {\n                const li = el.closest(\"li\");\n    \n                if (!li) {\n                    throw Error(\"Node element not found\");\n                }\n    \n                return li;\n            }\n            \"\"\"\n        )\n        assert node_element\n        return node_element\n\n    def find_title_element(self, title) -> ElementHandle:\n        element = self.page.query_selector(f'css=.jqtree-title >> text=\"{title}\"')\n        assert element\n        return element\n\n    def find_toggler(self, node_element: ElementHandle) -> ElementHandle:\n        toggler = node_element.query_selector(\".jqtree-toggler\")\n        assert toggler\n        return toggler\n\n    def grid_view(self):\n        self.find_link(\"Grid view\").click()\n        self.page.wait_for_selector(\"#result_list\")\n\n    def login(self, username, password):\n        page = self.page\n\n        page.goto(self.live_server_url + \"/login/\")\n        page.wait_for_selector(\"text=Username:\")\n\n        page.fill(\"#id_username\", username)\n        page.fill(\"#id_password\", password)\n        page.click(\"input[type=submit]\")\n        page.wait_for_load_state(\"load\")\n        page.wait_for_selector(\"text=Site administration\")\n\n    def node_titles(self):\n        return [e.text_content() for e in self.page.query_selector_all(\".jqtree-title\")]\n\n    def open_node(self, title):\n        self.toggle_node(title)\n        node_element = self.find_node_element(title)\n\n        if \"jqtree-loading\" in node_element.get_attribute(\"class\"):\n            wait_until(\n                lambda: \"jqtree-loading\" not in node_element.get_attribute(\"class\")\n            )\n\n    def save_coverage(self):\n        coverage = self.page.evaluate_handle(\n            \"\"\"\n            function() {\n                return window.__coverage__;\n            }\n            \"\"\"\n        ).json_value()\n\n        filename = uuid4().hex\n        write_json(f\"js_coverage/{filename}.json\", coverage)\n\n    def save_form(self):\n        self.page.query_selector(\"input[value='Save']\").click()\n        self.page.wait_for_selector(\"li.success\")\n\n    def select_node(self, title):\n        self.find_title_element(title).click()\n\n    def selected_node(self):\n        return self.page.query_selector(\n            \".jqtree-selected > .jqtree-element > .jqtree-title\"\n        )\n\n    def toggle_node(self, title):\n        node_element = self.find_node_element(title)\n        toggler = self.find_toggler(node_element)\n        toggler.click()\n\n    def tree_view(self):\n        self.find_link(\"Tree view\").click()\n        self.page.wait_for_selector(\"css=#tree >> text=Oceania\")\n\n    def visit_countries_page(self, expected_text=\"Select country to change\"):\n        page = self.page\n        page.goto(self.live_server_url + \"/django_mptt_example/country/\")\n        page.wait_for_selector(f\"text={expected_text}\")\n        page.wait_for_selector(\"css=#tree >> text=Oceania\")\n\n    def visit_country_codes_page(self, expected_text=\"Select country code to change\"):\n        page = self.page\n        page.goto(self.live_server_url + \"/django_mptt_example/countrycode/\")\n        page.wait_for_selector(f\"text={expected_text}\")\n        page.wait_for_selector(\"css=#tree >> text=Oceania\")\n\n    def visit_country_codes_and_names_page(\n        self, expected_text=\"Select country code and name to change\"\n    ):\n        page = self.page\n        page.goto(self.live_server_url + \"/django_mptt_example/countrycodeandname/\")\n        page.wait_for_selector(f\"text={expected_text}\")\n        page.wait_for_selector(\"css=#tree >> text=Oceania\")\n\n    def wait_for_node(self, title):\n        self.page.wait_for_selector(f'css=#tree .jqtree-title >> text=\"{title}\"')\n\n    def wait_for_text(self, text):\n        self.page.wait_for_selector(f'text=\"{text}\"')\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/test_playwright.py",
    "content": "from django.test import override_settings\nfrom django.contrib.auth.models import Permission, User\n\nfrom ..models import Country\nfrom .base_playwright_testcase import BasePlaywrightTestCase\n\n\n@override_settings(DJANGO_TESTING=True)\nclass PlaywrightTestCase(BasePlaywrightTestCase):\n    fixtures = [\"countries.json\"]\n\n    def setUp(self):\n        User.objects.create_superuser(\"admin\", \"admin@admin.com\", \"password\")\n        super().setUp()\n        self.page.visit_countries_page()\n\n    def test_display_tree(self):\n        page = self.page\n\n        page.find_title_element(\"Oceania\")\n\n        self.assertEqual(\n            page.node_titles(),\n            [\n                \"root\",\n                \"Africa\",\n                \"Antarctica\",\n                \"Asia\",\n                \"Europe\",\n                \"North America\",\n                \"Oceania\",\n                \"South America\",\n            ],\n        )\n\n        self.assertEqual(self.page.page.get_by_text(\"(add)\").count(), 8)\n\n    def test_select_node(self):\n        page = self.page\n\n        page.select_node(\"Asia\")\n        self.assertEqual(page.selected_node().text_content(), \"Asia\")\n        self.assertEqual(\n            page.find_edit_link(\"Asia\", \"(edit)\").get_attribute(\"tabindex\"), \"0\"\n        )\n\n        page.select_node(\"Europe\")\n        self.assertEqual(page.selected_node().text_content(), \"Europe\")\n        self.assertEqual(\n            page.find_edit_link(\"Asia\", \"(edit)\").get_attribute(\"tabindex\"), \"-1\"\n        )\n\n    def test_open_node(self):\n        page = self.page\n\n        page.open_node(\"Oceania\")\n        page.find_title_element(\"Tuvalu\")\n\n    def test_grid_view(self):\n        page = self.page\n\n        page.grid_view()\n        page.tree_view()\n\n    def test_save_state(self):\n        page = self.page\n\n        page.open_node(\"Oceania\")\n        page.select_node(\"Tuvalu\")\n\n        page.grid_view()\n        page.tree_view()\n\n        page.wait_for_node(\"Tuvalu\")\n        self.assertEqual(page.selected_node().text_content(), \"Tuvalu\")\n\n    def test_edit(self):\n        page = self.page\n\n        page.edit_node(\"Oceania\")\n        name_input = page.find_input(\"name\")\n        self.assertEqual(name_input.get_attribute(\"value\"), \"Oceania\")\n\n        name_input.fill(\"**Oceania**\")\n        page.save_form()\n\n        page.wait_for_node(\"**Oceania**\")\n        page.find_node_element(\"**Oceania**\")\n\n    def test_add(self):\n        page = self.page\n\n        page.add_node(\"Oceania\")\n\n        page.find_input(\"code\").fill(\"TST\")\n        page.find_input(\"name\").fill(\"**Test**\")\n        page.save_form()\n\n        page.wait_for_node(\"Oceania\")\n        page.open_node(\"Oceania\")\n\n        page.wait_for_node(\"**Test**\")\n        page.find_node_element(\"**Test**\")\n\n    def test_move_node(self):\n        page = self.page\n\n        page.open_node(\"Asia\")\n        page.close_node(\"Asia\")\n\n        with page.page.expect_response(\"**/move/\"):\n            page.drag_and_drop(\"Africa\", \"Asia\")\n\n        self.assertEqual(\n            page.node_titles()[:5],\n            [\n                \"root\",\n                \"Antarctica\",\n                \"Asia\",\n                \"Africa\",\n                \"Afghanistan\",\n            ],\n        )\n\n    def test_move_node_error(self):\n        page = self.page\n\n        page.open_node(\"Asia\")\n        page.close_node(\"Asia\")\n\n        page.abort_requests()\n\n        page.drag_and_drop(\"Africa\", \"Asia\")\n        page.wait_for_text(\"move failed\")\n\n    def test_load_error(self):\n        page = self.page\n        page.abort_requests()\n\n        page.toggle_node(\"Asia\")\n        page.wait_for_text(\"Error while loading the data from the server\")\n\n\n# Test the CountryCodeAdmin\n# * Test the item_label_field_name feature\n@override_settings(DJANGO_TESTING=True)\nclass PlaywrightCountryCodeAdminTestCase(BasePlaywrightTestCase):\n    fixtures = [\"countries.json\"]\n\n    def setUp(self):\n        User.objects.create_superuser(\"admin\", \"admin@admin.com\", \"password\")\n        super().setUp()\n        self.page.visit_country_codes_page()\n\n    def test_display_tree(self):\n        page = self.page\n\n        page.find_title_element(\"Oceania\")\n        page.open_node(\"Oceania\")\n\n        page.find_title_element(\"AU\")\n\n\n# Test the CountryCodeAdmin\n# * Test the item_label_field_name feature with html\n@override_settings(DJANGO_TESTING=True)\nclass PlaywrightCountryCodeAndNameAdminTestCase(BasePlaywrightTestCase):\n    fixtures = [\"countries.json\"]\n\n    def setUp(self):\n        User.objects.create_superuser(\"admin\", \"admin@admin.com\", \"password\")\n        super().setUp()\n        self.page.visit_country_codes_and_names_page()\n\n    def test_display_tree(self):\n        page = self.page\n\n        page.find_title_element(\"Oceania\")\n        page.open_node(\"Oceania\")\n\n        element = self.page.page.query_selector('css=strong >> text=\"AU\"')\n        assert element\n\n\n@override_settings(DJANGO_TESTING=True)\nclass PlaywrightReadonlyTestCase(BasePlaywrightTestCase):\n    fixtures = [\"countries.json\"]\n\n    def setUp(self):\n        user = User.objects.create_user(\n            \"admin\", \"admin@admin.com\", \"password\", is_staff=True\n        )\n\n        user.user_permissions.add(Permission.objects.get(codename=\"view_country\"))\n        user.save()\n\n        super().setUp()\n        self.page.visit_countries_page(expected_text=\"Select country to view\")\n\n    def test_display_tree(self):\n        page = self.page\n\n        page.find_edit_link(\"Asia\", \"(view)\")\n        self.assertEqual(self.page.page.get_by_text(\"(add)\").count(), 0)\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/test_util.py",
    "content": "from uuid import UUID\nfrom django.test import TestCase\n\nfrom django_mptt_admin.util import (\n    get_tree_queryset,\n    get_tree_from_queryset,\n    serialize_id,\n)\n\nfrom ..models import Country\n\n\nclass GetQuerySetTestCase(TestCase):\n    fixtures = [\"countries.json\"]\n\n    def test_default(self):\n        qs = get_tree_queryset(Country)\n        self.assertEqual(len(qs), 257)\n        self.assertEqual(qs[0].name, \"root\")\n\n    def test_subtree(self):\n        qs = get_tree_queryset(Country, node_id=Country.objects.get(name=\"Europe\").id)\n        self.assertEqual(len(qs), 50)\n        self.assertEqual(qs[0].name, \"Åland Islands\")\n\n    def test_max_level_1(self):\n        qs = get_tree_queryset(Country, max_level=1)\n        self.assertEqual(len(qs), 8)\n        self.assertEqual(qs[0].name, \"root\")\n\n    def test_max_level_true(self):\n        qs = get_tree_queryset(Country, max_level=True)\n        self.assertEqual(len(qs), 8)\n\n    def test_exclude_root(self):\n        qs = get_tree_queryset(Country, include_root=False)\n        self.assertEqual(len(qs), 256)\n        self.assertEqual(qs[0].name, \"Africa\")\n\n\nclass GetTreeFromQuerySetTestCase(TestCase):\n    fixtures = [\"countries.json\"]\n\n    def test_default(self):\n        tree = get_tree_from_queryset(get_tree_queryset(Country))\n\n        root = tree[0]\n        self.assertEqual(root[\"name\"], \"root\")\n\n        continents = root[\"children\"]\n        self.assertEqual(len(continents), 7)\n        self.assertEqual(continents[0][\"name\"], \"Africa\")\n\n        african_countries = continents[0][\"children\"]\n        self.assertEqual(african_countries[0][\"name\"], \"Algeria\")\n\n    def test_format_label(self):\n        tree = get_tree_from_queryset(\n            get_tree_queryset(Country), item_label_field_name=\"code\"\n        )\n        root = tree[0]\n        continents = root[\"children\"]\n        african_countries = continents[0][\"children\"]\n        self.assertEqual(african_countries[0][\"name\"], \"DZ\")\n\n\nclass SerializeIdTestCase(TestCase):\n    testcases = (\n        (10, 10),\n        (\"10\", \"10\"),\n        (\n            UUID(\"7b6dd6ba55fb400ca0f59cde381c987f\"),\n            \"7b6dd6ba-55fb-400c-a0f5-9cde381c987f\",\n        ),\n    )\n\n    def test(self):\n        for [value, expected] in self.testcases:\n            self.assertEqual(serialize_id(value), expected)\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/test_views.py",
    "content": "from django.contrib.admin.options import IS_POPUP_VAR\nfrom django.contrib.auth.models import User\nimport django\n\nfrom ..models import Country\nfrom .base_view_testcase import BaseViewTestCase\nfrom .utils import get_continents\n\n\nclass MoveTestCase(BaseViewTestCase):\n    def test_move_inside(self):\n        bouvet_island = Country.objects.get(code=\"BV\")\n        oceania = Country.objects.get(name=\"Oceania\")\n\n        self.assertEqual(bouvet_island.parent.name, \"Antarctica\")\n\n        # - move Bouvet Island under Oceania\n        self.move(bouvet_island.id, oceania.id, \"inside\")\n\n        bouvet_island = Country.objects.get(code=\"BV\")\n        self.assertEqual(bouvet_island.parent.name, \"Oceania\")\n\n    def test_move_before(self):\n        self.assertEqual(\n            get_continents(),\n            \"Africa,Antarctica,Asia,Europe,North America,Oceania,South America\",\n        )\n\n        self.move(\n            Country.objects.get(name=\"Antarctica\", level=1).id,\n            Country.objects.get(name=\"Africa\").id,\n            \"before\",\n        )\n\n        self.assertEqual(\n            get_continents(),\n            \"Antarctica,Africa,Asia,Europe,North America,Oceania,South America\",\n        )\n\n    def test_move_after(self):\n        self.move(\n            Country.objects.get(name=\"Antarctica\", level=1).id,\n            Country.objects.get(name=\"Europe\").id,\n            \"after\",\n        )\n        self.assertEqual(\n            get_continents(),\n            \"Africa,Asia,Europe,Antarctica,North America,Oceania,South America\",\n        )\n\n    def test_move_to_unknown_position(self):\n        self.assertRaisesMessage(\n            Exception,\n            \"Unknown position\",\n            lambda: self.move(\n                Country.objects.get(name=\"Antarctica\", level=1).id,\n                Country.objects.get(name=\"Europe\").id,\n                \"unknown\",\n            ),\n        )\n\n    def move(self, source_id, target_id, position):\n        countries_page = self.app.get(\"/django_mptt_example/country/\")\n        csrf_token = countries_page.forms[\"changelist-form\"][\n            \"csrfmiddlewaretoken\"\n        ].value\n\n        response = self.app.post(\n            \"/django_mptt_example/country/{0:d}/move/\".format(source_id),\n            params=dict(\n                csrfmiddlewaretoken=csrf_token,\n                target_id=target_id,\n                position=position,\n            ),\n        )\n        self.assertEqual(response.json, dict(success=True))\n\n\nclass PopupTestCase(BaseViewTestCase):\n    def test_return_grid_view(self):\n        grid_page = self.app.get(\n            \"/django_mptt_example/country/?{0!s}=true\".format(IS_POPUP_VAR)\n        )\n\n        first_row = grid_page.pyquery(\"#result_list tbody tr\").eq(0)\n        self.assertEqual(first_row.find(\"td\").eq(0).text(), \"Afghanistan\")\n\n\nclass PermissionsTestCase(BaseViewTestCase):\n    def create_test_user(self):\n        User.objects.create_user(\"admin\", \"admin@admin.nl\", \"password\", is_staff=True)\n\n    def test_no_superuser(self):\n        self.app.get(\"/django_mptt_example/country/\", status=403)\n\n\nclass FilterTestCase(BaseViewTestCase):\n    def test_without_filter(self):\n        countries_page = self.app.get(\"/django_mptt_example/country/\")\n\n        self.assertEqual(\n            countries_page.pyquery(\"#changelist-filter li a\").text(),\n            \"All Africa Antarctica Asia Europe North America Oceania South America\",\n        )\n\n    def test_filter(self):\n        countries_page = self.app.get(\"/django_mptt_example/country/?continent=Europe\")\n\n        tree_div = countries_page.pyquery(\"#tree\")\n        self.assertEqual(\n            tree_div.attr(\"data-url\"),\n            \"/django_mptt_example/country/tree_json/?continent=Europe\",\n        )\n\n        self.assertEqual(\n            tree_div.attr(\"data-insert_at_url\"),\n            \"/django_mptt_example/country/add/?_changelist_filters=continent%3DEurope\",\n        )\n\n    def test_filter_and_selected_node(self):\n        json_data = self.app.get(\n            \"/django_mptt_example/country/tree_json/?continent=Europe&selected_node=2\"\n        ).json\n\n        self.assertEqual(len(json_data), 1)\n        root = json_data[0]\n        self.assertEqual(root[\"name\"], \"Europe\")\n        self.assertEqual(len(root[\"children\"]), 50)\n\n        country_node = root[\"children\"][0]\n\n        expected_changelist_filters = (\n            \"continent%3D%255B%2527Europe%2527%255D\"\n            if django.VERSION >= (5, 0)\n            else \"continent%3DEurope\"\n        )\n        node_id = country_node[\"id\"]\n\n        self.assertEqual(\n            country_node[\"url\"],\n            f\"/django_mptt_example/country/{node_id}/change/?_changelist_filters={expected_changelist_filters}\",\n        )\n\n    def test_urls(self):\n        countries_page = self.app.get(\"/django_mptt_example/country/?continent=Europe\")\n\n        object_tool_buttons = countries_page.pyquery(\".object-tools a\")\n        self.assertEqual(len(object_tool_buttons), 2)\n\n        self.assertEqual(\n            object_tool_buttons.eq(0).attr(\"href\"),\n            \"/django_mptt_example/country/add/?_changelist_filters=continent%3DEurope\",\n        )\n        self.assertEqual(\n            object_tool_buttons.eq(1).attr(\"href\"),\n            \"/django_mptt_example/country/grid/?continent=Europe\",\n        )\n\n    def test_grid_view(self):\n        grid_page = self.app.get(\"/django_mptt_example/country/grid/?continent=Europe\")\n\n        object_tool_buttons = grid_page.pyquery(\".object-tools a\")\n        self.assertEqual(len(object_tool_buttons), 2)\n\n        self.assertEqual(\n            object_tool_buttons.eq(0).attr(\"href\"),\n            \"/django_mptt_example/country/add/?_changelist_filters=continent%3DEurope\",\n        )\n        self.assertEqual(\n            object_tool_buttons.eq(1).attr(\"href\"),\n            \"/django_mptt_example/country/?continent=Europe\",\n        )\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/utils.py",
    "content": "from json import dumps\nfrom pathlib import Path\nfrom time import sleep\n\nfrom ..models import Country\n\n\ndef remove_directory(string):  # pragma: no cover\n    path = Path(string)\n\n    if not path.exists():\n        return\n\n    for file in path.iterdir():\n        file.unlink()\n\n    path.rmdir()\n\n\ndef write_json(path, data):\n    json = dumps(data)\n\n    Path(path).write_text(json)\n\n\ndef get_continents():\n    return \",\".join(c.name for c in Country.objects.filter(level=1).order_by(\"lft\"))\n\n\ndef wait_until(fn):  # pragma: no cover\n    for i in range(100):\n        if fn():\n            return\n        sleep(0.1)\n\n    assert False\n"
  },
  {
    "path": "example_project/example_project/__init__.py",
    "content": ""
  },
  {
    "path": "example_project/example_project/settings.py",
    "content": "import sys\nimport os\n\nfrom pathlib import Path\n\n\nBASE_DIR = Path(__file__).parent.parent.resolve()\n\nsys.path.append(str(BASE_DIR.parent))\n\nDEBUG = True\n\nDEFAULT_AUTO_FIELD = \"django.db.models.AutoField\"\n\nUSE_TZ = True\n\nDATABASES = dict(\n    default=dict(\n        ENGINE=\"django.db.backends.postgresql\",\n        NAME=\"django-mptt-admin-example\",\n        USER=\"postgres\",\n        PASSWORD=os.environ.get(\"POSTGRES_PASSWORD\", \"\"),\n        HOST=os.environ.get(\"POSTGRES_HOST\", \"\"),\n        PORT=os.environ.get(\"POSTGRES_PORT\", \"\"),\n    )\n)\n\n\nINSTALLED_APPS = [\n    # Project app\n    \"django_mptt_example\",\n    # Generic apps\n    \"mptt\",\n    \"django_mptt_admin\",\n    # Django\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"django.contrib.staticfiles\",\n    \"django.contrib.admin\",\n]\n\n\nMIDDLEWARE = [\n    \"django.middleware.common.CommonMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"django.middleware.csrf.CsrfViewMiddleware\",\n    \"django.contrib.auth.middleware.AuthenticationMiddleware\",\n    \"django.contrib.messages.middleware.MessageMiddleware\",\n]\n\nSTATIC_URL = \"/static/\"\nROOT_URLCONF = \"example_project.urls\"\n\nSTATIC_ROOT = str(BASE_DIR.joinpath(\"static\"))\n\nSECRET_KEY = \"test_key\"\n\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"APP_DIRS\": True,\n        \"OPTIONS\": {\n            \"debug\": DEBUG,\n            \"context_processors\": [\n                \"django.template.context_processors.request\",\n                \"django.contrib.auth.context_processors.auth\",\n                \"django.template.context_processors.debug\",\n                \"django.template.context_processors.i18n\",\n                \"django.template.context_processors.media\",\n                \"django.template.context_processors.static\",\n                \"django.template.context_processors.tz\",\n                \"django.contrib.messages.context_processors.messages\",\n            ],\n        },\n    },\n]\n\nALLOWED_HOSTS = [\"*\"]\n\nif \"COVERAGE\" in os.environ:\n    DJANGO_MPTT_ADMIN_COVERAGE_JS = True\n\nSTORAGES = {\n    \"default\": {\n        \"BACKEND\": \"django.core.files.storage.FileSystemStorage\",\n    },\n    \"staticfiles\": {\n        \"BACKEND\": \"django.contrib.staticfiles.storage.ManifestStaticFilesStorage\",\n    },\n}\n"
  },
  {
    "path": "example_project/example_project/urls.py",
    "content": "from django.urls import path\nfrom django.contrib import admin\n\n\nurlpatterns = (path(\"\", admin.site.urls),)\n"
  },
  {
    "path": "example_project/import_test_data",
    "content": "python manage.py loaddata django_mptt_example/fixtures/countries.json\n"
  },
  {
    "path": "example_project/manage.py",
    "content": "#!/usr/bin/env python\nimport os\nimport sys\n\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"example_project.settings\")\n\n    from django.core.management import execute_from_command_line\n\n    execute_from_command_line(sys.argv)\n"
  },
  {
    "path": "example_project/requirements_all.txt",
    "content": "-r requirements_example.txt\n-r requirements_test.txt\n-r requirements_ci.txt\n"
  },
  {
    "path": "example_project/requirements_ci.txt",
    "content": "coverage==7.13.5\ndocopt==0.6.2\nPyYAML===6.0.3\nrequests==2.33.1\n"
  },
  {
    "path": "example_project/requirements_example.txt",
    "content": "Django>=6.0,<6.1\n"
  },
  {
    "path": "example_project/requirements_test.txt",
    "content": "beautifulsoup4==4.14.3\ndjango-mptt==0.18.0\ndjango-webtest==1.9.14\ncssselect==1.4.0\nlxml==6.1.0\nplaywright==1.58.0\npsycopg==3.3.3\npyquery==2.0.1\nwaitress==3.0.2\nWebOb==1.8.9\nWebTest==3.0.7\n"
  },
  {
    "path": "example_project/run_coverage",
    "content": "coverage run --source=django_mptt_admin,django_mptt_example manage.py test django_mptt_example\ncoverage report -m\n"
  },
  {
    "path": "example_project/run_tests",
    "content": "PYTHONWARNINGS=default python manage.py test --failfast -v 2 django_mptt_example\n"
  },
  {
    "path": "frontend/.babelrc",
    "content": "{\n    \"presets\": [\"@babel/preset-env\", \"@babel/preset-typescript\"],\n    \"plugins\": [\"@babel/plugin-transform-runtime\"]\n}\n"
  },
  {
    "path": "frontend/.editorconfig",
    "content": "# EditorConfig helps developers define and maintain\n# consistent coding styles between different editors and IDEs.\n\nroot = true\n\n[*]\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\n"
  },
  {
    "path": "frontend/django_mptt_admin.scss",
    "content": "@use \"node_modules/jqtree/jqtree\";\n\n@keyframes jqtree-spin {\n    0% {\n        transform: rotate(0deg);\n    }\n    100% {\n        transform: rotate(360deg);\n    }\n}\n\n#changelist {\n    border: none;\n}\n#tree {\n    padding: 1em 0 1em 0;\n\n    .mptt-admin-error {\n        color: var(--error-fg);\n        margin-left: 8px;\n    }\n\n    ul.jqtree-tree {\n        .jqtree-toggler {\n            top: 10%;\n            color: var(--link-fg);\n            text-decoration: none;\n        }\n\n        .edit {\n            margin-left: 0.5em;\n            vertical-align: middle;\n            color: var(--link-fg);\n        }\n\n        ul.jqtree_common {\n            margin-top: 0;\n        }\n\n        li.jqtree_common {\n            padding: 0;\n        }\n\n        &.jqtree-rtl {\n            .edit {\n                margin-left: 0;\n                margin-right: 0.5em;\n            }\n        }\n    }\n\n    .jqtree-spin {\n        margin-left: 1em;\n        width: 1em;\n        height: 1em;\n        border: 2px solid var(--body-fg);\n        border-bottom-color: transparent;\n        border-radius: 50%;\n        display: inline-block;\n        box-sizing: border-box;\n        animation: jqtree-spin 1s linear infinite;\n        vertical-align: middle;\n    }\n\n    &.block-style {\n        ul.jqtree-tree {\n            margin-left: 0;\n            margin-right: 0;\n\n            ul.jqtree_common {\n                margin-left: 2em;\n            }\n\n            .jqtree-element {\n                margin-bottom: 8px;\n                background-color: var(--darkened-bg);\n                padding: 8px;\n\n                .jqtree-title {\n                    color: var(--body-fg);\n                    margin-left: 0;\n                    margin-right: 0;\n                }\n\n                .jqtree-toggler.jqtree-toggler-right {\n                    margin-left: 1em;\n                }\n            }\n\n            li.jqtree-selected > .jqtree-element {\n                background: var(--breadcrumbs-bg);\n                color: var(--header-color);\n                text-shadow: none;\n\n                .jqtree-title {\n                    color: var(--breadcrumbs-link-fg);\n                }\n\n                .edit {\n                    color: var(--breadcrumbs-fg);\n                }\n            }\n\n            &.jqtree-rtl {\n                ul.jqtree_common {\n                    margin-left: 0;\n                    margin-right: 2em;\n                }\n\n                .jqtree-toggler.jqtree-toggler-right {\n                    margin-left: 0;\n                    margin-right: 1em;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "frontend/eslint.config.mjs",
    "content": "import eslint from \"@eslint/js\";\nimport tseslint from \"typescript-eslint\";\nimport importPlugin from \"eslint-plugin-import\";\nimport perfectionistPlugin from \"eslint-plugin-perfectionist\";\nimport vitest from \"@vitest/eslint-plugin\";\n\nexport default [\n    eslint.configs.recommended,\n    ...tseslint.configs.strictTypeChecked,\n    ...tseslint.configs.stylisticTypeChecked,\n    importPlugin.flatConfigs.recommended,\n    importPlugin.flatConfigs.typescript,\n    perfectionistPlugin.configs[\"recommended-natural\"],\n    {\n        languageOptions: {\n            parserOptions: {\n                projectService: true,\n                tsconfigRootDir: import.meta.dirname,\n            },\n        },\n        rules: {\n            \"@typescript-eslint/restrict-template-expressions\": \"error\",\n        },\n    },\n    {\n        files: [\"src/**/*.test.ts\"],\n        plugins: {\n            vitest,\n        },\n        rules: {\n            ...vitest.configs.recommended.rules,\n        },\n    },\n];\n"
  },
  {
    "path": "frontend/package.json",
    "content": "{\n    \"name\": \"django-mptt-admin\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Frontend code for django-mptt-admin\",\n    \"main\": \"index.js\",\n    \"scripts\": {\n        \"build\": \"pnpm run sass && pnpm run build_javascript_production && pnpm run build_javascript_production_debug && pnpm run build_javascript_coverage && pnpm run copy_jqtree_map_files\",\n        \"build_javascript_production\": \"webpack --mode production\",\n        \"build_javascript_production_debug\": \"SKIP_COMPRESS_JS=true webpack --mode production\",\n        \"build_javascript_coverage\": \"COVERAGE=true webpack --mode production\",\n        \"copy_jqtree_map_files\": \"cp node_modules/jqtree/*.map ../django_mptt_admin/static/django_mptt_admin/; cp node_modules/cookie/dist/*.map ../django_mptt_admin/static/django_mptt_admin/\",\n        \"sass\": \"sass django_mptt_admin.scss ../django_mptt_admin/static/django_mptt_admin/django_mptt_admin.css\",\n        \"webpack\": \"webpack --mode development --watch\",\n        \"lint\": \"eslint src\",\n        \"test\": \"vitest --watch=false\",\n        \"test:coverage\": \"vitest run --coverage\",\n        \"test:watch\": \"vitest\",\n        \"tsc\": \"tsc --noEmit --project tsconfig.json\",\n        \"ci\": \"pnpm run lint && pnpm run tsc && pnpm run test\"\n    },\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"git+https://github.com/mbraak/django-mptt-admin.git\"\n    },\n    \"author\": \"\",\n    \"license\": \"Apache-2.0\",\n    \"bugs\": {\n        \"url\": \"https://github.com/mbraak/django-mptt-admin/issues\"\n    },\n    \"homepage\": \"https://github.com/mbraak/django-mptt-admin#readme\",\n    \"peerDependencies\": {\n        \"jquery\": \">= 3\"\n    },\n    \"devDependencies\": {\n        \"@babel/core\": \"^7.29.0\",\n        \"@babel/plugin-transform-runtime\": \"^7.29.0\",\n        \"@babel/preset-env\": \"^7.29.2\",\n        \"@babel/preset-typescript\": \"^7.28.5\",\n        \"@eslint/js\": \"^9.39.4\",\n        \"@testing-library/dom\": \"^10.4.1\",\n        \"@testing-library/jest-dom\": \"^6.9.1\",\n        \"@types/jquery\": \"^4.0.0\",\n        \"@types/node\": \"^25.6.0\",\n        \"@vitest/coverage-istanbul\": \"^4.1.4\",\n        \"@vitest/eslint-plugin\": \"^1.6.15\",\n        \"babel-loader\": \"^10.1.1\",\n        \"babel-plugin-istanbul\": \"^8.0.0\",\n        \"eslint\": \"^9.39.4\",\n        \"eslint-plugin-import\": \"^2.32.0\",\n        \"eslint-plugin-perfectionist\": \"^5.8.0\",\n        \"jsdom\": \"^29.0.2\",\n        \"msw\": \"^2.13.3\",\n        \"sass\": \"^1.99.0\",\n        \"typescript\": \"^6\",\n        \"typescript-eslint\": \"^8.58.2\",\n        \"vitest\": \"^4.1.4\",\n        \"webpack\": \"^5.106.1\",\n        \"webpack-cli\": \"^7.0.2\"\n    },\n    \"dependencies\": {\n        \"cookie\": \"^1.1.1\",\n        \"jqtree\": \"^1.8.11\"\n    }\n}\n"
  },
  {
    "path": "frontend/src/djangoMpttAdmin.ts",
    "content": "import initTree from \"./initTree\";\n\njQuery(() => {\n    const $tree = jQuery(\"#tree\");\n\n    if ($tree.length) {\n        const animationSpeed = $tree.data(\"tree-animation-speed\") as\n            | null\n            | number\n            | string;\n        const autoOpen = $tree.data(\"auto_open\") as boolean | number;\n        const autoEscape = Boolean($tree.data(\"autoescape\"));\n        const hasAddPermission = Boolean($tree.data(\"has-add-permission\"));\n        const hasChangePermission = Boolean(\n            $tree.data(\"has-change-permission\")\n        );\n        const mouseDelay = $tree.data(\"tree-mouse-delay\") as null | number;\n        const dragAndDrop = $tree.data(\"drag-and-drop\") as boolean;\n        const rtl = $tree.data(\"rtl\") === \"1\";\n        const csrfCookieName = $tree.data(\"csrf-cookie-name\") as string;\n\n        initTree($tree, {\n            animationSpeed,\n            autoEscape,\n            autoOpen,\n            csrfCookieName,\n            dragAndDrop,\n            hasAddPermission,\n            hasChangePermission,\n            mouseDelay,\n            rtl,\n        });\n    }\n});\n"
  },
  {
    "path": "frontend/src/global.d.ts",
    "content": "declare function gettext(s: string): string;\n"
  },
  {
    "path": "frontend/src/initTree.test.ts",
    "content": "import { screen, waitFor } from \"@testing-library/dom\";\nimport * as cookie from \"cookie\";\nimport jQuery from \"jquery\";\nimport { http, HttpResponse } from \"msw\";\nimport { setupServer } from \"msw/node\";\nimport {\n    afterAll,\n    afterEach,\n    beforeAll,\n    beforeEach,\n    describe,\n    expect,\n    test,\n    vi,\n} from \"vitest\";\n\nimport initTree, { InitTreeOptions } from \"./initTree\";\n\nconst defaultTreeData = [\n    {\n        children: [\n            {\n                id: 2,\n                name: \"Africa\",\n                url: \"/edit/2\",\n            },\n        ],\n        id: 1,\n        name: \"root\",\n        url: \"/edit/1\",\n    },\n];\nlet treeData = {};\nlet csrfTokenInRequest: null | string = null;\n\nconst server = setupServer();\n\nbeforeAll(() => {\n    server.listen();\n});\n\nafterEach(() => {\n    server.resetHandlers();\n});\n\nafterAll(() => {\n    server.close();\n});\n\nbeforeEach(() => {\n    treeData = defaultTreeData;\n    csrfTokenInRequest = null;\n\n    server.use(\n        http.get(\"/tree\", () => HttpResponse.json(treeData)),\n        http.get(\"/no_data\", () => new HttpResponse(null, { status: 404 })),\n        http.post(\"/move\", ({ request }) => {\n            csrfTokenInRequest = request.headers.get(\"X-CSRFToken\");\n            return HttpResponse.json({});\n        })\n    );\n\n    document.body.innerHTML = \"\";\n    document.cookie = cookie.serialize(\"csrf\", \"\", {\n        expires: new Date(\"1970-01-01\"),\n    });\n});\n\nconst createTreeElement = (dataUrl = \"/tree\") => {\n    const treeElement = document.createElement(\"div\");\n    treeElement.setAttribute(\"data-url\", dataUrl);\n    treeElement.setAttribute(\"data-insert_at_url\", \"/add\");\n    document.body.append(treeElement);\n\n    return treeElement;\n};\n\nconst initTestTree = (\n    treeElement: HTMLElement,\n    paramOptions?: Partial<InitTreeOptions>\n) => {\n    const defaultOptions: InitTreeOptions = {\n        animationSpeed: null,\n        autoEscape: false,\n        autoOpen: false,\n        csrfCookieName: \"csrf\",\n        dragAndDrop: false,\n        hasAddPermission: true,\n        hasChangePermission: true,\n        mouseDelay: null,\n        rtl: false,\n    };\n\n    const $tree = jQuery(treeElement);\n    const options = { ...defaultOptions, ...paramOptions };\n\n    initTree($tree, options);\n};\n\ntest(\"initializes the tree\", async () => {\n    initTestTree(createTreeElement());\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n    expect(\n        screen.getByRole(\"treeitem\", { name: \"Africa\" })\n    ).toBeInTheDocument();\n});\n\ntest(\"displays a message when the data cannot be loaded\", async () => {\n    initTestTree(createTreeElement(\"/no_data\"));\n\n    expect(\n        await screen.findByText(\"Error while loading the data from the server\")\n    ).toBeInTheDocument();\n});\n\ntest(\"adds edit links when hasChangePermission is true\", async () => {\n    initTestTree(createTreeElement());\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n    const editLinks = screen.getAllByRole<HTMLAnchorElement>(\"link\", {\n        name: \"(edit)\",\n    });\n    expect(editLinks).toHaveLength(2);\n    expect(editLinks[0]?.href).toEqual(\"http://localhost:3000/edit/1\");\n\n    expect(screen.queryAllByRole(\"link\", { name: \"(view)\" })).toHaveLength(0);\n});\n\ntest(\"adds view links when hasChangePermission is false\", async () => {\n    initTestTree(createTreeElement(), { hasChangePermission: false });\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n    const editLinks = screen.getAllByRole<HTMLAnchorElement>(\"link\", {\n        name: \"(view)\",\n    });\n    expect(editLinks).toHaveLength(2);\n    expect(editLinks[0]?.href).toEqual(\"http://localhost:3000/edit/1\");\n\n    expect(screen.queryAllByRole(\"link\", { name: \"(edit)\" })).toHaveLength(0);\n});\n\ntest(\"adds add links when hasAddPermission is true\", async () => {\n    initTestTree(createTreeElement());\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n    const addLinks = screen.getAllByRole<HTMLAnchorElement>(\"link\", {\n        name: \"(add)\",\n    });\n    expect(addLinks).toHaveLength(2);\n    expect(addLinks[0]?.href).toEqual(\"http://localhost:3000/add?insert_at=1\");\n});\n\ntest(\"doesn't add add links when hasAddPermission is false\", async () => {\n    initTestTree(createTreeElement(), { hasAddPermission: false });\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n    const addLinks = screen.queryAllByRole(\"link\", {\n        name: \"(add)\",\n    });\n    expect(addLinks).toHaveLength(0);\n});\n\ntest(\"doesn't add links without node ids\", async () => {\n    treeData = [\n        {\n            children: [\n                {\n                    name: \"Africa\",\n                    url: \"/edit/2\",\n                },\n            ],\n            name: \"root\",\n            url: \"/edit/1\",\n        },\n    ];\n\n    initTestTree(createTreeElement());\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n    expect(\n        screen.getByRole(\"treeitem\", { name: \"Africa\" })\n    ).toBeInTheDocument();\n    expect(screen.queryAllByRole(\"link\")).toHaveLength(0);\n});\n\ntest(\"renders a link for a closed node with rtl is false\", async () => {\n    initTestTree(createTreeElement());\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n    expect(screen.getByText(\"►\")).toBeInTheDocument();\n});\n\ntest(\"renders a link for a closed node with rtl is true\", async () => {\n    initTestTree(createTreeElement(), { rtl: true });\n\n    expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n    expect(screen.getByText(\"◀\")).toBeInTheDocument();\n});\n\ndescribe(\"tree.move event\", () => {\n    const triggerTreeMove = (treeElement: HTMLElement) => {\n        const doMove = vi.fn();\n        const africaElement = screen.getByRole(\"treeitem\", { name: \"Africa\" });\n        const movedNode = {\n            element: africaElement,\n            id: 1,\n            move_url: \"/move\",\n        };\n        const targetNode = {\n            id: 2,\n        };\n\n        const move_info = {\n            do_move: doMove,\n            moved_node: movedNode,\n            original_event: {},\n            position: \"after\",\n            previous_parent: null,\n            target_node: targetNode,\n        };\n\n        jQuery(treeElement).trigger(jQuery.Event(\"tree.move\", { move_info }));\n\n        return doMove;\n    };\n\n    test(\"calls do_move\", async () => {\n        const treeElement = createTreeElement();\n        initTestTree(treeElement);\n        expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n        const doMove = triggerTreeMove(treeElement);\n\n        await waitFor(() => {\n            expect(doMove).toHaveBeenCalled();\n        });\n    });\n\n    test(\"sets the csrf cookie with a crsf cookie\", async () => {\n        document.cookie = cookie.serialize(\"csrf\", \"csrf1\");\n\n        const treeElement = createTreeElement();\n        initTestTree(treeElement);\n        expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n        const doMove = triggerTreeMove(treeElement);\n\n        await waitFor(() => {\n            expect(doMove).toHaveBeenCalled();\n        });\n        expect(csrfTokenInRequest).toEqual(\"csrf1\");\n    });\n\n    test(\"sets the csrf cookie with a crsf cookie and a csrfCookieName parameter\", async () => {\n        document.cookie = cookie.serialize(\"otherName\", \"value1\");\n\n        const treeElement = createTreeElement();\n        initTestTree(treeElement, { csrfCookieName: \"otherName\" });\n        expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n        const doMove = triggerTreeMove(treeElement);\n\n        await waitFor(() => {\n            expect(doMove).toHaveBeenCalled();\n        });\n        expect(csrfTokenInRequest).toEqual(\"value1\");\n    });\n\n    test(\"sets the csrf cookie with a crsf cookie and an empty csrfCookieName parameter\", async () => {\n        document.cookie = cookie.serialize(\"csrf\", \"testcsrf\");\n\n        const treeElement = createTreeElement();\n        initTestTree(treeElement, { csrfCookieName: undefined });\n        expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n        const doMove = triggerTreeMove(treeElement);\n\n        await waitFor(() => {\n            expect(doMove).toHaveBeenCalled();\n        });\n        expect(csrfTokenInRequest).toEqual(\"\");\n    });\n\n    test(\"sets the csrf cookie with a hidden csrf input\", async () => {\n        const csrfInput = document.createElement(\"input\");\n        csrfInput.setAttribute(\"name\", \"csrfmiddlewaretoken\");\n        csrfInput.setAttribute(\"value\", \"csrf_test\");\n        csrfInput.setAttribute(\"type\", \"hidden\");\n        document.body.append(csrfInput);\n\n        const treeElement = createTreeElement();\n        initTestTree(treeElement);\n        expect(await screen.findByRole(\"tree\")).toBeInTheDocument();\n\n        const doMove = triggerTreeMove(treeElement);\n\n        await waitFor(() => {\n            expect(doMove).toHaveBeenCalled();\n        });\n        expect(csrfTokenInRequest).toEqual(\"csrf_test\");\n    });\n});\n"
  },
  {
    "path": "frontend/src/initTree.ts",
    "content": "import * as cookie from \"cookie\";\nimport \"jqtree\";\n\nexport interface InitTreeOptions {\n    animationSpeed: null | number | string;\n    autoEscape: boolean;\n    autoOpen: boolean | number;\n    csrfCookieName: string;\n    dragAndDrop: boolean;\n    hasAddPermission: boolean;\n    hasChangePermission: boolean;\n    mouseDelay: null | number;\n    rtl: boolean;\n}\n\ninterface JQTreeLoadDataEvent extends JQuery.Event {\n    parent_node: INode | null;\n}\n\ninterface JQTreeLoadingEvent extends JQuery.Event {\n    isLoading: boolean;\n    node: INode | null;\n}\n\ninterface JQTreeMoveEvent extends JQuery.Event {\n    move_info: {\n        do_move: () => void;\n        moved_node: INode;\n        position: string;\n        target_node: INode;\n    };\n}\n\ninterface JQTreeSelectEvent extends JQuery.Event {\n    deselected_node: INode | null;\n    node: INode;\n}\n\nfunction initTree(\n    $tree: JQuery,\n    {\n        animationSpeed,\n        autoEscape,\n        autoOpen,\n        csrfCookieName,\n        dragAndDrop,\n        hasAddPermission,\n        hasChangePermission,\n        mouseDelay,\n        rtl,\n    }: InitTreeOptions\n) {\n    let errorNode: INode | null = null;\n    const baseUrl = \"http://example.com\";\n    const insertAtUrl = new URL($tree.data(\"insert_at_url\") as string, baseUrl);\n\n    function createLi(node: INode, $li: JQuery, isSelected: boolean) {\n        if (node.id == null) {\n            return;\n        }\n\n        // Create edit link\n        const $title = $li.find(\".jqtree-title\");\n\n        insertAtUrl.searchParams.set(\"insert_at\", node.id.toString());\n\n        const insertUrlString = insertAtUrl\n            .toString()\n            .substring(baseUrl.length);\n\n        const tabindex = isSelected ? \"0\" : \"-1\";\n        const editCaption = hasChangePermission\n            ? gettext(\"edit\")\n            : gettext(\"view\");\n\n        $title.after(\n            `<a href=\"${\n                node.url as string\n            }\" class=\"edit\" tabindex=\"${tabindex}\">(${editCaption})</a>`,\n            hasAddPermission\n                ? `<a href=\"${insertUrlString}\" class=\"edit\" tabindex=\"${tabindex}\">(${gettext(\n                      \"add\"\n                  )})</a>`\n                : \"\"\n        );\n    }\n\n    function getCsrfToken() {\n        function getFromMiddleware() {\n            const inputElement = document.querySelector<HTMLInputElement>(\n                '[name=\"csrfmiddlewaretoken\"]'\n            );\n            return inputElement?.value;\n        }\n\n        function getFromCookie() {\n            if (!csrfCookieName) {\n                return null;\n            } else {\n                return cookie.parse(document.cookie)[csrfCookieName];\n            }\n        }\n\n        return getFromCookie() ?? getFromMiddleware() ?? \"\";\n    }\n\n    function handleMove(eventParam: JQuery.Event) {\n        const e = eventParam as JQTreeMoveEvent;\n        const info = e.move_info;\n\n        if (!info.moved_node.element) {\n            return;\n        }\n\n        const $el = jQuery(info.moved_node.element);\n\n        const data = {\n            position: info.position,\n            target_id: info.target_node.id,\n        };\n\n        handleLoading(null);\n\n        removeErrorMessage();\n\n        e.preventDefault();\n\n        void jQuery.ajax({\n            beforeSend: (xhr) => {\n                // Set Django csrf token\n                xhr.setRequestHeader(\"X-CSRFToken\", getCsrfToken());\n            },\n            data,\n            error: () => {\n                handleLoaded(null);\n                const $node = $el.find(\".jqtree-element\");\n                $node.append(\n                    `<span class=\"mptt-admin-error\">${gettext(\n                        \"move failed\"\n                    )}</span>`\n                );\n\n                errorNode = info.moved_node;\n            },\n            success: () => {\n                info.do_move();\n                handleLoaded(null);\n            },\n            type: \"POST\",\n            url: info.moved_node.move_url as string,\n        });\n\n        function removeErrorMessage() {\n            if (errorNode?.element) {\n                jQuery(errorNode.element).find(\".mptt-admin-error\").remove();\n                errorNode = null;\n            }\n        }\n    }\n\n    function handleLoadFailed() {\n        $tree.html(gettext(\"Error while loading the data from the server\"));\n    }\n\n    const spinners: Record<number | string, HTMLElement | null> = {};\n\n    function getSpinnerId(node: INode | null): null | number | string {\n        if (!node) {\n            return \"__root__\";\n        } else {\n            if (node.id == null) {\n                return null;\n            } else {\n                return node.id as number | string;\n            }\n        }\n    }\n\n    function handleLoading(node: INode | null) {\n        function getContainer() {\n            if (node) {\n                return node.element;\n            } else {\n                return $tree.get(0);\n            }\n        }\n\n        const container = getContainer();\n        const spinnerId = getSpinnerId(node);\n\n        if (!container || spinnerId == null) {\n            return;\n        }\n\n        const spinner = document.createElement(\"span\");\n        spinner.className = \"jqtree-spin\";\n        container.append(spinner);\n        spinners[spinnerId] = spinner;\n    }\n\n    function handleLoaded(node: INode | null) {\n        const spinnerId = getSpinnerId(node);\n\n        if (spinnerId == null) {\n            return;\n        }\n\n        const spinner = spinners[spinnerId];\n\n        if (spinner) {\n            spinner.remove();\n        }\n    }\n\n    function handleSelect(eventParam: JQuery.Event) {\n        const e = eventParam as JQTreeSelectEvent;\n        const { deselected_node, node } = e;\n\n        if (deselected_node?.element) {\n            // deselected node: remove tabindex\n            jQuery(deselected_node.element).find(\".edit\").attr(\"tabindex\", -1);\n        }\n\n        // selected: add tabindex\n        if (node.element) {\n            jQuery(node.element).find(\".edit\").attr(\"tabindex\", 0);\n        }\n    }\n\n    function handleLoadingEvent(e: JQuery.Event) {\n        const { isLoading, node } = e as JQTreeLoadingEvent;\n\n        if (isLoading) {\n            handleLoading(node);\n        }\n    }\n\n    function handleLoadDataEvent(e: JQuery.Event) {\n        const { parent_node } = e as JQTreeLoadDataEvent;\n\n        handleLoaded(parent_node);\n    }\n\n    const treeOptions: Record<string, unknown> = {\n        autoEscape,\n        autoOpen,\n        buttonLeft: rtl,\n        closedIcon: rtl ? \"&#x25c0;\" : \"&#x25ba;\",\n        dragAndDrop: dragAndDrop && hasChangePermission,\n        onCreateLi: createLi,\n        onLoadFailed: handleLoadFailed,\n        saveState: $tree.data(\"save_state\") as boolean,\n        useContextMenu: Boolean($tree.data(\"use_context_menu\")),\n    };\n\n    if (animationSpeed !== null) {\n        treeOptions.animationSpeed = animationSpeed;\n    }\n\n    if (mouseDelay != null) {\n        treeOptions.startDndDelay = mouseDelay;\n    }\n\n    $tree.on(\"tree.loading_data\", handleLoadingEvent);\n    $tree.on(\"tree.load_data\", handleLoadDataEvent);\n    $tree.on(\"tree.move\", handleMove);\n    $tree.on(\"tree.select\", handleSelect);\n\n    $tree.tree(treeOptions);\n}\n\nexport default initTree;\n"
  },
  {
    "path": "frontend/src/vitestSetup.ts",
    "content": "import jQuery from \"jquery\";\nimport \"@testing-library/jest-dom/vitest\";\n\ndeclare global {\n    interface Window {\n        $: JQueryStatic;\n        jQuery: JQueryStatic;\n    }\n}\n\nwindow.$ = jQuery;\nwindow.jQuery = jQuery;\n\nwindow.gettext = (key) => key;\n"
  },
  {
    "path": "frontend/tsconfig.json",
    "content": "{\n    \"compileOnSave\": false,\n    \"exclude\": [\"node_modules\"],\n    \"include\": [\"src/**/*\"],\n    \"compilerOptions\": {\n        \"erasableSyntaxOnly\": true,\n        \"esModuleInterop\": true,\n        \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n        \"module\": \"ESNext\",\n        \"moduleResolution\": \"bundler\",\n        \"noEmit\": true,\n        \"noFallthroughCasesInSwitch\": true,\n        \"noImplicitReturns\": true,\n        \"noImplicitThis\": true,\n        \"noUncheckedIndexedAccess\": true,\n        \"noUnusedLocals\": true,\n        \"noUnusedParameters\": true,\n        \"rootDir\": \"src\",\n        \"skipLibCheck\": true,\n        \"strictNullChecks\": true,\n        \"strictPropertyInitialization\": false,\n        \"strict\": true,\n        \"target\": \"ES2022\"\n    }\n}\n"
  },
  {
    "path": "frontend/vitest.config.ts",
    "content": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n    test: {\n        coverage: {\n            provider: \"istanbul\",\n            reporter: [\"lcov\", \"text\"],\n        },\n        environment: \"jsdom\",\n        setupFiles: [\"./src/vitestSetup.ts\"],\n    },\n});\n"
  },
  {
    "path": "frontend/webpack.config.js",
    "content": "const path = require(\"path\");\n\nconst skipCompressJs = Boolean(process.env.SKIP_COMPRESS_JS);\nconst coverage = Boolean(process.env.COVERAGE);\n\nconst getOutputFilename = () => {\n    if (coverage) {\n        return \"django_mptt_admin.coverage.js\";\n    } else if (skipCompressJs) {\n        return \"django_mptt_admin.debug.js\";\n    } else {\n        return \"django_mptt_admin.js\";\n    }\n};\n\nconst minimize = !skipCompressJs && !coverage;\n\nmodule.exports = {\n    entry: {\n        django_mptt_admin: [\"./src/djangoMpttAdmin.ts\"],\n    },\n    output: {\n        path: path.resolve(\n            __dirname,\n            \"../django_mptt_admin/static/django_mptt_admin/\"\n        ),\n        filename: getOutputFilename(),\n    },\n    module: {\n        rules: [\n            {\n                test: /\\.ts$/,\n                exclude: /node_modules/,\n                use: {\n                    loader: \"babel-loader\",\n                    options: {\n                        presets: [\n                            \"@babel/preset-typescript\",\n                            [\"@babel/preset-env\", { targets: \"defaults\" }],\n                        ],\n                        plugins: coverage ? [\"istanbul\"] : [],\n                    },\n                },\n            },\n        ].filter(Boolean),\n    },\n    resolve: {\n        extensions: [\".ts\", \".js\"],\n    },\n    devtool: \"source-map\",\n    optimization: {\n        minimize,\n    },\n    externals: {\n        jquery: \"jQuery\",\n    },\n};\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "site_name: django-mptt-admin\ntheme: readthedocs\n"
  },
  {
    "path": "requirements_docs.txt",
    "content": "mkdocs==1.6.1\n"
  },
  {
    "path": "setup.cfg",
    "content": "[wheel]\nuniversal = 1\n"
  },
  {
    "path": "setup.py",
    "content": "from setuptools import setup, find_packages\n\nfrom os import path\nfrom io import open\n\nthis_directory = path.abspath(path.dirname(__file__))\nwith open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:\n    long_description = f.read()\n\nversion = '2.9.0'\n\nsetup(\n    name='django-mptt-admin',\n    version=version,\n    packages=find_packages(),\n    license='Apache License, Version 2.0',\n    long_description=long_description,\n    long_description_content_type='text/markdown',\n    include_package_data=True,\n    zip_safe=False,\n    author='Marco Braak',\n    author_email='marco.braak@planet.nl',\n    install_requires=['django-mptt'],\n    description='Django-mptt-admin provides a nice Django Admin interface for Mptt models',\n    url='https://github.com/mbraak/django-mptt-admin',\n    classifiers=[\n        \"Development Status :: 5 - Production/Stable\",\n        \"Framework :: Django\",\n        \"Framework :: Django :: 4.2\",\n        \"Framework :: Django :: 5.2\",\n        \"Framework :: Django :: 6.0\",\n        \"Intended Audience :: Developers\",\n        \"License :: OSI Approved :: Apache Software License\",\n        \"Programming Language :: Python :: 3.10\",\n        \"Programming Language :: Python :: 3.11\",\n        \"Programming Language :: Python :: 3.12\",\n        \"Programming Language :: Python :: 3.13\",\n        \"Programming Language :: Python :: 3.14\",\n        \"Programming Language :: Python :: Implementation :: CPython\"\n    ]\n)\n"
  },
  {
    "path": "tox.ini",
    "content": "[tox]\nenvlist = py310-django42,py312-django42,py313-django52,py314-django6\n\n[testenv]\nchangedir = {toxinidir}/example_project\nsetenv =\n    PYTHONWARNINGS = default\ndeps =\n    -r{toxinidir}/example_project/requirements_test.txt\n    django42: Django>=4.2,<4.3\n    django52: Django>=5.2,<5.3\n    django6: Django>=6.0,<6.1\ncommands =\n    python -Wd manage.py test django_mptt_example\nbasepython =\n    py310: python3.10\n    py312: python3.12\n    py313: python3.13\n    py314: python3.14\n"
  }
]