Full Code of mbraak/django-mptt-admin for AI

master b5fbe3b3ad02 cached
108 files
273.7 KB
83.5k tokens
155 symbols
1 requests
Download .txt
Showing preview only (299K chars total). Download the full file or copy to clipboard to get everything.
Repository: mbraak/django-mptt-admin
Branch: master
Commit: b5fbe3b3ad02
Files: 108
Total size: 273.7 KB

Directory structure:
gitextract_r07_re3i/

├── .coveragerc
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       ├── codeql-analysis.yml
│       └── mkdocs.yml
├── .gitignore
├── LICENSE.rst
├── MANIFEST.in
├── README.md
├── coverage/
│   ├── .nycrc.json
│   └── package.json
├── cspell.json
├── django_mptt_admin/
│   ├── __init__.py
│   ├── admin.py
│   ├── django_mptt_admin_mixin.py
│   ├── locale/
│   │   ├── ca/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── de/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── es/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── fr/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── he/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── hu/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── pl/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── ru/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   └── tr/
│   │       └── LC_MESSAGES/
│   │           ├── django.mo
│   │           ├── django.po
│   │           ├── djangojs.mo
│   │           └── djangojs.po
│   ├── static/
│   │   └── django_mptt_admin/
│   │       ├── django_mptt_admin.css
│   │       ├── django_mptt_admin.debug.js
│   │       ├── django_mptt_admin.debug.js.LICENSE.txt
│   │       ├── django_mptt_admin.js
│   │       ├── django_mptt_admin.js.LICENSE.txt
│   │       └── jquery_namespace.js
│   ├── templates/
│   │   └── django_mptt_admin/
│   │       ├── change_list.html
│   │       └── grid_view.html
│   ├── templatetags/
│   │   ├── __init__.py
│   │   └── javascript_value.py
│   ├── tree_change_list.py
│   └── util.py
├── docs/
│   └── index.md
├── example_project/
│   ├── django_mptt_example/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── fixtures/
│   │   │   └── countries.json
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_alter_country_level_alter_country_lft_and_more.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── base_playwright_testcase.py
│   │       ├── base_view_testcase.py
│   │       ├── playwright_page.py
│   │       ├── test_playwright.py
│   │       ├── test_util.py
│   │       ├── test_views.py
│   │       └── utils.py
│   ├── example_project/
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   └── urls.py
│   ├── import_test_data
│   ├── manage.py
│   ├── requirements_all.txt
│   ├── requirements_ci.txt
│   ├── requirements_example.txt
│   ├── requirements_test.txt
│   ├── run_coverage
│   └── run_tests
├── frontend/
│   ├── .babelrc
│   ├── .editorconfig
│   ├── django_mptt_admin.scss
│   ├── eslint.config.mjs
│   ├── package.json
│   ├── src/
│   │   ├── djangoMpttAdmin.ts
│   │   ├── global.d.ts
│   │   ├── initTree.test.ts
│   │   ├── initTree.ts
│   │   └── vitestSetup.ts
│   ├── tsconfig.json
│   ├── vitest.config.ts
│   └── webpack.config.js
├── mkdocs.yml
├── requirements_docs.txt
├── setup.cfg
├── setup.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .coveragerc
================================================
[run]
branch = True
omit =
  example_project/django_mptt_example/tests/base_playwright_testcase.py
  example_project/django_mptt_example/tests/playwright_page.py
  example_project/django_mptt_example/tests/test_playwright.py


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/ci.yml
================================================
name: Continuous integration

on: [push]

jobs:
  runner-job:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        django: ["django==4.2.30", "django==5.2.13", "django==6.0.4"]

    services:
      postgres:
        image: postgres
        env:
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

    steps:
      - name: Check out repository code
        uses: actions/checkout@v6
      - name: Check spelling
        uses: streetsidesoftware/cspell-action@v8
        with:
          files: |
            frontend/src/**/*.ts
            django_mptt_admin/**/*.py
            example_project/**/*.py
          incremental_files_only: false
      - name: Setup node
        uses: actions/setup-node@v6
        with:
          node-version: "20"
      - name: Install pnpm
        run: npm install -g pnpm
      - name: Get pnpm store directory
        id: pnpm-cache
        run: |
          echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v5
        name: Setup pnpm cache
        with:
          path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      - name: Install javascript packages
        working-directory: ./frontend
        run: pnpm install
      - name: Cache python packages
        uses: actions/cache@v5
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements**.txt') }}
          restore-keys: |
            ${{ runner.os }}-pip-
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - name: Install python packages
        run: |
          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 .
      - name: Build javascript
        working-directory: ./frontend
        run: pnpm run build
      - name: Javascript test
        working-directory: ./frontend
        run: pnpm run test:coverage
      - name: Collect static files
        run: python manage.py collectstatic --no-input
        working-directory: example_project
      - name: Create javascript coverage directory
        run: mkdir js_coverage
      - name: Test with coverage
        run: |
          COVERAGE=true coverage run --source=django_mptt_admin,example_project/django_mptt_example example_project/manage.py test django_mptt_example
        env:
          POSTGRES_HOST: localhost
          POSTGRES_PASSWORD: postgres
          POSTGRES_PORT: 5432
      - name: Merge Python coverage
        run: coverage report && coverage lcov
      - name: Merge javascript coverage
        working-directory: ./coverage
        run: pnpm i && pnpm run merge_coverage
      - name: Codecov
        uses: codecov/codecov-action@v6
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          verbose: true


================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
name: "CodeQL"

on:
  push:
    branches: ["master"]
  pull_request:
    branches: ["master"]

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        language: ["javascript", "python"]

    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}

      - name: Autobuild
        uses: github/codeql-action/autobuild@v3

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3


================================================
FILE: .github/workflows/mkdocs.yml
================================================
name: Publish docs via GitHub Pages

on:
  push:
    branches:
      - master
      - mkdocs-workflow

jobs:
  build:
    name: Deploy docs
    runs-on: ubuntu-latest

    steps:
      - name: Checkout master
        uses: actions/checkout@v6

      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: 3.12

      - name: Install python packages
        run: |
          pip install -r requirements_docs.txt

      - name: Run mkdocs
        run: mkdocs gh-deploy --force


================================================
FILE: .gitignore
================================================
.DS_Store
*.pyc
django_mptt_admin/static/django_mptt_admin/django_mptt_admin.coverage.js
django_mptt_admin/static/django_mptt_admin/django_mptt_admin.coverage.js.map


================================================
FILE: LICENSE.rst
================================================
=======
LICENSE
=======

Copyright © 2013, Marco Braak

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this software except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: MANIFEST.in
================================================
include LICENSE.rst
include README.md
recursive-include django_mptt_admin/templates *
recursive-include django_mptt_admin/static *
recursive-include django_mptt_admin/locale *


================================================
FILE: README.md
================================================
![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/)

[![codecov](https://codecov.io/gh/mbraak/django-mptt-admin/branch/master/graph/badge.svg?token=YGojePND2M)](https://codecov.io/gh/mbraak/django-mptt-admin)

[![License](https://img.shields.io/pypi/l/django-mptt-admin.svg)](https://pypi.python.org/pypi/django-mptt-admin/)

# Django Mptt Admin

_Django-mptt-admin_ provides a nice Django Admin interface for [django-mptt models](https://django-mptt.readthedocs.io/).

- The source is available on [https://github.com/mbraak/django-mptt-admin](https://github.com/mbraak/django-mptt-admin).
- Documentation is available on [https://mbraak.github.io/django-mptt-admin/](https://mbraak.github.io/django-mptt-admin/).

![Screenshot](https://raw.github.com/mbraak/django-mptt-admin/master/screenshot.png)


================================================
FILE: coverage/.nycrc.json
================================================
{
  "exclude-after-remap": false
}


================================================
FILE: coverage/package.json
================================================
{
  "name": "coverage",
  "dependencies": {
    "nyc": "^18"
  },
  "scripts": {
    "merge_coverage": "nyc --reporter lcov -t ./js_coverage --cwd .. report"
  }
}


================================================
FILE: cspell.json
================================================
{
  "language": "en-GB",
  "words": [
    "Åland",
    "bouvet",
    "countrycode",
    "countrycodeandname",
    "crsf",
    "csrfmiddlewaretoken",
    "jqtree",
    "mptt",
    "rght",
    "tabindex",
    "testcsrf",
    "toggler",
    "webtest"
  ]
}


================================================
FILE: django_mptt_admin/__init__.py
================================================


================================================
FILE: django_mptt_admin/admin.py
================================================
from mptt.admin import MPTTModelAdmin

from .django_mptt_admin_mixin import DjangoMpttAdminMixin


class DjangoMpttAdmin(DjangoMpttAdminMixin, MPTTModelAdmin):
    pass


class FilterableDjangoMpttAdmin(DjangoMpttAdmin):
    pass


================================================
FILE: django_mptt_admin/django_mptt_admin_mixin.py
================================================
from functools import update_wrapper
from typing import Union

from django.conf import settings
from django.templatetags.static import static
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.http import JsonResponse
from django.template.response import TemplateResponse
from django.contrib.admin.options import csrf_protect_m, ModelAdmin
from django.contrib.admin.utils import unquote, quote
from django.contrib.admin.options import IS_POPUP_VAR
from django.db import transaction
from django.utils.http import urlencode
from django.forms import Media
from django.urls import re_path, reverse
from django.views.i18n import JavaScriptCatalog
import django

from . import util
from .tree_change_list import TreeChangeList


class DjangoMpttAdminMixin:
    tree_animation_speed = None
    tree_auto_open = 1
    tree_load_on_demand = 1
    tree_mouse_delay = None
    trigger_save_after_move = False

    # Autoescape the tree data; default is True
    autoescape = True

    # useContextMenu option for the tree; default is False
    use_context_menu = False

    change_list_template = "django_mptt_admin/grid_view.html"
    change_tree_template = "django_mptt_admin/change_list.html"

    # define which field of the model should be the label for tree items
    item_label_field_name = None

    # list and tree filter
    list_filter = ()

    change_list_tree_class = TreeChangeList

    @csrf_protect_m
    def changelist_view(
        self: Union[ModelAdmin, "DjangoMpttAdminMixin"], request, extra_context=None
    ):
        request.current_app = self.admin_site.name
        is_popup = IS_POPUP_VAR in request.GET
        if is_popup:
            return super(DjangoMpttAdminMixin, self).changelist_view(
                request, extra_context=extra_context
            )

        if not self.has_view_or_change_permission(request):
            raise PermissionDenied()

        change_list = self.get_change_list_for_tree(request)

        preserved_filters = self.get_preserved_filters(request)

        def get_admin_url_with_filters(name):
            admin_url = self.get_admin_url(name)

            if change_list.params:
                return admin_url + change_list.get_query_string()
            else:
                return admin_url

        def get_admin_url_with_preserved_filters(name):
            return add_preserved_filters(
                {"preserved_filters": preserved_filters, "opts": self.opts},
                self.get_admin_url(name),
            )

        def get_csrf_cookie_name():
            if settings.CSRF_USE_SESSIONS:
                return ""
            else:
                return settings.CSRF_COOKIE_NAME

        grid_url = get_admin_url_with_filters("grid")
        tree_json_url = get_admin_url_with_filters("tree_json")
        insert_at_url = get_admin_url_with_preserved_filters("add")

        tree_options = {
            "autoescape": self.autoescape,
            "csrf_cookie_name": get_csrf_cookie_name(),
            "drag_and_drop": self.is_drag_and_drop_enabled(),
            "grid_url": grid_url,
            "has_add_permission": self.has_add_permission(request),
            "has_change_permission": self.has_change_permission(request),
            "insert_at_url": insert_at_url,
            "jsi18n_url": self.get_admin_url("jsi18n"),
            "model_name": util.get_model_name(self.model),
            "tree_animation_speed": self.tree_animation_speed,
            "tree_auto_open": self.tree_auto_open,
            "tree_json_url": tree_json_url,
            "tree_mouse_delay": self.get_tree_mouse_delay(),
            "use_context_menu": self.use_context_menu,
        }

        context = {
            **self.admin_site.each_context(request),
            "django_major_version": django.VERSION[0],
            "module_name": str(self.opts.verbose_name_plural),
            "title": change_list.title,
            "subtitle": None,
            "is_popup": change_list.is_popup,
            "to_field": change_list.to_field,
            "cl": change_list,
            "media": self.get_tree_media(),
            "opts": change_list.opts,
            "preserved_filters": self.get_preserved_filters(request),
            **tree_options,
            **(extra_context or {}),
        }

        request.current_app = self.admin_site.name

        return TemplateResponse(request, self.change_tree_template, context)

    def get_urls(self: Union[ModelAdmin, "DjangoMpttAdminMixin"]):
        def wrap(view, cacheable=False):
            def wrapper(*args, **kwargs):
                return self.admin_site.admin_view(view, cacheable)(*args, **kwargs)

            return update_wrapper(wrapper, view)

        def create_url(regex, url_name, view, kwargs=None, cacheable=False):
            return re_path(
                regex,
                wrap(view, cacheable),
                kwargs=kwargs,
                name="{0!s}_{1!s}_{2!s}".format(
                    self.opts.app_label,
                    util.get_model_name(self.model),
                    url_name,
                ),
            )

        def create_js_catalog_url():
            packages = ["django_mptt_admin"]
            url_pattern = r"^jsi18n/$"

            return create_url(
                url_pattern,
                "jsi18n",
                JavaScriptCatalog.as_view(packages=packages),
                cacheable=True,
            )

        # prepend new urls to existing urls
        return [
            create_url(r"^(.+)/move/$", "move", self.move_view),
            create_url(r"^tree_json/$", "tree_json", self.tree_json_view),
            create_url(r"^grid/$", "grid", self.grid_view),
            create_js_catalog_url(),
        ] + super(DjangoMpttAdminMixin, self).get_urls()

    def get_tree_media(self: ModelAdmin):
        django_mptt_admin_js = (
            "django_mptt_admin.coverage.js"
            if getattr(settings, "DJANGO_MPTT_ADMIN_COVERAGE_JS", False)
            else "django_mptt_admin.js"
        )

        js = [
            "admin/js/jquery.init.js",
            static("django_mptt_admin/jquery_namespace.js"),
            static(f"django_mptt_admin/{django_mptt_admin_js}"),
        ]
        css = dict(all=(static("django_mptt_admin/django_mptt_admin.css"),))

        tree_media = Media(js=js, css=css)

        return self.media + tree_media

    @csrf_protect_m
    @transaction.atomic()
    def move_view(self: Union[ModelAdmin, "DjangoMpttAdminMixin"], request, object_id):
        request.current_app = self.admin_site.name
        instance = self.get_object(request, unquote(object_id))

        if not self.has_change_permission(request, instance):
            raise PermissionDenied()

        if request.method != "POST":
            raise SuspiciousOperation()

        target_id = request.POST["target_id"]
        position = request.POST["position"]
        target_instance = self.get_object(request, target_id)

        self.do_move(instance, position, target_instance)

        return JsonResponse(dict(success=True))

    def do_move(self, instance, position, target_instance):
        if position == "before":
            instance.move_to(target_instance, "left")
        elif position == "after":
            instance.move_to(target_instance, "right")
        elif position == "inside":
            instance.move_to(target_instance)
        else:
            raise Exception("Unknown position")

        if self.trigger_save_after_move:
            instance.save()

    def get_change_list_for_tree(
        self: Union[ModelAdmin, "DjangoMpttAdminMixin"],
        request,
        node_id=None,
        max_level=None,
    ):
        request.current_app = self.admin_site.name

        return self.change_list_tree_class(
            request=request,
            model=self.model,
            model_admin=self,
            list_filter=self.get_list_filter(request),
            node_id=node_id,
            max_level=max_level,
        )

    def get_admin_url(self: ModelAdmin, name, args=None):
        opts = self.opts
        url_name = "admin:{0!s}_{1!s}_{2!s}".format(
            opts.app_label, util.get_model_name(self.model), name
        )
        return reverse(url_name, args=args, current_app=self.admin_site.name)

    def get_tree_data(
        self: Union[ModelAdmin, "DjangoMpttAdminMixin"], qs, max_level, filters_params
    ):
        pk_attname = self.opts.pk.attname

        preserved_filters = urlencode(
            {"_changelist_filters": urlencode(filters_params)}
        )

        def add_preserved_filters_to_url(url):
            return add_preserved_filters(
                {"preserved_filters": preserved_filters, "opts": self.opts}, url
            )

        def handle_create_node(instance, node_info):
            pk = getattr(instance, pk_attname)

            node_url = add_preserved_filters_to_url(
                self.get_admin_url("change", (quote(pk),))
            )

            node_info.update(
                url=node_url, move_url=self.get_admin_url("move", (quote(pk),))
            )

        return util.get_tree_from_queryset(
            qs, handle_create_node, max_level, self.item_label_field_name
        )

    def tree_json_view(self: Union[ModelAdmin, "DjangoMpttAdminMixin"], request):
        request.current_app = self.admin_site.name
        node_id = request.GET.get("node")

        def get_max_level():
            if node_id:
                node = self.model.objects.get(pk=node_id)
                return node.level + 1
            else:
                return self.tree_load_on_demand

        max_level = get_max_level()

        change_list = self.get_change_list_for_tree(request, node_id, max_level)

        qs = change_list.get_queryset(request)
        qs = self.filter_tree_queryset(qs, request)

        tree_data = self.get_tree_data(qs, max_level, change_list.get_filters_params())

        # Set safe to False because the data is a list instead of a dict
        return JsonResponse(tree_data, safe=False)

    def grid_view(
        self: Union[ModelAdmin, "DjangoMpttAdminMixin"], request, extra_context=None
    ):
        request.current_app = self.admin_site.name

        preserved_filters = self.get_preserved_filters(request)

        tree_url = add_preserved_filters(
            {"preserved_filters": preserved_filters, "opts": self.opts},
            self.get_admin_url("changelist"),
        )

        context = dict(tree_url=tree_url)

        if extra_context:
            context.update(extra_context)
        return super(DjangoMpttAdminMixin, self).changelist_view(request, context)

    def get_preserved_filters(self: Union[ModelAdmin, "DjangoMpttAdminMixin"], request):
        """
        Override `get_preserved_filters` to make sure that it returns the current filters for the grid view.
        """

        def must_return_current_filters():
            match = request.resolver_match

            if not self.preserve_filters or not match:
                return False
            else:
                opts = self.opts
                current_url = "{0!s}:{1!s}".format(match.app_name, match.url_name)
                grid_url = "admin:{0!s}_{1!s}_grid".format(
                    opts.app_label, opts.model_name
                )

                return current_url == grid_url

        if must_return_current_filters():
            # for the grid view return the current filters
            preserved_filters = request.GET.urlencode()
            return urlencode({"_changelist_filters": preserved_filters})
        else:
            return super(DjangoMpttAdminMixin, self).get_preserved_filters(request)

    def filter_tree_queryset(self, queryset, request):
        """
        Override 'filter_tree_queryset' to filter the queryset for the tree.
        """
        return queryset

    def get_changeform_initial_data(
        self: Union[ModelAdmin, "DjangoMpttAdminMixin"], request
    ):
        initial_data = super(DjangoMpttAdminMixin, self).get_changeform_initial_data(
            request=request
        )

        if "insert_at" in request.GET:
            initial_data[self.get_insert_at_field()] = request.GET.get("insert_at")

        return initial_data

    def get_insert_at_field(self):
        return "parent"

    def is_drag_and_drop_enabled(self) -> bool:
        # Override this method to disable drag-and-drop
        return True

    def get_tree_mouse_delay(self):
        return self.tree_mouse_delay


================================================
FILE: django_mptt_admin/locale/ca/LC_MESSAGES/django.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-12 11:48+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: django_mptt_admin/templates/django_mptt_admin/change_list.html:31
msgid "Filter"
msgstr "Filtre"

#: django_mptt_admin/templates/django_mptt_admin/change_list.html:42
msgid "Grid view"
msgstr "Vista de quadrícula"

#: django_mptt_admin/templates/django_mptt_admin/grid_view.html:7
msgid "Tree view"
msgstr "Vista d'arbre"


================================================
FILE: django_mptt_admin/locale/ca/LC_MESSAGES/djangojs.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-12 11:51+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "edit"
msgstr "editar"

#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "add"
msgstr "afegir"

#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "Error while loading the data from the server"
msgstr "Error quan es carregaven les dades del servidor"

#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "move failed"
msgstr "moviment fallit"


================================================
FILE: django_mptt_admin/locale/de/LC_MESSAGES/django.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-22 09:30+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: templates/django_mptt_admin/change_list.html:31
msgid "Filter"
msgstr ""

#: templates/django_mptt_admin/change_list.html:42
msgid "Grid view"
msgstr "Tabellenansicht"

#: templates/django_mptt_admin/grid_view.html:7
msgid "Tree view"
msgstr "Baumansicht"


================================================
FILE: django_mptt_admin/locale/de/LC_MESSAGES/djangojs.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-22 09:32+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "edit"
msgstr "Bearbeiten"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "add"
msgstr "Neu"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "Error while loading the data from the server"
msgstr "Fehler beim Laden der Daten vom Server"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "move failed"
msgstr "Verschieben fehlgeschlagen"


================================================
FILE: django_mptt_admin/locale/es/LC_MESSAGES/django.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-12 11:55+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: django_mptt_admin/templates/django_mptt_admin/change_list.html:31
msgid "Filter"
msgstr "Filtro"

#: django_mptt_admin/templates/django_mptt_admin/change_list.html:42
msgid "Grid view"
msgstr "Vista de cuadrícula"

#: django_mptt_admin/templates/django_mptt_admin/grid_view.html:7
msgid "Tree view"
msgstr "Vista de árbol"


================================================
FILE: django_mptt_admin/locale/es/LC_MESSAGES/djangojs.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-12 11:56+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "edit"
msgstr "editar"

#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "add"
msgstr "añadir"

#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "Error while loading the data from the server"
msgstr "Error cuando se cargaban los datos del servidor"

#: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js:1
msgid "move failed"
msgstr "movimiento fallido"


================================================
FILE: django_mptt_admin/locale/fr/LC_MESSAGES/django.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-05 20:20+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: django_mptt_admin/templates/django_mptt_admin/change_list.html:30
msgid "Filter"
msgstr "Filtre"

#: django_mptt_admin/templates/django_mptt_admin/change_list.html:41
msgid "Grid view"
msgstr "Vue Tableau"

#: django_mptt_admin/templates/django_mptt_admin/grid_view.html:7
msgid "Tree view"
msgstr "Vue arbre"


================================================
FILE: django_mptt_admin/locale/fr/LC_MESSAGES/djangojs.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-05 20:18+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "edit"
msgstr "éditer"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "add"
msgstr "ajouter"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "move failed"
msgstr "déplacement échoué"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "Error while loading the data from the server"
msgstr "Erreur en chargeant les données depuis le serveur"


================================================
FILE: django_mptt_admin/locale/he/LC_MESSAGES/django.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-11-10 15:29+0200\n"
"PO-Revision-Date: 2014-11-10 15:30+0200\n"
"Last-Translator: Udi Oron <udioron@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.5.7\n"

msgid "Grid view"
msgstr "תצוגה טבלאית"

msgid "Tree view"
msgstr "תצוגת עץ"


================================================
FILE: django_mptt_admin/locale/he/LC_MESSAGES/djangojs.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-11-10 15:29+0200\n"
"PO-Revision-Date: 2014-11-10 15:30+0200\n"
"Last-Translator: Udi Oron <udioron@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.5.7\n"

msgid "edit"
msgstr "עריכה"

msgid "add"
msgstr "הוספה"

msgid "move failed"
msgstr "ההעברה נכשלה"

msgid "Error while loading the data from the server"
msgstr "שגיאה במהלך שליחת הנתונים לשרת"


================================================
FILE: django_mptt_admin/locale/hu/LC_MESSAGES/django.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-21 14:32+0100\n"
"PO-Revision-Date: 2016-11-21 14:32+0100\n"
"Last-Translator: Istvan Farkas <istvan.farkas@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: .\templates\django_mptt_admin\change_list.html:30
msgid "Filter"
msgstr "Szűrő"

#: .\templates\django_mptt_admin\change_list.html:41
msgid "Grid view"
msgstr "Táblázatos nézet"

#: .\templates\django_mptt_admin\grid_view.html:7
msgid "Tree view"
msgstr "Fa nézet"


================================================
FILE: django_mptt_admin/locale/hu/LC_MESSAGES/djangojs.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-21 14:32+0100\n"
"PO-Revision-Date: 2016-11-21 14:32+0100\n"
"Last-Translator: Istvan Farkas <istvan.farkas@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

msgid "edit"
msgstr "szerkeszt"

msgid "add"
msgstr "új"

msgid "move failed"
msgstr "mozgatás sikertelen"

msgid "Error while loading the data from the server"
msgstr "Hiba történt az adatok betöltése közben"


================================================
FILE: django_mptt_admin/locale/pl/LC_MESSAGES/django.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-22 09:30+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: templates/django_mptt_admin/change_list.html:31
msgid "Filter"
msgstr "Filtruj"

#: templates/django_mptt_admin/change_list.html:42
msgid "Grid view"
msgstr "Widok tabeli"

#: templates/django_mptt_admin/grid_view.html:7
msgid "Tree view"
msgstr "Widok drzewa"


================================================
FILE: django_mptt_admin/locale/pl/LC_MESSAGES/djangojs.po
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-22 09:32+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "edit"
msgstr "zmień"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "add"
msgstr "dodaj"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "Error while loading the data from the server"
msgstr "Błąd podczas wczytywania danych z serwera"

#: static/django_mptt_admin/django_mptt_admin.js:1
msgid "move failed"
msgstr "przenoszenie nieudane"


================================================
FILE: django_mptt_admin/locale/ru/LC_MESSAGES/django.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-05-21 00:42+0300\n"
"PO-Revision-Date: 2015-05-21 00:42+0300\n"
"Last-Translator: Mikhail Silonov <m.silonov@gmail.com>\n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

msgid "Grid view"
msgstr "В виде сетки"

msgid "Tree view"
msgstr "В виде дерева"


================================================
FILE: django_mptt_admin/locale/ru/LC_MESSAGES/djangojs.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-05-21 00:42+0300\n"
"PO-Revision-Date: 2015-05-21 00:42+0300\n"
"Last-Translator: Mikhail Silonov <m.silonov@gmail.com>\n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

msgid "edit"
msgstr "редактировать"

msgid "add"
msgstr "Добавить"

msgid "move failed"
msgstr "не удалось переместить"

msgid "Error while loading the data from the server"
msgstr "Ошибка при загрузке данных с сервера"

msgid "Grid view"
msgstr "В виде сетки"

msgid "Tree view"
msgstr "В виде дерева"


================================================
FILE: django_mptt_admin/locale/tr/LC_MESSAGES/django.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-05 06:00+0300\n"
"PO-Revision-Date: 2015-01-05 06:00+0300\n"
"Last-Translator: Emir Tagmat <emir@tagmat.net>\n"
"Language-Team: \n"
"Language: Turkish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

msgid "Grid view"
msgstr "Tablo görünümü"

msgid "Tree view"
msgstr "Ağaç görünümü"


================================================
FILE: django_mptt_admin/locale/tr/LC_MESSAGES/djangojs.po
================================================
msgid ""
msgstr ""
"Project-Id-Version: django-mptt-admin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-05 06:00+0300\n"
"PO-Revision-Date: 2015-01-05 06:00+0300\n"
"Last-Translator: Emir Tagmat <emir@tagmat.net>\n"
"Language-Team: \n"
"Language: Turkish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

msgid "edit"
msgstr "düzenle"

msgid "add"
msgstr "ekle"

msgid "move failed"
msgstr "taşıma başarısız"

msgid "Error while loading the data from the server"
msgstr "Veri sunucudan yüklenirken hata oluştu"


================================================
FILE: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.css
================================================
ul.jqtree-tree {
  list-style: none outside;
  margin-left: 0;
  margin-bottom: 0;
  padding: 0;
}

ul.jqtree-tree.jqtree-dnd {
  touch-action: none;
}

ul.jqtree-tree ul.jqtree_common {
  list-style: none outside;
  margin-left: 12px;
  margin-right: 0;
  margin-bottom: 0;
  padding: 0;
  display: block;
}

ul.jqtree-tree li.jqtree-closed > ul.jqtree_common {
  display: none;
}

ul.jqtree-tree li.jqtree_common {
  clear: both;
  list-style-type: none;
}

ul.jqtree-tree .jqtree-toggler {
  border-bottom: none;
  color: #333;
  text-decoration: none;
  vertical-align: middle;
}

ul.jqtree-tree .jqtree-toggler:hover {
  color: #000;
  text-decoration: none;
}

ul.jqtree-tree .jqtree-toggler.jqtree-closed {
  background-position: 0 0;
}

ul.jqtree-tree .jqtree-toggler.jqtree-toggler-left {
  margin-right: 0.5em;
}

ul.jqtree-tree .jqtree-toggler.jqtree-toggler-right {
  margin-left: 0.5em;
}

ul.jqtree-tree .jqtree-element {
  cursor: pointer;
  position: relative;
  display: flex;
}

ul.jqtree-tree .jqtree-element:has(.jqtree-title-button-right) {
  display: block;
}

ul.jqtree-tree .jqtree-title {
  color: #1c4257;
  vertical-align: middle;
}

ul.jqtree-tree .jqtree-title-button-left {
  margin-left: 1.5em;
}

ul.jqtree-tree .jqtree-title-button-left.jqtree-title-folder {
  margin-left: 0;
}

ul.jqtree-tree li.jqtree-folder {
  margin-bottom: 4px;
}

ul.jqtree-tree li.jqtree-folder.jqtree-closed {
  margin-bottom: 1px;
}

ul.jqtree-tree li.jqtree-ghost {
  position: relative;
  z-index: 10;
  margin-right: 10px;
}

ul.jqtree-tree li.jqtree-ghost span {
  display: block;
}

ul.jqtree-tree li.jqtree-ghost span.jqtree-circle {
  border: solid 2px #0000ff;
  border-radius: 100px;
  height: 8px;
  width: 8px;
  position: absolute;
  top: -4px;
  left: -6px;
  box-sizing: border-box;
}

ul.jqtree-tree li.jqtree-ghost span.jqtree-line {
  background-color: #0000ff;
  height: 2px;
  padding: 0;
  position: absolute;
  top: -1px;
  left: 2px;
  width: 100%;
}

ul.jqtree-tree li.jqtree-ghost.jqtree-inside {
  margin-left: 48px;
}

ul.jqtree-tree span.jqtree-border {
  position: absolute;
  display: block;
  left: -2px;
  top: 0;
  border: solid 2px #0000ff;
  border-radius: 6px;
  margin: 0;
  box-sizing: content-box;
}

ul.jqtree-tree li.jqtree-selected > .jqtree-element,
ul.jqtree-tree li.jqtree-selected > .jqtree-element:hover {
  background-color: #97bdd6;
  background: linear-gradient(#bee0f5, #89afca);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
}

ul.jqtree-tree .jqtree-moving > .jqtree-element .jqtree-title {
  outline: dashed 1px #0000ff;
}

ul.jqtree-tree.jqtree-rtl {
  direction: rtl;
}

ul.jqtree-tree.jqtree-rtl ul.jqtree_common {
  margin-left: 0;
  margin-right: 12px;
}

ul.jqtree-tree.jqtree-rtl .jqtree-toggler {
  margin-left: 0.5em;
  margin-right: 0;
}

ul.jqtree-tree.jqtree-rtl .jqtree-title {
  margin-left: 0;
  margin-right: 1.5em;
}

ul.jqtree-tree.jqtree-rtl .jqtree-title.jqtree-title-folder {
  margin-right: 0;
}

ul.jqtree-tree.jqtree-rtl li.jqtree-ghost {
  margin-right: 0;
  margin-left: 10px;
}

ul.jqtree-tree.jqtree-rtl li.jqtree-ghost span.jqtree-circle {
  right: -6px;
}

ul.jqtree-tree.jqtree-rtl li.jqtree-ghost span.jqtree-line {
  right: 2px;
}

ul.jqtree-tree.jqtree-rtl li.jqtree-ghost.jqtree-inside {
  margin-left: 0;
  margin-right: 48px;
}

ul.jqtree-tree.jqtree-rtl span.jqtree-border {
  right: -2px;
}

span.jqtree-dragging {
  color: #fff;
  background: #000;
  opacity: 0.6;
  cursor: pointer;
  padding: 2px 8px;
}

@keyframes jqtree-spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
#changelist {
  border: none;
}

#tree {
  padding: 1em 0 1em 0;
}
#tree .mptt-admin-error {
  color: var(--error-fg);
  margin-left: 8px;
}
#tree ul.jqtree-tree .jqtree-toggler {
  top: 10%;
  color: var(--link-fg);
  text-decoration: none;
}
#tree ul.jqtree-tree .edit {
  margin-left: 0.5em;
  vertical-align: middle;
  color: var(--link-fg);
}
#tree ul.jqtree-tree ul.jqtree_common {
  margin-top: 0;
}
#tree ul.jqtree-tree li.jqtree_common {
  padding: 0;
}
#tree ul.jqtree-tree.jqtree-rtl .edit {
  margin-left: 0;
  margin-right: 0.5em;
}
#tree .jqtree-spin {
  margin-left: 1em;
  width: 1em;
  height: 1em;
  border: 2px solid var(--body-fg);
  border-bottom-color: transparent;
  border-radius: 50%;
  display: inline-block;
  box-sizing: border-box;
  animation: jqtree-spin 1s linear infinite;
  vertical-align: middle;
}
#tree.block-style ul.jqtree-tree {
  margin-left: 0;
  margin-right: 0;
}
#tree.block-style ul.jqtree-tree ul.jqtree_common {
  margin-left: 2em;
}
#tree.block-style ul.jqtree-tree .jqtree-element {
  margin-bottom: 8px;
  background-color: var(--darkened-bg);
  padding: 8px;
}
#tree.block-style ul.jqtree-tree .jqtree-element .jqtree-title {
  color: var(--body-fg);
  margin-left: 0;
  margin-right: 0;
}
#tree.block-style ul.jqtree-tree .jqtree-element .jqtree-toggler.jqtree-toggler-right {
  margin-left: 1em;
}
#tree.block-style ul.jqtree-tree li.jqtree-selected > .jqtree-element {
  background: var(--breadcrumbs-bg);
  color: var(--header-color);
  text-shadow: none;
}
#tree.block-style ul.jqtree-tree li.jqtree-selected > .jqtree-element .jqtree-title {
  color: var(--breadcrumbs-link-fg);
}
#tree.block-style ul.jqtree-tree li.jqtree-selected > .jqtree-element .edit {
  color: var(--breadcrumbs-fg);
}
#tree.block-style ul.jqtree-tree.jqtree-rtl ul.jqtree_common {
  margin-left: 0;
  margin-right: 2em;
}
#tree.block-style ul.jqtree-tree.jqtree-rtl .jqtree-toggler.jqtree-toggler-right {
  margin-left: 0;
  margin-right: 1em;
}

/*# sourceMappingURL=django_mptt_admin.css.map */


================================================
FILE: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.debug.js
================================================
/******/ (() => { // webpackBootstrap
/******/ 	var __webpack_modules__ = ({

/***/ 163
(__unused_webpack_module, exports) {

"use strict";
var __webpack_unused_export__;

__webpack_unused_export__ = ({ value: true });
__webpack_unused_export__ = parseCookie;
exports.qg = parseCookie;
__webpack_unused_export__ = stringifyCookie;
__webpack_unused_export__ = stringifySetCookie;
__webpack_unused_export__ = stringifySetCookie;
__webpack_unused_export__ = parseSetCookie;
__webpack_unused_export__ = stringifySetCookie;
__webpack_unused_export__ = stringifySetCookie;
/**
 * RegExp to match cookie-name in RFC 6265 sec 4.1.1
 * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2
 * which has been replaced by the token definition in RFC 7230 appendix B.
 *
 * cookie-name       = token
 * token             = 1*tchar
 * tchar             = "!" / "#" / "$" / "%" / "&" / "'" /
 *                     "*" / "+" / "-" / "." / "^" / "_" /
 *                     "`" / "|" / "~" / DIGIT / ALPHA
 *
 * Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191
 * Allow same range as cookie value, except `=`, which delimits end of name.
 */
const cookieNameRegExp = /^[\u0021-\u003A\u003C\u003E-\u007E]+$/;
/**
 * RegExp to match cookie-value in RFC 6265 sec 4.1.1
 *
 * cookie-value      = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
 * cookie-octet      = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
 *                     ; US-ASCII characters excluding CTLs,
 *                     ; whitespace DQUOTE, comma, semicolon,
 *                     ; and backslash
 *
 * Allowing more characters: https://github.com/jshttp/cookie/issues/191
 * Comma, backslash, and DQUOTE are not part of the parsing algorithm.
 */
const cookieValueRegExp = /^[\u0021-\u003A\u003C-\u007E]*$/;
/**
 * RegExp to match domain-value in RFC 6265 sec 4.1.1
 *
 * domain-value      = <subdomain>
 *                     ; defined in [RFC1034], Section 3.5, as
 *                     ; enhanced by [RFC1123], Section 2.1
 * <subdomain>       = <label> | <subdomain> "." <label>
 * <label>           = <let-dig> [ [ <ldh-str> ] <let-dig> ]
 *                     Labels must be 63 characters or less.
 *                     'let-dig' not 'letter' in the first char, per RFC1123
 * <ldh-str>         = <let-dig-hyp> | <let-dig-hyp> <ldh-str>
 * <let-dig-hyp>     = <let-dig> | "-"
 * <let-dig>         = <letter> | <digit>
 * <letter>          = any one of the 52 alphabetic characters A through Z in
 *                     upper case and a through z in lower case
 * <digit>           = any one of the ten digits 0 through 9
 *
 * Keep support for leading dot: https://github.com/jshttp/cookie/issues/173
 *
 * > (Note that a leading %x2E ("."), if present, is ignored even though that
 * character is not permitted, but a trailing %x2E ("."), if present, will
 * cause the user agent to ignore the attribute.)
 */
const domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
/**
 * RegExp to match path-value in RFC 6265 sec 4.1.1
 *
 * path-value        = <any CHAR except CTLs or ";">
 * CHAR              = %x01-7F
 *                     ; defined in RFC 5234 appendix B.1
 */
const pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
/**
 * RegExp to match max-age-value in RFC 6265 sec 5.6.2
 */
const maxAgeRegExp = /^-?\d+$/;
const __toString = Object.prototype.toString;
const NullObject = /* @__PURE__ */ (() => {
    const C = function () { };
    C.prototype = Object.create(null);
    return C;
})();
/**
 * Parse a `Cookie` header.
 *
 * Parse the given cookie header string into an object
 * The object has the various cookies as keys(names) => values
 */
function parseCookie(str, options) {
    const obj = new NullObject();
    const len = str.length;
    // RFC 6265 sec 4.1.1, RFC 2616 2.2 defines a cookie name consists of one char minimum, plus '='.
    if (len < 2)
        return obj;
    const dec = options?.decode || decode;
    let index = 0;
    do {
        const eqIdx = eqIndex(str, index, len);
        if (eqIdx === -1)
            break; // No more cookie pairs.
        const endIdx = endIndex(str, index, len);
        if (eqIdx > endIdx) {
            // backtrack on prior semicolon
            index = str.lastIndexOf(";", eqIdx - 1) + 1;
            continue;
        }
        const key = valueSlice(str, index, eqIdx);
        // only assign once
        if (obj[key] === undefined) {
            obj[key] = dec(valueSlice(str, eqIdx + 1, endIdx));
        }
        index = endIdx + 1;
    } while (index < len);
    return obj;
}
/**
 * Stringifies an object into an HTTP `Cookie` header.
 */
function stringifyCookie(cookie, options) {
    const enc = options?.encode || encodeURIComponent;
    const cookieStrings = [];
    for (const name of Object.keys(cookie)) {
        const val = cookie[name];
        if (val === undefined)
            continue;
        if (!cookieNameRegExp.test(name)) {
            throw new TypeError(`cookie name is invalid: ${name}`);
        }
        const value = enc(val);
        if (!cookieValueRegExp.test(value)) {
            throw new TypeError(`cookie val is invalid: ${val}`);
        }
        cookieStrings.push(`${name}=${value}`);
    }
    return cookieStrings.join("; ");
}
function stringifySetCookie(_name, _val, _opts) {
    const cookie = typeof _name === "object"
        ? _name
        : { ..._opts, name: _name, value: String(_val) };
    const options = typeof _val === "object" ? _val : _opts;
    const enc = options?.encode || encodeURIComponent;
    if (!cookieNameRegExp.test(cookie.name)) {
        throw new TypeError(`argument name is invalid: ${cookie.name}`);
    }
    const value = cookie.value ? enc(cookie.value) : "";
    if (!cookieValueRegExp.test(value)) {
        throw new TypeError(`argument val is invalid: ${cookie.value}`);
    }
    let str = cookie.name + "=" + value;
    if (cookie.maxAge !== undefined) {
        if (!Number.isInteger(cookie.maxAge)) {
            throw new TypeError(`option maxAge is invalid: ${cookie.maxAge}`);
        }
        str += "; Max-Age=" + cookie.maxAge;
    }
    if (cookie.domain) {
        if (!domainValueRegExp.test(cookie.domain)) {
            throw new TypeError(`option domain is invalid: ${cookie.domain}`);
        }
        str += "; Domain=" + cookie.domain;
    }
    if (cookie.path) {
        if (!pathValueRegExp.test(cookie.path)) {
            throw new TypeError(`option path is invalid: ${cookie.path}`);
        }
        str += "; Path=" + cookie.path;
    }
    if (cookie.expires) {
        if (!isDate(cookie.expires) || !Number.isFinite(cookie.expires.valueOf())) {
            throw new TypeError(`option expires is invalid: ${cookie.expires}`);
        }
        str += "; Expires=" + cookie.expires.toUTCString();
    }
    if (cookie.httpOnly) {
        str += "; HttpOnly";
    }
    if (cookie.secure) {
        str += "; Secure";
    }
    if (cookie.partitioned) {
        str += "; Partitioned";
    }
    if (cookie.priority) {
        const priority = typeof cookie.priority === "string"
            ? cookie.priority.toLowerCase()
            : undefined;
        switch (priority) {
            case "low":
                str += "; Priority=Low";
                break;
            case "medium":
                str += "; Priority=Medium";
                break;
            case "high":
                str += "; Priority=High";
                break;
            default:
                throw new TypeError(`option priority is invalid: ${cookie.priority}`);
        }
    }
    if (cookie.sameSite) {
        const sameSite = typeof cookie.sameSite === "string"
            ? cookie.sameSite.toLowerCase()
            : cookie.sameSite;
        switch (sameSite) {
            case true:
            case "strict":
                str += "; SameSite=Strict";
                break;
            case "lax":
                str += "; SameSite=Lax";
                break;
            case "none":
                str += "; SameSite=None";
                break;
            default:
                throw new TypeError(`option sameSite is invalid: ${cookie.sameSite}`);
        }
    }
    return str;
}
/**
 * Deserialize a `Set-Cookie` header into an object.
 *
 * deserialize('foo=bar; httpOnly')
 *   => { name: 'foo', value: 'bar', httpOnly: true }
 */
function parseSetCookie(str, options) {
    const dec = options?.decode || decode;
    const len = str.length;
    const endIdx = endIndex(str, 0, len);
    const eqIdx = eqIndex(str, 0, endIdx);
    const setCookie = eqIdx === -1
        ? { name: "", value: dec(valueSlice(str, 0, endIdx)) }
        : {
            name: valueSlice(str, 0, eqIdx),
            value: dec(valueSlice(str, eqIdx + 1, endIdx)),
        };
    let index = endIdx + 1;
    while (index < len) {
        const endIdx = endIndex(str, index, len);
        const eqIdx = eqIndex(str, index, endIdx);
        const attr = eqIdx === -1
            ? valueSlice(str, index, endIdx)
            : valueSlice(str, index, eqIdx);
        const val = eqIdx === -1 ? undefined : valueSlice(str, eqIdx + 1, endIdx);
        switch (attr.toLowerCase()) {
            case "httponly":
                setCookie.httpOnly = true;
                break;
            case "secure":
                setCookie.secure = true;
                break;
            case "partitioned":
                setCookie.partitioned = true;
                break;
            case "domain":
                setCookie.domain = val;
                break;
            case "path":
                setCookie.path = val;
                break;
            case "max-age":
                if (val && maxAgeRegExp.test(val))
                    setCookie.maxAge = Number(val);
                break;
            case "expires":
                if (!val)
                    break;
                const date = new Date(val);
                if (Number.isFinite(date.valueOf()))
                    setCookie.expires = date;
                break;
            case "priority":
                if (!val)
                    break;
                const priority = val.toLowerCase();
                if (priority === "low" ||
                    priority === "medium" ||
                    priority === "high") {
                    setCookie.priority = priority;
                }
                break;
            case "samesite":
                if (!val)
                    break;
                const sameSite = val.toLowerCase();
                if (sameSite === "lax" ||
                    sameSite === "strict" ||
                    sameSite === "none") {
                    setCookie.sameSite = sameSite;
                }
                break;
        }
        index = endIdx + 1;
    }
    return setCookie;
}
/**
 * Find the `;` character between `min` and `len` in str.
 */
function endIndex(str, min, len) {
    const index = str.indexOf(";", min);
    return index === -1 ? len : index;
}
/**
 * Find the `=` character between `min` and `max` in str.
 */
function eqIndex(str, min, max) {
    const index = str.indexOf("=", min);
    return index < max ? index : -1;
}
/**
 * Slice out a value between startPod to max.
 */
function valueSlice(str, min, max) {
    let start = min;
    let end = max;
    do {
        const code = str.charCodeAt(start);
        if (code !== 0x20 /*   */ && code !== 0x09 /* \t */)
            break;
    } while (++start < end);
    while (end > start) {
        const code = str.charCodeAt(end - 1);
        if (code !== 0x20 /*   */ && code !== 0x09 /* \t */)
            break;
        end--;
    }
    return str.slice(start, end);
}
/**
 * URL-decode string value. Optimized to skip native call when no %.
 */
function decode(str) {
    if (str.indexOf("%") === -1)
        return str;
    try {
        return decodeURIComponent(str);
    }
    catch (e) {
        return str;
    }
}
/**
 * Determine if value is a Date.
 */
function isDate(val) {
    return __toString.call(val) === "[object Date]";
}
//# sourceMappingURL=index.js.map

/***/ },

/***/ 751
() {

/*
JqTree 1.8.11

Copyright 2026 Marco Braak

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@license

*/
var 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}({});
//# sourceMappingURL=tree.jquery.js.map


/***/ }

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
(() => {
"use strict";

// EXTERNAL MODULE: ./node_modules/.pnpm/cookie@1.1.1/node_modules/cookie/dist/index.js
var dist = __webpack_require__(163);
// EXTERNAL MODULE: ./node_modules/.pnpm/jqtree@1.8.11_jquery@4.0.0/node_modules/jqtree/tree.jquery.js
var tree_jquery = __webpack_require__(751);
;// ./src/initTree.ts


function initTree($tree, {
  animationSpeed,
  autoEscape,
  autoOpen,
  csrfCookieName,
  dragAndDrop,
  hasAddPermission,
  hasChangePermission,
  mouseDelay,
  rtl
}) {
  let errorNode = null;
  const baseUrl = "http://example.com";
  const insertAtUrl = new URL($tree.data("insert_at_url"), baseUrl);
  function createLi(node, $li, isSelected) {
    if (node.id == null) {
      return;
    }

    // Create edit link
    const $title = $li.find(".jqtree-title");
    insertAtUrl.searchParams.set("insert_at", node.id.toString());
    const insertUrlString = insertAtUrl.toString().substring(baseUrl.length);
    const tabindex = isSelected ? "0" : "-1";
    const editCaption = hasChangePermission ? gettext("edit") : gettext("view");
    $title.after(`<a href="${node.url}" class="edit" tabindex="${tabindex}">(${editCaption})</a>`, hasAddPermission ? `<a href="${insertUrlString}" class="edit" tabindex="${tabindex}">(${gettext("add")})</a>` : "");
  }
  function getCsrfToken() {
    function getFromMiddleware() {
      const inputElement = document.querySelector('[name="csrfmiddlewaretoken"]');
      return inputElement?.value;
    }
    function getFromCookie() {
      if (!csrfCookieName) {
        return null;
      } else {
        return dist/* parse */.qg(document.cookie)[csrfCookieName];
      }
    }
    return getFromCookie() ?? getFromMiddleware() ?? "";
  }
  function handleMove(eventParam) {
    const e = eventParam;
    const info = e.move_info;
    if (!info.moved_node.element) {
      return;
    }
    const $el = jQuery(info.moved_node.element);
    const data = {
      position: info.position,
      target_id: info.target_node.id
    };
    handleLoading(null);
    removeErrorMessage();
    e.preventDefault();
    void jQuery.ajax({
      beforeSend: xhr => {
        // Set Django csrf token
        xhr.setRequestHeader("X-CSRFToken", getCsrfToken());
      },
      data,
      error: () => {
        handleLoaded(null);
        const $node = $el.find(".jqtree-element");
        $node.append(`<span class="mptt-admin-error">${gettext("move failed")}</span>`);
        errorNode = info.moved_node;
      },
      success: () => {
        info.do_move();
        handleLoaded(null);
      },
      type: "POST",
      url: info.moved_node.move_url
    });
    function removeErrorMessage() {
      if (errorNode?.element) {
        jQuery(errorNode.element).find(".mptt-admin-error").remove();
        errorNode = null;
      }
    }
  }
  function handleLoadFailed() {
    $tree.html(gettext("Error while loading the data from the server"));
  }
  const spinners = {};
  function getSpinnerId(node) {
    if (!node) {
      return "__root__";
    } else {
      if (node.id == null) {
        return null;
      } else {
        return node.id;
      }
    }
  }
  function handleLoading(node) {
    function getContainer() {
      if (node) {
        return node.element;
      } else {
        return $tree.get(0);
      }
    }
    const container = getContainer();
    const spinnerId = getSpinnerId(node);
    if (!container || spinnerId == null) {
      return;
    }
    const spinner = document.createElement("span");
    spinner.className = "jqtree-spin";
    container.append(spinner);
    spinners[spinnerId] = spinner;
  }
  function handleLoaded(node) {
    const spinnerId = getSpinnerId(node);
    if (spinnerId == null) {
      return;
    }
    const spinner = spinners[spinnerId];
    if (spinner) {
      spinner.remove();
    }
  }
  function handleSelect(eventParam) {
    const e = eventParam;
    const {
      deselected_node,
      node
    } = e;
    if (deselected_node?.element) {
      // deselected node: remove tabindex
      jQuery(deselected_node.element).find(".edit").attr("tabindex", -1);
    }

    // selected: add tabindex
    if (node.element) {
      jQuery(node.element).find(".edit").attr("tabindex", 0);
    }
  }
  function handleLoadingEvent(e) {
    const {
      isLoading,
      node
    } = e;
    if (isLoading) {
      handleLoading(node);
    }
  }
  function handleLoadDataEvent(e) {
    const {
      parent_node
    } = e;
    handleLoaded(parent_node);
  }
  const treeOptions = {
    autoEscape,
    autoOpen,
    buttonLeft: rtl,
    closedIcon: rtl ? "&#x25c0;" : "&#x25ba;",
    dragAndDrop: dragAndDrop && hasChangePermission,
    onCreateLi: createLi,
    onLoadFailed: handleLoadFailed,
    saveState: $tree.data("save_state"),
    useContextMenu: Boolean($tree.data("use_context_menu"))
  };
  if (animationSpeed !== null) {
    treeOptions.animationSpeed = animationSpeed;
  }
  if (mouseDelay != null) {
    treeOptions.startDndDelay = mouseDelay;
  }
  $tree.on("tree.loading_data", handleLoadingEvent);
  $tree.on("tree.load_data", handleLoadDataEvent);
  $tree.on("tree.move", handleMove);
  $tree.on("tree.select", handleSelect);
  $tree.tree(treeOptions);
}
/* harmony default export */ const src_initTree = (initTree);
;// ./src/djangoMpttAdmin.ts

jQuery(() => {
  const $tree = jQuery("#tree");
  if ($tree.length) {
    const animationSpeed = $tree.data("tree-animation-speed");
    const autoOpen = $tree.data("auto_open");
    const autoEscape = Boolean($tree.data("autoescape"));
    const hasAddPermission = Boolean($tree.data("has-add-permission"));
    const hasChangePermission = Boolean($tree.data("has-change-permission"));
    const mouseDelay = $tree.data("tree-mouse-delay");
    const dragAndDrop = $tree.data("drag-and-drop");
    const rtl = $tree.data("rtl") === "1";
    const csrfCookieName = $tree.data("csrf-cookie-name");
    src_initTree($tree, {
      animationSpeed,
      autoEscape,
      autoOpen,
      csrfCookieName,
      dragAndDrop,
      hasAddPermission,
      hasChangePermission,
      mouseDelay,
      rtl
    });
  }
});
})();

/******/ })()
;
//# sourceMappingURL=django_mptt_admin.debug.js.map

================================================
FILE: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.debug.js.LICENSE.txt
================================================
/*
JqTree 1.8.10

Copyright 2025 Marco Braak

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@license

*/


================================================
FILE: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js
================================================
/*! For license information please see django_mptt_admin.js.LICENSE.txt */
(()=>{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})}})})()})();
//# sourceMappingURL=django_mptt_admin.js.map

================================================
FILE: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js.LICENSE.txt
================================================
/*
JqTree 1.8.11

Copyright 2026 Marco Braak

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@license

*/


================================================
FILE: django_mptt_admin/static/django_mptt_admin/jquery_namespace.js
================================================
window.$ = django.jQuery;
window.jQuery = django.jQuery;


================================================
FILE: django_mptt_admin/templates/django_mptt_admin/change_list.html
================================================
{% extends 'admin/change_list.html' %}
{% load i18n admin_list static javascript_value %}

{% block extrastyle %}
    {{ block.super }}
    <script type="text/javascript" src="{{ jsi18n_url }}"></script>
{% endblock %}

{% block extrahead %}
    {{ block.super }}
    {% if django_major_version >= 4 %}
        <script src="{% static 'admin/js/filters.js' %}" defer></script>
    {% endif %}
{% endblock %}

{% block search %}{% endblock %}

{% block result_list %}
    <div
        id="tree"
        class="block-style"
        data-auto_open="{{ tree_auto_open|javascript_value }}"
        data-autoescape="{{ autoescape|javascript_value }}"
        data-csrf-cookie-name="{{ csrf_cookie_name }}"
        data-insert_at_url="{{ insert_at_url }}"
        data-drag-and-drop="{{ drag_and_drop|javascript_value }}"
        data-has-add-permission="{{ has_add_permission|javascript_value }}"
        data-has-change-permission="{{ has_change_permission|javascript_value }}"
        {% if LANGUAGE_BIDI %}
            data-rtl
        {% endif %}
        data-save_state="{{ app_label }}_{{ model_name }}"
        {% if tree_animation_speed is not None %}
            data-tree-animation-speed="{{ tree_animation_speed|javascript_value }}"
        {% endif %}
        {% if tree_mouse_delay is not None %}
            data-tree-mouse-delay="{{ tree_mouse_delay|javascript_value }}"
        {% endif %}
        data-url="{{ tree_json_url }}"
        data-use_context_menu="{{ use_context_menu|javascript_value }}"
    ></div>
{% endblock %}

{% block pagination %}{% endblock %}

{% block object-tools-items %}
    {{ block.super }}
    <li>
        <a href="{{ grid_url }}">{% trans "Grid view" %}</a>
    </li>
{% endblock %}


================================================
FILE: django_mptt_admin/templates/django_mptt_admin/grid_view.html
================================================
{% extends 'admin/change_list.html' %}
{% load i18n %}

{% block object-tools-items %}
{{ block.super }}
<li>
    <a href="{{ tree_url }}">{% trans "Tree view" %}</a>
</li>
{% endblock %}


================================================
FILE: django_mptt_admin/templatetags/__init__.py
================================================


================================================
FILE: django_mptt_admin/templatetags/javascript_value.py
================================================
import json
from django import template

register = template.Library()


@register.filter
def javascript_value(value):
    """
    Get javascript value for python value.

    >>> get_javascript_value(True)
    true
    >>> get_javascript_value(10)
    10
    """
    if isinstance(value, bool):
        if value:
            return "true"
        else:
            return "false"
    else:
        return json.dumps(value)


================================================
FILE: django_mptt_admin/tree_change_list.py
================================================
from django.contrib.admin.views.main import ChangeList
import django

from . import util


class TreeChangeList(ChangeList):
    TREE_IGNORED_PARAMS = ("_", "node", "selected_node")

    def __init__(self, request, model, model_admin, list_filter, node_id, max_level):
        self.node_id = node_id
        self.max_level = max_level

        params = dict(
            request=request,
            model=model,
            list_display=(),
            list_display_links=(),
            list_filter=list_filter,
            date_hierarchy=None,
            search_fields=(),
            list_select_related=(),
            list_per_page=100,
            list_max_show_all=200,
            list_editable=(),
            model_admin=model_admin,
            sortable_by=[],
        )

        if django.VERSION >= (4, 0):
            params["search_help_text"] = ""

        super().__init__(**params)

    def get_filters_params(self, params=None):
        params = super().get_filters_params()

        lookup_params = params.copy()

        for ignored in self.TREE_IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        return lookup_params

    def get_queryset(self, request, exclude_parameters=None):
        (
            self.filter_specs,
            self.has_filters,
            remaining_lookup_params,
            filters_may_have_duplicates,
            self.has_active_filters,
        ) = self.get_filters(request)

        qs = util.get_tree_queryset(
            model=self.model,
            node_id=self.node_id,
            max_level=self.max_level,
        )

        for filter_spec in self.filter_specs:
            new_qs = filter_spec.queryset(request, qs)
            if new_qs is not None:
                qs = new_qs

        self.clear_all_filters_qs = self.get_query_string(
            new_params=remaining_lookup_params,
            remove=self.get_filters_params(),
        )

        return qs


================================================
FILE: django_mptt_admin/util.py
================================================
def serialize_id(pk):
    if isinstance(pk, (int, str)):
        return pk
    else:
        # Nb. special case for uuid field
        return str(pk)


def get_tree_from_queryset(
    queryset, on_create_node=None, max_level=None, item_label_field_name=None
):
    """
    Return tree data that is suitable for jqTree.
    The queryset must be sorted by 'tree_id' and 'left' fields.
    """
    pk_attname = queryset.model._meta.pk.attname

    # Result tree
    tree = []

    # Dict of all nodes; used for building the tree
    # - key is node id
    # - value is node info (label, id)
    node_dict = dict()

    # The lowest level of the tree; used for building the tree
    # - Initial value is None; set later
    # - For the whole tree this is 0, for a subtree this is higher
    min_level = None

    for instance in queryset:
        if min_level is None or instance.level < min_level:
            min_level = instance.level

        pk = getattr(instance, pk_attname)

        if item_label_field_name:
            label = getattr(instance, item_label_field_name)
        else:
            label = str(instance)

        node_info = dict(name=label, id=serialize_id(pk))
        if on_create_node:
            on_create_node(instance, node_info)

        if max_level is not None and not instance.is_leaf_node():
            # If there is a maximum level and this node has children, then initially set property 'load_on_demand' to true.
            node_info["load_on_demand"] = True

        if instance.level == min_level:
            # This is the lowest level. Skip finding a parent.
            # Add node to the tree
            tree.append(node_info)
        else:
            # NB: use instance's local value for parent attribute - consistent values for uuid
            parent_field = instance._meta.get_field(instance._mptt_meta.parent_attr)
            parent_attname = parent_field.get_attname()
            parent_id = getattr(instance, parent_attname)

            # Get parent from node dict
            parent_info = node_dict.get(parent_id)

            # Check for corner case: parent is deleted.
            if parent_info:
                if "children" not in parent_info:
                    parent_info["children"] = []

                # Add node to the tree
                parent_info["children"].append(node_info)

                # If there is a maximum level, then reset property 'load_on_demand' for parent
                if max_level is not None:
                    parent_info["load_on_demand"] = False

        # Update node dict
        node_dict[pk] = node_info

    return tree


def get_tree_queryset(model, node_id=None, max_level=None, include_root=True):
    if node_id:
        node = model.objects.get(pk=node_id)

        if max_level is None:
            max_level = node.level + 1

        qs = node.get_descendants().filter(level__lte=max_level)
    else:
        qs = model._default_manager.all()

        if max_level is True:
            max_level = 1

        if isinstance(max_level, int) and max_level is not False:
            qs = qs.filter(level__lte=max_level)

        if not include_root:
            qs = qs.exclude(level=0)

    return qs.order_by("tree_id", "lft")


def get_model_name(model):
    """
    Get the name of a Django model

    >>> get_model_name(Country)
    country
    """
    return model._meta.model_name


================================================
FILE: docs/index.md
================================================
# Django Mptt Admin

_Django-mptt-admin_ provides a nice Django Admin interface for [django-mptt models](http://django-mptt.github.io/django-mptt/).

- The source is available on [https://github.com/mbraak/django-mptt-admin](https://github.com/mbraak/django-mptt-admin).
- Documentation is available on [https://mbraak.github.io/django-mptt-admin/](https://mbraak.github.io/django-mptt-admin/).

![Screenshot](https://raw.github.com/mbraak/django-mptt-admin/master/screenshot.png)

## Requirements

The package is tested with Django (4.2, 5.2 and 6.0), and django-mptt (0.18). Also with Python 3.10 - 3.14.

Older versions:

- Version 2.5.x supports Django 4.1.
- Version 2.7.x supports Django 5.0.
- Version 2.8.x supports Django 5.1.

## Installation

Install the package:

```
$ pip install django-mptt-admin
```

Add **django_mptt_admin** to your installed apps in **settings.py**.

```python
  INSTALLED_APPS = (
      ..
      'django_mptt_admin',
  )
```

Use the DjangoMpttAdmin class in admin.py:

```python
    from django.contrib import admin
    from django_mptt_admin.admin import DjangoMpttAdmin
    from models import Country

    class CountryAdmin(DjangoMpttAdmin):
        pass

    admin.site.register(Country, CountryAdmin)
```

## Options

**tree_animation_speed**

The speed of the open/close animation in milliseconds. The default is 200 milliseconds.

**tree_auto_open**

Auto-open node. Default value is 1.

Values:

- **True**: autopen all nodes
- **False**: do not autoopen
- **integer**: autopen until this level

**tree_load_on_demand**

Load on demand (True / False / level). Default is True.

- **True**: load nodes on demand
- **False**: do not load nodes on demand
- **int**: load nodes on demand until this level

**autoescape**

Autoescape (True / False). Default is True.

Autoescape titles in tree.

**filter_tree_queryset**

Override the **filter_tree_queryset** method to filter the queyset for the tree.

```python
class CountryAdmin(DjangoMpttAdmin):
  def filter_tree_queryset(self, queryset):
    return queryset.filter(name='abc')
```

**is_drag_and_drop_enabled**

Override the **is_drag_and_drop_enabled** method to disable drag-and-drop. By default drag-and-drop is enabled.

```python
class CountryAdmin(DjangoMpttAdmin):
  def is_drag_and_drop_enabled(self):
    return False
```

**use_context_menu**

Capture the contextmenu event. NB: the contextmenu event is triggered when you click with the right mouse button.

- True: Capture the contextmenu event.
  - This is useful if you want to write custom javascript to catch the `tree.contextmenu` event.
  - Also see https://mbraak.github.io/jqTree/#usecontextmenu and https://mbraak.github.io/jqTree/#event-tree-contextmenu
- False (default): do not capture the contextmenu event.

**item_label_field_name**

Define which field of the model should be the label for tree items.

Possible values are:

- string: name of the model field or model property method to use as tree items label
- None (default): model unicode used ad tree item label

Example:

```python
class MyMpttModel(MPTTModel):
    title = models.CharField(......

    @property
    def title_for_admin(self):
          return '%s %s' % (self.pk, self.title)

class MyMpttModelAdminClass(MPTTModelAdmin):
    item_label_field_name = 'title_for_admin'
```

## Filters

If 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).

```python
from django_mptt_admin.admin import DjangoMpttAdmin

class CountryAdmin(DjangoMpttAdmin):
    list_filter = ('continent',)
```

Also see the example project for a complete continent filter.

## Changelog

**2.9.0** (december 2025)

- Support Django 6.0; drop support for Django 5.1

**2.8.0** (april 7 2025)

- Support Django 5.2; drop support for Django 5.0

**2.7.2** (january 9 2025)

- Issue #605: fix missing map file

**2.7.1** (january 8 2025)

- Issue #604: delay before opening a folder during drag and drop

**2.7.0** (august 13 2024)

- Issue #557: support Django 5.1; drop support for Django 3.2

**2.6.2** (april 13 2024)

- Issue #509: use css for the loading spinner. Support dark mode.
- Issue #541: fix javascript import error in Django 3.2 (thanks to scottp-dpaw)

**2.6.1** (december 9 2023)

- Issue #505: fix collectstatic error

**2.6.0** (december 7 2023)

- Issue #495: support Django 5.0

**2.5.1** (may 6 2023)

- Support dark mode (thanks to Sumit Kumar)

**2.5.0** (april 4 2023)

- Support Django 4.2

**2.4.1** (february 1 2023)

- Issue #431: fix get_tree_mouse_delay error

**2.4.0** (january 31 2023)

- Issue #426: handle permissions:
  - 'Add' link: only display it if the admin user has the 'Add' permission
  - 'Edit' link: only display it if the admin user has the 'Edit' permission
    - Otherwise: still display it but change the text to 'view'
  - Drag and drop: only enable it if the admin user has the 'Edit' permission
    - It's also possible to disable drag and drop by overriding the 'is_drag_and_drop_enabled' method.

**2.3.0** (august 4 2022)

- Update jqtree to 1.6.2. This fixes an issue with the keyboard focus when using on demand loading.
- Support Django 4.1

**2.2.0** (december 8 2021)

- Support Django 4.0

**2.1.0** (april 6 2021)

- Issue #353: support Django 3.2

**2.0.3** (march 1 2021)

- Issue #341: update jqtree to 1.6.0
- Issue #345: add option to disable drag-and-drop (thanks to Maxim Popov)

**2.0.2** (october 27 2020)

- Issue #328: fix DJANGO_MPTT_ADMIN_COVERAGE_JS (thanks to Andrew Kh)

**2.0.1** (october 26 2020)

- Issue #309: add option for animation speed
- Issue #325: update jqtree to 1.5.2

**2.0.0** (august 7 2020)

- Support Django 3.1

**1.0.2** (june 26 2020)

- Issue #287: add Catalan and Spanish translations (thanks to Joan Marc Soler)

**1.0.1** (february 14 2020)

- Issue #282: add German translations (thanks to Christian Wiegand)
- Issue #284: add Polish translations (thanks to Paweł Chojnowski)

**1.0.0** (december 5 2019)

- Issue #271: support Django 3
- Issue #276: fix movement during drag-and-drop

**0.7.2** (october 19 2019)

- Issue #270: support media class (thanks to Sencer H.)

**0.7.1** (april 23 2019)

- Issue #254: upgrade jqtree to 1.4.10
- Issue #255: test with django-mptt 0.10
- Issue #258: include jqtree.css in django_mptt_admin.css

**0.7.0** (april 5 2019)

- Issue #242: minified build
- Issue #243: upgrade jqTree to 1.4.9
- Issue #252: support Django 2.2

**0.6.0** (august 4 2018)

- Issue #232: support Django 2.1
- Issue #233: upgrade jqTree to 1.4.7

**0.5.1** (april 8 2018)

- Issue #220: upgrade jqTree to 1.4.5
- Issue #224: add a spinner for the move action (thanks to Riccardo Magliocchetti)

**0.5.0** (december 7 2017)

- Issue #217: Support Django 2.0

**0.4.7** (september 29 2017)

- Issue #212: Fix unsafe reference to instance.parent (thanks to John D'Ambrosio)
- Issue #211: Make ChangeList configurable using `change_list_tree_class` (thanks to Riccardo Magliocchetti)

**0.4.6** (june 7 2017)

- Issue #200: Upgrade to jqtree 1.4.1
- Issue #201: Make 'edit' and 'add' buttons not focusable
- Issue #203: 'Add' url path must end with '/'

**0.4.5** (april 5 2017)

- Issue #188: Handle CSRF_COOKIE_NAME option
- Issue #189: Handle Django CSRF_USE_SESSIONS option (new option in Django 1.11)
- Issue #191: Only initialize the tree on the tree page (thanks to Stanislav Zholudev)
- Issue #197: Support Django 1.11

**0.4.4** (january 30 2017)

- Issue #185: Support preserved filters (thanks to Riccardo Magliocchetti)
- Issue #186: Move list_filter option to DjangoMpttAdmin class

**0.4.3** (january 18 2017)

- Issue 178: Added Hungarian translations (thanks to roodie)
- Issue 182: Add option to configure node label (thanks to Claudio Bartolini)
- Issue 183: Update jqtree to 1.3.7

**0.4.2** (november 10 2016)

- Issue 170: Added FilterableDjangoMpttAdmin (thanks to Riccardo Magliocchetti)
- Issue 172: Update jqtree to 1.3.6
- Issue 173: Move translations to djangojs domain
- Issue 174: Added French translations (thanks to Vhotz)
- Issue 175: Fixed: can't move items in tree view with CSRF_COOKIE_HTTPONLY = True (thanks to Vhotz)

**0.4.1** (september 21 2016)

- Issue 162: Add request parameter to filter_tree_queryset signature (thanks to Max Perreault)
- Issue 163: Update to jqtree 1.3.5

**0.4.0** (august 3 2016)

- Issue 152: Django 1.10 support.
  - Drop support for Django 1.7

**0.3.8** (july 27 2016)

- Issue 142: use the Django admin static tag for CSS / Javascript (thanks to Alex Tomkins)
- Issue 143: update jqtree to 1.3.4

**0.3.7** (june 1 2016)

- Issue 132: use MPTTModelAdmin for DjangoMpttAdmin (thanks to Alex Tomkins)
  - MPTTModelAdmin contains fixes for mass deletions and TreeForeignKey
- Issue 139: update to jqtree 1.3.3

**0.3.6** (march 28 2016)

- Issue 125: fix jQuery.cookie error (thanks to Patrick Colmant)

**0.3.5** (march 28 2016)

- Issue 126: add missing jqtree-circle.png (thanks to Generalov)

**0.3.4** (march 25 2016)

- Issue 115: implemented 'add' button (thanks to Andrew Dodd)
- Issue 116: fix block-style layout for right-to-left-languages
- Issue 119: display transparent loading image

**0.3.3** (february 10 2016)

- Issue 112: correctly override media (thanks to Generalov)

**0.3.2** (january 29 2016)

- Issue 103: use jquery from django admin itself
- Issue 105: added Turkish translation (thanks to Tagmat)
- Issue 106: use the same colors as the Django admin
- Issue 109: include locale files in package

**0.3.1** (december 2 2015)

- Issue 82: make admin views easily extendable (thanks to Vsevolod Novikov)
- Issue 93: flat styling
- Issue 95: update jqtree to 1.3.0
- Issue 96: cannot move to the top of the tree
- Issue 97: support Django 1.9

**0.3.0** (august 21 2015)

- Issue 67: update jqtree to 1.2.1
- Issue 68: drop support for Django 1.6 and older
  - Note that version 0.2.1 supports these versions.
- Issue 71: added use_context_menu option (thanks to ITCase)
- Issue 75: added Russian translation (thanks to Mike Silonov)
- Issue 80: fix wrong url resolving with multiple admin sites (thanks to Hubert Bielenia)

**0.2.1** (march 29 2015)

- Issue 65: support Django 1.8

**0.2.0** (january 12 2015)

- Issue 23: fixed save-state for load-on-demand
- Issue 35: fixed auto-open for load-on-demand
- Issue 40: use jqtree 1.0.0
- Issue 45: added i18n support and Hebrew translation (thanks to Udi Oron)
- Issue 47: added filter_tree_queryset method

**0.1.10** (september 24 2014)

- Issue 31: added autoescape option
- Issue 34: use the default change list in popup mode (thanks to hstanev)
- Issue 36: the option tree_load_on_demand = False does not work

**0.1.9** (july 12 2014)

- Issue 25: update jqtree to 0.21.0
- Issue 28: fixing problems related to working with model's pk-field, named other than "id" (thanks to Igor Gai)
- Issue 29: fix path to spinner.gif (thanks to Igor Gai)

**0.1.8** (februari 2 2014)

- Issue 17: handle error when moving node
- Issue 18: do not use inline javascript
- Issue 19: support Django 1.7 alpha

**0.1.7** (january 3 2014)

- Issue 16: moving a node fails if the node id is a uuid

**0.1.6** (october 10 2013)

- Issue 8: removing node from the tree causes the tree view to crash

**0.1.5** (august 27 2013)

- Issue 6: save the tree state
- Issue 7: do not handle the right mouse click

**0.1.4** (august 8 2013)

- Issue 5: Support for uuid ids

**0.1.3** (may 2 2013)

_This version drops support for Django 1.3.7_

- Issue 2: Posting a screenshot in the readme would be really useful (thanks to Andy Baker)
- Issue 3: Use static templatetag for CDN-compatible file paths (thanks to Alex Holmes)
- Added [Coveralls](https://coveralls.io/r/mbraak/django-mptt-admin) support

**0.1.2** (march 12 2013)

- Issue 1: Grid view doesn't link correctly to object change pages (thanks to Kris Fields)

**0.1.1** (februari 25 2013)

- Added experimental Python 3 support

**0.1** (februari 7 2013)

- Initial version

[![Code Issues](https://www.quantifiedcode.com/api/v1/project/dd888e7a1804465798821f28717af384/badge.svg)](https://www.quantifiedcode.com/app/project/dd888e7a1804465798821f28717af384)


================================================
FILE: example_project/django_mptt_example/__init__.py
================================================


================================================
FILE: example_project/django_mptt_example/admin.py
================================================
from django.contrib import admin
from django.conf import settings

from django_mptt_admin.admin import DjangoMpttAdmin

from .models import Country


class ContinentFilter(admin.SimpleListFilter):
    title = "continent"
    parameter_name = "continent"

    def lookups(self, request, model_admin):
        continents = Country.objects.filter(level=1).order_by("name")

        return [(c.name, c.name) for c in continents]

    def queryset(self, request, queryset):
        value = self.value()

        if not value:
            return queryset
        else:
            continent = Country.objects.get(name=value, level=1)

            return continent.get_descendants(include_self=True)


class CountryAdmin(DjangoMpttAdmin):
    tree_auto_open = 0
    list_display = ("code", "name")
    ordering = ("name",)
    list_filter = (ContinentFilter,)

    def has_change_permission(self, request, obj=None):
        return request.user.is_superuser

    def get_tree_mouse_delay(self):
        if getattr(settings, "DJANGO_TESTING", False):
            return 0
        else:
            return None


# Display the code for countries instead of the name.
class CountryCodeAdmin(CountryAdmin):
    item_label_field_name = "code_or_name"


# Display a title with html
class CountryWithHtmlAdmin(CountryAdmin):
    autoescape = False
    item_label_field_name = "html_code_and_name"


class CountryCode(Country):
    class Meta:
        proxy = True


class CountryCodeAndName(Country):
    class Meta:
        proxy = True


admin.site.register(Country, CountryAdmin)
admin.site.register(CountryCode, CountryCodeAdmin)
admin.site.register(CountryCodeAndName, CountryWithHtmlAdmin)


================================================
FILE: example_project/django_mptt_example/fixtures/countries.json
================================================
[{"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}},
Download .txt
gitextract_r07_re3i/

├── .coveragerc
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       ├── codeql-analysis.yml
│       └── mkdocs.yml
├── .gitignore
├── LICENSE.rst
├── MANIFEST.in
├── README.md
├── coverage/
│   ├── .nycrc.json
│   └── package.json
├── cspell.json
├── django_mptt_admin/
│   ├── __init__.py
│   ├── admin.py
│   ├── django_mptt_admin_mixin.py
│   ├── locale/
│   │   ├── ca/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── de/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── es/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── fr/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── he/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── hu/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── pl/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   ├── ru/
│   │   │   └── LC_MESSAGES/
│   │   │       ├── django.mo
│   │   │       ├── django.po
│   │   │       ├── djangojs.mo
│   │   │       └── djangojs.po
│   │   └── tr/
│   │       └── LC_MESSAGES/
│   │           ├── django.mo
│   │           ├── django.po
│   │           ├── djangojs.mo
│   │           └── djangojs.po
│   ├── static/
│   │   └── django_mptt_admin/
│   │       ├── django_mptt_admin.css
│   │       ├── django_mptt_admin.debug.js
│   │       ├── django_mptt_admin.debug.js.LICENSE.txt
│   │       ├── django_mptt_admin.js
│   │       ├── django_mptt_admin.js.LICENSE.txt
│   │       └── jquery_namespace.js
│   ├── templates/
│   │   └── django_mptt_admin/
│   │       ├── change_list.html
│   │       └── grid_view.html
│   ├── templatetags/
│   │   ├── __init__.py
│   │   └── javascript_value.py
│   ├── tree_change_list.py
│   └── util.py
├── docs/
│   └── index.md
├── example_project/
│   ├── django_mptt_example/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── fixtures/
│   │   │   └── countries.json
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_alter_country_level_alter_country_lft_and_more.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── base_playwright_testcase.py
│   │       ├── base_view_testcase.py
│   │       ├── playwright_page.py
│   │       ├── test_playwright.py
│   │       ├── test_util.py
│   │       ├── test_views.py
│   │       └── utils.py
│   ├── example_project/
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   └── urls.py
│   ├── import_test_data
│   ├── manage.py
│   ├── requirements_all.txt
│   ├── requirements_ci.txt
│   ├── requirements_example.txt
│   ├── requirements_test.txt
│   ├── run_coverage
│   └── run_tests
├── frontend/
│   ├── .babelrc
│   ├── .editorconfig
│   ├── django_mptt_admin.scss
│   ├── eslint.config.mjs
│   ├── package.json
│   ├── src/
│   │   ├── djangoMpttAdmin.ts
│   │   ├── global.d.ts
│   │   ├── initTree.test.ts
│   │   ├── initTree.ts
│   │   └── vitestSetup.ts
│   ├── tsconfig.json
│   ├── vitest.config.ts
│   └── webpack.config.js
├── mkdocs.yml
├── requirements_docs.txt
├── setup.cfg
├── setup.py
└── tox.ini
Download .txt
SYMBOL INDEX (155 symbols across 20 files)

FILE: django_mptt_admin/admin.py
  class DjangoMpttAdmin (line 6) | class DjangoMpttAdmin(DjangoMpttAdminMixin, MPTTModelAdmin):
  class FilterableDjangoMpttAdmin (line 10) | class FilterableDjangoMpttAdmin(DjangoMpttAdmin):

FILE: django_mptt_admin/django_mptt_admin_mixin.py
  class DjangoMpttAdminMixin (line 24) | class DjangoMpttAdminMixin:
    method changelist_view (line 49) | def changelist_view(
    method get_urls (line 127) | def get_urls(self: Union[ModelAdmin, "DjangoMpttAdminMixin"]):
    method get_tree_media (line 165) | def get_tree_media(self: ModelAdmin):
    method move_view (line 185) | def move_view(self: Union[ModelAdmin, "DjangoMpttAdminMixin"], request...
    method do_move (line 203) | def do_move(self, instance, position, target_instance):
    method get_change_list_for_tree (line 216) | def get_change_list_for_tree(
    method get_admin_url (line 233) | def get_admin_url(self: ModelAdmin, name, args=None):
    method get_tree_data (line 240) | def get_tree_data(
    method tree_json_view (line 269) | def tree_json_view(self: Union[ModelAdmin, "DjangoMpttAdminMixin"], re...
    method grid_view (line 292) | def grid_view(
    method get_preserved_filters (line 310) | def get_preserved_filters(self: Union[ModelAdmin, "DjangoMpttAdminMixi...
    method filter_tree_queryset (line 336) | def filter_tree_queryset(self, queryset, request):
    method get_changeform_initial_data (line 342) | def get_changeform_initial_data(
    method get_insert_at_field (line 354) | def get_insert_at_field(self):
    method is_drag_and_drop_enabled (line 357) | def is_drag_and_drop_enabled(self) -> bool:
    method get_tree_mouse_delay (line 361) | def get_tree_mouse_delay(self):

FILE: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.debug.js
  method 163 (line 4) | 163
  method 751 (line 362) | 751
  function __webpack_require__ (line 396) | function __webpack_require__(moduleId) {
  function initTree (line 429) | function initTree($tree, {

FILE: django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js
  method 163 (line 2) | 163(e,t){"use strict";t.qg=function(e,t){const l=new o,a=e.length;if(a<2...
  method 751 (line 2) | 751(){!function(){"use strict";class e{constructor({dataFilter:e,loadDat...
  function o (line 2) | function o(n){var s=t[n];if(void 0!==s)return s.exports;var r=t[n]={expo...
  function g (line 2) | function g(e){return e?null==e.id?null:e.id:"__root__"}
  function p (line 2) | function p(e){const o=e?e.element:t.get(0),n=g(e);if(!o||null==n)return;...
  function f (line 2) | function f(e){const t=g(e);if(null==t)return;const o=m[t];o&&o.remove()}

FILE: django_mptt_admin/templatetags/javascript_value.py
  function javascript_value (line 8) | def javascript_value(value):

FILE: django_mptt_admin/tree_change_list.py
  class TreeChangeList (line 7) | class TreeChangeList(ChangeList):
    method __init__ (line 10) | def __init__(self, request, model, model_admin, list_filter, node_id, ...
    method get_filters_params (line 35) | def get_filters_params(self, params=None):
    method get_queryset (line 46) | def get_queryset(self, request, exclude_parameters=None):

FILE: django_mptt_admin/util.py
  function serialize_id (line 1) | def serialize_id(pk):
  function get_tree_from_queryset (line 9) | def get_tree_from_queryset(
  function get_tree_queryset (line 81) | def get_tree_queryset(model, node_id=None, max_level=None, include_root=...
  function get_model_name (line 104) | def get_model_name(model):

FILE: example_project/django_mptt_example/admin.py
  class ContinentFilter (line 9) | class ContinentFilter(admin.SimpleListFilter):
    method lookups (line 13) | def lookups(self, request, model_admin):
    method queryset (line 18) | def queryset(self, request, queryset):
  class CountryAdmin (line 29) | class CountryAdmin(DjangoMpttAdmin):
    method has_change_permission (line 35) | def has_change_permission(self, request, obj=None):
    method get_tree_mouse_delay (line 38) | def get_tree_mouse_delay(self):
  class CountryCodeAdmin (line 46) | class CountryCodeAdmin(CountryAdmin):
  class CountryWithHtmlAdmin (line 51) | class CountryWithHtmlAdmin(CountryAdmin):
  class CountryCode (line 56) | class CountryCode(Country):
    class Meta (line 57) | class Meta:
  class CountryCodeAndName (line 61) | class CountryCodeAndName(Country):
    class Meta (line 62) | class Meta:

FILE: example_project/django_mptt_example/migrations/0001_initial.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: example_project/django_mptt_example/migrations/0002_alter_country_level_alter_country_lft_and_more.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: example_project/django_mptt_example/models.py
  class Country (line 7) | class Country(MPTTModel):
    class Meta (line 8) | class Meta:
    method __str__ (line 18) | def __str__(self):
    method code_or_name (line 23) | def code_or_name(self):
    method html_code_and_name (line 29) | def html_code_and_name(self):

FILE: example_project/django_mptt_example/tests/base_playwright_testcase.py
  class BasePlaywrightTestCase (line 6) | class BasePlaywrightTestCase(LiveServerTestCase):
    method setUp (line 7) | def setUp(self):
    method tearDown (line 13) | def tearDown(self):
    method setup_page (line 22) | def setup_page(self):

FILE: example_project/django_mptt_example/tests/base_view_testcase.py
  class BaseViewTestCase (line 5) | class BaseViewTestCase(WebTest):
    method create_test_user (line 8) | def create_test_user(self):
    method setUp (line 11) | def setUp(self):
    method login (line 17) | def login(self):

FILE: example_project/django_mptt_example/tests/playwright_page.py
  class PlaywrightPage (line 6) | class PlaywrightPage:
    method __init__ (line 7) | def __init__(self, live_server_url):
    method abort_requests (line 14) | def abort_requests(self):
    method reset_abort_requests (line 17) | def reset_abort_requests(self):
    method add_node (line 20) | def add_node(self, parent_title):
    method close (line 24) | def close(self):
    method close_node (line 28) | def close_node(self, title):
    method drag_and_drop (line 31) | def drag_and_drop(self, from_title, to_title):
    method edit_node (line 46) | def edit_node(self, title):
    method find_edit_link (line 50) | def find_edit_link(self, node_title, link_title):
    method find_input (line 58) | def find_input(self, name):
    method find_link (line 61) | def find_link(self, label):
    method find_node_element (line 64) | def find_node_element(self, title) -> ElementHandle:
    method find_title_element (line 81) | def find_title_element(self, title) -> ElementHandle:
    method find_toggler (line 86) | def find_toggler(self, node_element: ElementHandle) -> ElementHandle:
    method grid_view (line 91) | def grid_view(self):
    method login (line 95) | def login(self, username, password):
    method node_titles (line 107) | def node_titles(self):
    method open_node (line 110) | def open_node(self, title):
    method save_coverage (line 119) | def save_coverage(self):
    method save_form (line 131) | def save_form(self):
    method select_node (line 135) | def select_node(self, title):
    method selected_node (line 138) | def selected_node(self):
    method toggle_node (line 143) | def toggle_node(self, title):
    method tree_view (line 148) | def tree_view(self):
    method visit_countries_page (line 152) | def visit_countries_page(self, expected_text="Select country to change"):
    method visit_country_codes_page (line 158) | def visit_country_codes_page(self, expected_text="Select country code ...
    method visit_country_codes_and_names_page (line 164) | def visit_country_codes_and_names_page(
    method wait_for_node (line 172) | def wait_for_node(self, title):
    method wait_for_text (line 175) | def wait_for_text(self, text):

FILE: example_project/django_mptt_example/tests/test_playwright.py
  class PlaywrightTestCase (line 9) | class PlaywrightTestCase(BasePlaywrightTestCase):
    method setUp (line 12) | def setUp(self):
    method test_display_tree (line 17) | def test_display_tree(self):
    method test_select_node (line 38) | def test_select_node(self):
    method test_open_node (line 53) | def test_open_node(self):
    method test_grid_view (line 59) | def test_grid_view(self):
    method test_save_state (line 65) | def test_save_state(self):
    method test_edit (line 77) | def test_edit(self):
    method test_add (line 90) | def test_add(self):
    method test_move_node (line 105) | def test_move_node(self):
    method test_move_node_error (line 125) | def test_move_node_error(self):
    method test_load_error (line 136) | def test_load_error(self):
  class PlaywrightCountryCodeAdminTestCase (line 147) | class PlaywrightCountryCodeAdminTestCase(BasePlaywrightTestCase):
    method setUp (line 150) | def setUp(self):
    method test_display_tree (line 155) | def test_display_tree(self):
  class PlaywrightCountryCodeAndNameAdminTestCase (line 167) | class PlaywrightCountryCodeAndNameAdminTestCase(BasePlaywrightTestCase):
    method setUp (line 170) | def setUp(self):
    method test_display_tree (line 175) | def test_display_tree(self):
  class PlaywrightReadonlyTestCase (line 186) | class PlaywrightReadonlyTestCase(BasePlaywrightTestCase):
    method setUp (line 189) | def setUp(self):
    method test_display_tree (line 200) | def test_display_tree(self):

FILE: example_project/django_mptt_example/tests/test_util.py
  class GetQuerySetTestCase (line 13) | class GetQuerySetTestCase(TestCase):
    method test_default (line 16) | def test_default(self):
    method test_subtree (line 21) | def test_subtree(self):
    method test_max_level_1 (line 26) | def test_max_level_1(self):
    method test_max_level_true (line 31) | def test_max_level_true(self):
    method test_exclude_root (line 35) | def test_exclude_root(self):
  class GetTreeFromQuerySetTestCase (line 41) | class GetTreeFromQuerySetTestCase(TestCase):
    method test_default (line 44) | def test_default(self):
    method test_format_label (line 57) | def test_format_label(self):
  class SerializeIdTestCase (line 67) | class SerializeIdTestCase(TestCase):
    method test (line 77) | def test(self):

FILE: example_project/django_mptt_example/tests/test_views.py
  class MoveTestCase (line 10) | class MoveTestCase(BaseViewTestCase):
    method test_move_inside (line 11) | def test_move_inside(self):
    method test_move_before (line 23) | def test_move_before(self):
    method test_move_after (line 40) | def test_move_after(self):
    method test_move_to_unknown_position (line 51) | def test_move_to_unknown_position(self):
    method move (line 62) | def move(self, source_id, target_id, position):
  class PopupTestCase (line 79) | class PopupTestCase(BaseViewTestCase):
    method test_return_grid_view (line 80) | def test_return_grid_view(self):
  class PermissionsTestCase (line 89) | class PermissionsTestCase(BaseViewTestCase):
    method create_test_user (line 90) | def create_test_user(self):
    method test_no_superuser (line 93) | def test_no_superuser(self):
  class FilterTestCase (line 97) | class FilterTestCase(BaseViewTestCase):
    method test_without_filter (line 98) | def test_without_filter(self):
    method test_filter (line 106) | def test_filter(self):
    method test_filter_and_selected_node (line 120) | def test_filter_and_selected_node(self):
    method test_urls (line 144) | def test_urls(self):
    method test_grid_view (line 159) | def test_grid_view(self):

FILE: example_project/django_mptt_example/tests/utils.py
  function remove_directory (line 8) | def remove_directory(string):  # pragma: no cover
  function write_json (line 20) | def write_json(path, data):
  function get_continents (line 26) | def get_continents():
  function wait_until (line 30) | def wait_until(fn):  # pragma: no cover

FILE: frontend/src/initTree.ts
  type InitTreeOptions (line 4) | interface InitTreeOptions {
  type JQTreeLoadDataEvent (line 16) | interface JQTreeLoadDataEvent extends JQuery.Event {
  type JQTreeLoadingEvent (line 20) | interface JQTreeLoadingEvent extends JQuery.Event {
  type JQTreeMoveEvent (line 25) | interface JQTreeMoveEvent extends JQuery.Event {
  type JQTreeSelectEvent (line 34) | interface JQTreeSelectEvent extends JQuery.Event {
  function initTree (line 39) | function initTree(

FILE: frontend/src/vitestSetup.ts
  type Window (line 5) | interface Window {
Condensed preview — 108 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (302K chars).
[
  {
    "path": ".coveragerc",
    "chars": 225,
    "preview": "[run]\nbranch = True\nomit =\n  example_project/django_mptt_example/tests/base_playwright_testcase.py\n  example_project/dja"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 107,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"pip\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 3218,
    "preview": "name: Continuous integration\n\non: [push]\n\njobs:\n  runner-job:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n  "
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "chars": 624,
    "preview": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [\"master\"]\n  pull_request:\n    branches: [\"master\"]\n\njobs:\n  analyze:\n    name"
  },
  {
    "path": ".github/workflows/mkdocs.yml",
    "chars": 520,
    "preview": "name: Publish docs via GitHub Pages\n\non:\n  push:\n    branches:\n      - master\n      - mkdocs-workflow\n\njobs:\n  build:\n  "
  },
  {
    "path": ".gitignore",
    "chars": 166,
    "preview": ".DS_Store\n*.pyc\ndjango_mptt_admin/static/django_mptt_admin/django_mptt_admin.coverage.js\ndjango_mptt_admin/static/django"
  },
  {
    "path": "LICENSE.rst",
    "chars": 584,
    "preview": "=======\nLICENSE\n=======\n\nCopyright © 2013, Marco Braak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "MANIFEST.in",
    "chars": 176,
    "preview": "include LICENSE.rst\ninclude README.md\nrecursive-include django_mptt_admin/templates *\nrecursive-include django_mptt_admi"
  },
  {
    "path": "README.md",
    "chars": 975,
    "preview": "![Continuous integration](https://github.com/mbraak/django-mptt-admin/workflows/Continuous%20integration/badge.svg) [![V"
  },
  {
    "path": "coverage/.nycrc.json",
    "chars": 35,
    "preview": "{\n  \"exclude-after-remap\": false\n}\n"
  },
  {
    "path": "coverage/package.json",
    "chars": 164,
    "preview": "{\n  \"name\": \"coverage\",\n  \"dependencies\": {\n    \"nyc\": \"^18\"\n  },\n  \"scripts\": {\n    \"merge_coverage\": \"nyc --reporter l"
  },
  {
    "path": "cspell.json",
    "chars": 254,
    "preview": "{\n  \"language\": \"en-GB\",\n  \"words\": [\n    \"Åland\",\n    \"bouvet\",\n    \"countrycode\",\n    \"countrycodeandname\",\n    \"crsf\""
  },
  {
    "path": "django_mptt_admin/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "django_mptt_admin/admin.py",
    "chars": 230,
    "preview": "from mptt.admin import MPTTModelAdmin\n\nfrom .django_mptt_admin_mixin import DjangoMpttAdminMixin\n\n\nclass DjangoMpttAdmin"
  },
  {
    "path": "django_mptt_admin/django_mptt_admin_mixin.py",
    "chars": 12592,
    "preview": "from functools import update_wrapper\nfrom typing import Union\n\nfrom django.conf import settings\nfrom django.templatetags"
  },
  {
    "path": "django_mptt_admin/locale/ca/LC_MESSAGES/django.po",
    "chars": 952,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/ca/LC_MESSAGES/djangojs.po",
    "chars": 1118,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/de/LC_MESSAGES/django.po",
    "chars": 887,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/de/LC_MESSAGES/djangojs.po",
    "chars": 1050,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/es/LC_MESSAGES/django.po",
    "chars": 953,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/es/LC_MESSAGES/djangojs.po",
    "chars": 1121,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/fr/LC_MESSAGES/django.po",
    "chars": 939,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/fr/LC_MESSAGES/djangojs.po",
    "chars": 1052,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/he/LC_MESSAGES/django.po",
    "chars": 504,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2014-11-10 1"
  },
  {
    "path": "django_mptt_admin/locale/he/LC_MESSAGES/djangojs.po",
    "chars": 620,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2014-11-10 1"
  },
  {
    "path": "django_mptt_admin/locale/hu/LC_MESSAGES/django.po",
    "chars": 676,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2016-11-21 1"
  },
  {
    "path": "django_mptt_admin/locale/hu/LC_MESSAGES/djangojs.po",
    "chars": 618,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2016-11-21 1"
  },
  {
    "path": "django_mptt_admin/locale/pl/LC_MESSAGES/django.po",
    "chars": 892,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/pl/LC_MESSAGES/djangojs.po",
    "chars": 1045,
    "preview": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same "
  },
  {
    "path": "django_mptt_admin/locale/ru/LC_MESSAGES/django.po",
    "chars": 580,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-05-21 0"
  },
  {
    "path": "django_mptt_admin/locale/ru/LC_MESSAGES/djangojs.po",
    "chars": 801,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-05-21 0"
  },
  {
    "path": "django_mptt_admin/locale/tr/LC_MESSAGES/django.po",
    "chars": 503,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-01-05 0"
  },
  {
    "path": "django_mptt_admin/locale/tr/LC_MESSAGES/djangojs.po",
    "chars": 625,
    "preview": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: django-mptt-admin\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2015-01-05 0"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.css",
    "chars": 5655,
    "preview": "ul.jqtree-tree {\n  list-style: none outside;\n  margin-left: 0;\n  margin-bottom: 0;\n  padding: 0;\n}\n\nul.jqtree-tree.jqtre"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.debug.js",
    "chars": 67070,
    "preview": "/******/ (() => { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 163\n(__unused_webpack_module, export"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.debug.js.LICENSE.txt",
    "chars": 583,
    "preview": "/*\nJqTree 1.8.10\n\nCopyright 2025 Marco Braak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may no"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js",
    "chars": 50523,
    "preview": "/*! For license information please see django_mptt_admin.js.LICENSE.txt */\n(()=>{var e={163(e,t){\"use strict\";t.qg=funct"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/django_mptt_admin.js.LICENSE.txt",
    "chars": 583,
    "preview": "/*\nJqTree 1.8.11\n\nCopyright 2026 Marco Braak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may no"
  },
  {
    "path": "django_mptt_admin/static/django_mptt_admin/jquery_namespace.js",
    "chars": 57,
    "preview": "window.$ = django.jQuery;\nwindow.jQuery = django.jQuery;\n"
  },
  {
    "path": "django_mptt_admin/templates/django_mptt_admin/change_list.html",
    "chars": 1724,
    "preview": "{% extends 'admin/change_list.html' %}\n{% load i18n admin_list static javascript_value %}\n\n{% block extrastyle %}\n    {{"
  },
  {
    "path": "django_mptt_admin/templates/django_mptt_admin/grid_view.html",
    "chars": 188,
    "preview": "{% extends 'admin/change_list.html' %}\n{% load i18n %}\n\n{% block object-tools-items %}\n{{ block.super }}\n<li>\n    <a hre"
  },
  {
    "path": "django_mptt_admin/templatetags/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "django_mptt_admin/templatetags/javascript_value.py",
    "chars": 423,
    "preview": "import json\nfrom django import template\n\nregister = template.Library()\n\n\n@register.filter\ndef javascript_value(value):\n "
  },
  {
    "path": "django_mptt_admin/tree_change_list.py",
    "chars": 1984,
    "preview": "from django.contrib.admin.views.main import ChangeList\nimport django\n\nfrom . import util\n\n\nclass TreeChangeList(ChangeLi"
  },
  {
    "path": "django_mptt_admin/util.py",
    "chars": 3396,
    "preview": "def serialize_id(pk):\n    if isinstance(pk, (int, str)):\n        return pk\n    else:\n        # Nb. special case for uuid"
  },
  {
    "path": "docs/index.md",
    "chars": 12215,
    "preview": "# Django Mptt Admin\n\n_Django-mptt-admin_ provides a nice Django Admin interface for [django-mptt models](http://django-m"
  },
  {
    "path": "example_project/django_mptt_example/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example_project/django_mptt_example/admin.py",
    "chars": 1682,
    "preview": "from django.contrib import admin\nfrom django.conf import settings\n\nfrom django_mptt_admin.admin import DjangoMpttAdmin\n\n"
  },
  {
    "path": "example_project/django_mptt_example/fixtures/countries.json",
    "chars": 42504,
    "preview": "[{\"model\": \"django_mptt_example.country\", \"pk\": 1, \"fields\": {\"code\": null, \"name\": \"root\", \"parent\": null, \"lft\": 1, \"r"
  },
  {
    "path": "example_project/django_mptt_example/migrations/0001_initial.py",
    "chars": 1701,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.9.10 on 2016-10-22 06:22\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "example_project/django_mptt_example/migrations/0002_alter_country_level_alter_country_lft_and_more.py",
    "chars": 724,
    "preview": "# Generated by Django 4.0 on 2021-04-25 02:52\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.Mig"
  },
  {
    "path": "example_project/django_mptt_example/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example_project/django_mptt_example/models.py",
    "chars": 1039,
    "preview": "from django.db import models\nfrom django.utils.html import format_html\n\nfrom mptt.models import TreeForeignKey, MPTTMode"
  },
  {
    "path": "example_project/django_mptt_example/tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example_project/django_mptt_example/tests/base_playwright_testcase.py",
    "chars": 606,
    "preview": "from django.conf import settings\nfrom django.test import LiveServerTestCase\nfrom .playwright_page import PlaywrightPage\n"
  },
  {
    "path": "example_project/django_mptt_example/tests/base_view_testcase.py",
    "chars": 661,
    "preview": "from django_webtest import WebTest\nfrom django.contrib.auth.models import User\n\n\nclass BaseViewTestCase(WebTest):\n    fi"
  },
  {
    "path": "example_project/django_mptt_example/tests/playwright_page.py",
    "chars": 5930,
    "preview": "from uuid import uuid4\nfrom playwright.sync_api import ElementHandle, sync_playwright\nfrom .utils import wait_until, wri"
  },
  {
    "path": "example_project/django_mptt_example/tests/test_playwright.py",
    "chars": 5489,
    "preview": "from django.test import override_settings\nfrom django.contrib.auth.models import Permission, User\n\nfrom ..models import "
  },
  {
    "path": "example_project/django_mptt_example/tests/test_util.py",
    "chars": 2303,
    "preview": "from uuid import UUID\nfrom django.test import TestCase\n\nfrom django_mptt_admin.util import (\n    get_tree_queryset,\n    "
  },
  {
    "path": "example_project/django_mptt_example/tests/test_views.py",
    "chars": 5832,
    "preview": "from django.contrib.admin.options import IS_POPUP_VAR\nfrom django.contrib.auth.models import User\nimport django\n\nfrom .."
  },
  {
    "path": "example_project/django_mptt_example/tests/utils.py",
    "chars": 627,
    "preview": "from json import dumps\nfrom pathlib import Path\nfrom time import sleep\n\nfrom ..models import Country\n\n\ndef remove_direct"
  },
  {
    "path": "example_project/example_project/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example_project/example_project/settings.py",
    "chars": 2337,
    "preview": "import sys\nimport os\n\nfrom pathlib import Path\n\n\nBASE_DIR = Path(__file__).parent.parent.resolve()\n\nsys.path.append(str("
  },
  {
    "path": "example_project/example_project/urls.py",
    "chars": 107,
    "preview": "from django.urls import path\nfrom django.contrib import admin\n\n\nurlpatterns = (path(\"\", admin.site.urls),)\n"
  },
  {
    "path": "example_project/import_test_data",
    "chars": 70,
    "preview": "python manage.py loaddata django_mptt_example/fixtures/countries.json\n"
  },
  {
    "path": "example_project/manage.py",
    "chars": 259,
    "preview": "#!/usr/bin/env python\nimport os\nimport sys\n\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODUL"
  },
  {
    "path": "example_project/requirements_all.txt",
    "chars": 76,
    "preview": "-r requirements_example.txt\n-r requirements_test.txt\n-r requirements_ci.txt\n"
  },
  {
    "path": "example_project/requirements_ci.txt",
    "chars": 63,
    "preview": "coverage==7.13.5\ndocopt==0.6.2\nPyYAML===6.0.3\nrequests==2.33.1\n"
  },
  {
    "path": "example_project/requirements_example.txt",
    "chars": 17,
    "preview": "Django>=6.0,<6.1\n"
  },
  {
    "path": "example_project/requirements_test.txt",
    "chars": 188,
    "preview": "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\npsycop"
  },
  {
    "path": "example_project/run_coverage",
    "chars": 114,
    "preview": "coverage run --source=django_mptt_admin,django_mptt_example manage.py test django_mptt_example\ncoverage report -m\n"
  },
  {
    "path": "example_project/run_tests",
    "chars": 81,
    "preview": "PYTHONWARNINGS=default python manage.py test --failfast -v 2 django_mptt_example\n"
  },
  {
    "path": "frontend/.babelrc",
    "chars": 121,
    "preview": "{\n    \"presets\": [\"@babel/preset-env\", \"@babel/preset-typescript\"],\n    \"plugins\": [\"@babel/plugin-transform-runtime\"]\n}"
  },
  {
    "path": "frontend/.editorconfig",
    "chars": 263,
    "preview": "# EditorConfig helps developers define and maintain\n# consistent coding styles between different editors and IDEs.\n\nroot"
  },
  {
    "path": "frontend/django_mptt_admin.scss",
    "chars": 2581,
    "preview": "@use \"node_modules/jqtree/jqtree\";\n\n@keyframes jqtree-spin {\n    0% {\n        transform: rotate(0deg);\n    }\n    100% {\n"
  },
  {
    "path": "frontend/eslint.config.mjs",
    "chars": 977,
    "preview": "import eslint from \"@eslint/js\";\nimport tseslint from \"typescript-eslint\";\nimport importPlugin from \"eslint-plugin-impor"
  },
  {
    "path": "frontend/package.json",
    "chars": 2635,
    "preview": "{\n    \"name\": \"django-mptt-admin\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Frontend code for django-mptt-admin\",\n   "
  },
  {
    "path": "frontend/src/djangoMpttAdmin.ts",
    "chars": 1098,
    "preview": "import initTree from \"./initTree\";\n\njQuery(() => {\n    const $tree = jQuery(\"#tree\");\n\n    if ($tree.length) {\n        c"
  },
  {
    "path": "frontend/src/global.d.ts",
    "chars": 45,
    "preview": "declare function gettext(s: string): string;\n"
  },
  {
    "path": "frontend/src/initTree.test.ts",
    "chars": 8928,
    "preview": "import { screen, waitFor } from \"@testing-library/dom\";\nimport * as cookie from \"cookie\";\nimport jQuery from \"jquery\";\ni"
  },
  {
    "path": "frontend/src/initTree.ts",
    "chars": 7213,
    "preview": "import * as cookie from \"cookie\";\nimport \"jqtree\";\n\nexport interface InitTreeOptions {\n    animationSpeed: null | number"
  },
  {
    "path": "frontend/src/vitestSetup.ts",
    "chars": 252,
    "preview": "import jQuery from \"jquery\";\nimport \"@testing-library/jest-dom/vitest\";\n\ndeclare global {\n    interface Window {\n       "
  },
  {
    "path": "frontend/tsconfig.json",
    "chars": 744,
    "preview": "{\n    \"compileOnSave\": false,\n    \"exclude\": [\"node_modules\"],\n    \"include\": [\"src/**/*\"],\n    \"compilerOptions\": {\n   "
  },
  {
    "path": "frontend/vitest.config.ts",
    "chars": 281,
    "preview": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n    test: {\n        coverage: {\n           "
  },
  {
    "path": "frontend/webpack.config.js",
    "chars": 1457,
    "preview": "const path = require(\"path\");\n\nconst skipCompressJs = Boolean(process.env.SKIP_COMPRESS_JS);\nconst coverage = Boolean(pr"
  },
  {
    "path": "mkdocs.yml",
    "chars": 48,
    "preview": "site_name: django-mptt-admin\ntheme: readthedocs\n"
  },
  {
    "path": "requirements_docs.txt",
    "chars": 14,
    "preview": "mkdocs==1.6.1\n"
  },
  {
    "path": "setup.cfg",
    "chars": 22,
    "preview": "[wheel]\nuniversal = 1\n"
  },
  {
    "path": "setup.py",
    "chars": 1442,
    "preview": "from setuptools import setup, find_packages\n\nfrom os import path\nfrom io import open\n\nthis_directory = path.abspath(path"
  },
  {
    "path": "tox.ini",
    "chars": 481,
    "preview": "[tox]\nenvlist = py310-django42,py312-django42,py313-django52,py314-django6\n\n[testenv]\nchangedir = {toxinidir}/example_pr"
  }
]

// ... and 18 more files (download for full content)

About this extraction

This page contains the full source code of the mbraak/django-mptt-admin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 108 files (273.7 KB), approximately 83.5k tokens, and a symbol index with 155 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!