django-fast-treenode 3.0.6__py3-none-any.whl → 3.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {django_fast_treenode-3.0.6.dist-info → django_fast_treenode-3.0.8.dist-info}/METADATA +1 -1
  2. {django_fast_treenode-3.0.6.dist-info → django_fast_treenode-3.0.8.dist-info}/RECORD +37 -37
  3. {django_fast_treenode-3.0.6.dist-info → django_fast_treenode-3.0.8.dist-info}/WHEEL +1 -1
  4. treenode/__init__.py +1 -0
  5. treenode/admin/admin.py +105 -109
  6. treenode/admin/mixin.py +1 -1
  7. treenode/managers/queries.py +18 -6
  8. treenode/managers/tasks.py +1 -1
  9. treenode/models/models.py +2 -2
  10. treenode/static/css/treenode_admin.css +21 -0
  11. treenode/static/js/treenode_admin.js +130 -339
  12. treenode/static/vendors/jquery-ui/AUTHORS.txt +384 -384
  13. treenode/static/vendors/jquery-ui/LICENSE.txt +43 -43
  14. treenode/static/vendors/jquery-ui/external/jquery/jquery.js +10716 -10716
  15. treenode/static/vendors/jquery-ui/index.html +297 -297
  16. treenode/static/vendors/jquery-ui/jquery-ui.css +438 -438
  17. treenode/static/vendors/jquery-ui/jquery-ui.js +5222 -5222
  18. treenode/static/vendors/jquery-ui/jquery-ui.min.css +6 -6
  19. treenode/static/vendors/jquery-ui/jquery-ui.min.js +5 -5
  20. treenode/static/vendors/jquery-ui/jquery-ui.structure.css +16 -16
  21. treenode/static/vendors/jquery-ui/jquery-ui.structure.min.css +4 -4
  22. treenode/static/vendors/jquery-ui/jquery-ui.theme.css +439 -439
  23. treenode/static/vendors/jquery-ui/jquery-ui.theme.min.css +4 -4
  24. treenode/static/vendors/jquery-ui/package.json +82 -82
  25. treenode/templates/treenode/admin/treenode_changelist.html +61 -15
  26. treenode/templates/treenode/admin/treenode_rows.html +37 -40
  27. treenode/templatetags/treenode_admin.py +57 -14
  28. treenode/utils/db/sqlcompat.py +1 -33
  29. treenode/utils/db/sqlquery.py +0 -24
  30. treenode/version.py +2 -2
  31. treenode/views/autoapi.py +91 -91
  32. treenode/views/autocomplete.py +52 -52
  33. treenode/views/children.py +41 -41
  34. treenode/views/common.py +23 -23
  35. treenode/widgets.py +0 -2
  36. {django_fast_treenode-3.0.6.dist-info → django_fast_treenode-3.0.8.dist-info}/licenses/LICENSE +0 -0
  37. {django_fast_treenode-3.0.6.dist-info → django_fast_treenode-3.0.8.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
- /*! jQuery UI - v1.14.1 - 2025-04-13
2
- * https://jqueryui.com
3
- * Copyright OpenJS Foundation and other contributors; Licensed MIT */
4
-
1
+ /*! jQuery UI - v1.14.1 - 2025-04-13
2
+ * https://jqueryui.com
3
+ * Copyright OpenJS Foundation and other contributors; Licensed MIT */
4
+
5
5
  .ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;background-image:none}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank.ui-icon-blank.ui-icon-blank{background-image:none}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.3}.ui-widget-shadow{box-shadow:0 0 5px #666}
@@ -1,82 +1,82 @@
1
- {
2
- "name": "jquery-ui",
3
- "title": "jQuery UI",
4
- "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.",
5
- "version": "1.14.1",
6
- "homepage": "https://jqueryui.com",
7
- "author": {
8
- "name": "OpenJS Foundation and other contributors",
9
- "url": "https://github.com/jquery/jquery-ui/blob/1.14.1/AUTHORS.txt"
10
- },
11
- "main": "ui/widget.js",
12
- "maintainers": [
13
- {
14
- "name": "Jörn Zaefferer",
15
- "email": "joern.zaefferer@gmail.com",
16
- "url": "https://bassistance.de"
17
- },
18
- {
19
- "name": "Mike Sherov",
20
- "email": "mike.sherov@gmail.com",
21
- "url": "https://mike.sherov.com"
22
- },
23
- {
24
- "name": "TJ VanToll",
25
- "email": "tj.vantoll@gmail.com",
26
- "url": "https://www.tjvantoll.com"
27
- },
28
- {
29
- "name": "Felix Nagel",
30
- "email": "info@felixnagel.com",
31
- "url": "https://www.felixnagel.com"
32
- },
33
- {
34
- "name": "Alex Schmitz",
35
- "email": "arschmitz@gmail.com",
36
- "url": "https://github.com/arschmitz"
37
- }
38
- ],
39
- "repository": {
40
- "type": "git",
41
- "url": "git://github.com/jquery/jquery-ui.git"
42
- },
43
- "bugs": {
44
- "url": "https://github.com/jquery/jquery-ui/issues"
45
- },
46
- "license": "MIT",
47
- "scripts": {
48
- "build": "grunt build",
49
- "lint": "grunt lint",
50
- "test:server": "node tests/runner/server.js",
51
- "test:unit": "node tests/runner/command.js",
52
- "test": "grunt && npm run test:unit -- -h"
53
- },
54
- "dependencies": {
55
- "jquery": ">=1.12.0 <5.0.0"
56
- },
57
- "devDependencies": {
58
- "body-parser": "1.20.3",
59
- "browserstack-local": "1.5.5",
60
- "commitplease": "3.2.0",
61
- "diff": "5.2.0",
62
- "eslint-config-jquery": "3.0.2",
63
- "exit-hook": "4.0.0",
64
- "express": "4.21.1",
65
- "express-body-parser-error-handler": "1.0.7",
66
- "grunt": "1.6.1",
67
- "grunt-bowercopy": "1.2.5",
68
- "grunt-compare-size": "0.4.2",
69
- "grunt-contrib-concat": "2.1.0",
70
- "grunt-contrib-csslint": "2.0.0",
71
- "grunt-contrib-requirejs": "1.0.0",
72
- "grunt-contrib-uglify": "5.2.2",
73
- "grunt-eslint": "24.0.1",
74
- "grunt-git-authors": "3.2.0",
75
- "grunt-html": "17.1.0",
76
- "load-grunt-tasks": "5.1.0",
77
- "rimraf": "6.0.1",
78
- "selenium-webdriver": "4.26.0",
79
- "yargs": "17.7.2"
80
- },
81
- "keywords": []
82
- }
1
+ {
2
+ "name": "jquery-ui",
3
+ "title": "jQuery UI",
4
+ "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.",
5
+ "version": "1.14.1",
6
+ "homepage": "https://jqueryui.com",
7
+ "author": {
8
+ "name": "OpenJS Foundation and other contributors",
9
+ "url": "https://github.com/jquery/jquery-ui/blob/1.14.1/AUTHORS.txt"
10
+ },
11
+ "main": "ui/widget.js",
12
+ "maintainers": [
13
+ {
14
+ "name": "Jörn Zaefferer",
15
+ "email": "joern.zaefferer@gmail.com",
16
+ "url": "https://bassistance.de"
17
+ },
18
+ {
19
+ "name": "Mike Sherov",
20
+ "email": "mike.sherov@gmail.com",
21
+ "url": "https://mike.sherov.com"
22
+ },
23
+ {
24
+ "name": "TJ VanToll",
25
+ "email": "tj.vantoll@gmail.com",
26
+ "url": "https://www.tjvantoll.com"
27
+ },
28
+ {
29
+ "name": "Felix Nagel",
30
+ "email": "info@felixnagel.com",
31
+ "url": "https://www.felixnagel.com"
32
+ },
33
+ {
34
+ "name": "Alex Schmitz",
35
+ "email": "arschmitz@gmail.com",
36
+ "url": "https://github.com/arschmitz"
37
+ }
38
+ ],
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git://github.com/jquery/jquery-ui.git"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/jquery/jquery-ui/issues"
45
+ },
46
+ "license": "MIT",
47
+ "scripts": {
48
+ "build": "grunt build",
49
+ "lint": "grunt lint",
50
+ "test:server": "node tests/runner/server.js",
51
+ "test:unit": "node tests/runner/command.js",
52
+ "test": "grunt && npm run test:unit -- -h"
53
+ },
54
+ "dependencies": {
55
+ "jquery": ">=1.12.0 <5.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "body-parser": "1.20.3",
59
+ "browserstack-local": "1.5.5",
60
+ "commitplease": "3.2.0",
61
+ "diff": "5.2.0",
62
+ "eslint-config-jquery": "3.0.2",
63
+ "exit-hook": "4.0.0",
64
+ "express": "4.21.1",
65
+ "express-body-parser-error-handler": "1.0.7",
66
+ "grunt": "1.6.1",
67
+ "grunt-bowercopy": "1.2.5",
68
+ "grunt-compare-size": "0.4.2",
69
+ "grunt-contrib-concat": "2.1.0",
70
+ "grunt-contrib-csslint": "2.0.0",
71
+ "grunt-contrib-requirejs": "1.0.0",
72
+ "grunt-contrib-uglify": "5.2.2",
73
+ "grunt-eslint": "24.0.1",
74
+ "grunt-git-authors": "3.2.0",
75
+ "grunt-html": "17.1.0",
76
+ "load-grunt-tasks": "5.1.0",
77
+ "rimraf": "6.0.1",
78
+ "selenium-webdriver": "4.26.0",
79
+ "yargs": "17.7.2"
80
+ },
81
+ "keywords": []
82
+ }
@@ -2,24 +2,70 @@
2
2
  {% load admin_list %}
3
3
  {% load i18n %}
4
4
  {% load treenode_admin %}
5
+ {% load static %}
5
6
 
6
- {% block object-tools-items %}
7
- {{ block.super }}
8
- {% if import_export_enabled %}
9
- <li><a href="import/" class="button">Import</a></li>
10
- <li><a href="export/" class="button">Export</a></li>
7
+ {% block content %}
8
+
9
+ {% block object-tools %}
10
+ {% if has_add_permission %}
11
+ <ul class="object-tools">
12
+ {% block object-tools-items %}
13
+ {{ block.super }}
14
+ <li><a href="import/" class="button">Import</a></li>
15
+ <li><a href="export/" class="button">Export</a></li>
16
+ {% endblock %}
17
+ </ul>
11
18
  {% endif %}
12
- {% endblock %}
19
+ {% endblock %}
20
+
21
+ <div id="changelist" class="module filtered">
22
+ <div class="changelist-form-container">
23
+
24
+ {# Search bar + expand/collapse buttons #}
25
+ {% block search %}
26
+ <div id="toolbar">
27
+ <form id="changelist-search" method="get" role="search">
28
+ <label for="searchbar">
29
+ <img src="{% static 'admin/img/search.svg' %}" alt="{% translate 'Search' %}">
30
+ </label>
31
+ <input type="text" size="40" name="q" value="{{ cl.query }}" id="searchbar">
32
+ <input type="submit" value="{% translate 'Search' %}">
33
+ <button type="button" class="button treenode-button treenode-expand-all">
34
+ {% trans "Expand All" %}
35
+ </button>
36
+ <button type="button" class="button treenode-button treenode-collapse-all">
37
+ {% trans "Collapse All" %}
38
+ </button>
39
+ </form>
40
+ </div>
41
+ {% endblock %}
42
+
43
+ {# Form with list and actions #}
44
+ <form id="changelist-form" method="post" {% if cl.formset or action_form %} enctype="multipart/form-data"{% endif %}>
45
+ {% csrf_token %}
13
46
 
14
- {% block result_list %}
15
- {% if action_form and actions_on_top and cl.show_admin_actions %}
16
- {% admin_actions %}
17
- {% endif %}
47
+ {% if action_form and actions_on_top and cl.show_admin_actions %}
48
+ {% admin_actions %}
49
+ {% endif %}
18
50
 
19
- {% tree_result_list cl %}
51
+ {% block result_list %}
52
+ {% tree_result_list cl %}
53
+ {% endblock %}
20
54
 
21
- {% if action_form and actions_on_bottom and cl.show_admin_actions %}
22
- {% admin_actions %}
23
- {% endif %}
55
+ {% if action_form and actions_on_bottom and cl.show_admin_actions %}
56
+ {% admin_actions %}
57
+ {% endif %}
58
+
59
+ {% block pagination %}
60
+ {{ block.super }}
61
+ {% endblock %}
62
+ </form>
63
+ </div>
64
+
65
+ {# 📎 Боковая панель фильтров #}
66
+ {% block filters %}
67
+ {{ block.super }}
68
+ {% endblock %}
69
+ </div>
70
+ {% endblock %}
24
71
 
25
- {% endblock %}
@@ -2,49 +2,45 @@
2
2
 
3
3
  <div class="results">
4
4
  <table id="result_list">
5
-
6
-
7
- <thead>
8
- <tr>
9
- {% for h in headers %}
10
- <th scope="col"{{ h.class_attrib|safe }}>
11
- {% if "action-checkbox-column" in h.class_attrib %}
12
- <div class="text">
13
- <span>
14
- <input type="checkbox" id="action-toggle" aria-label="{% translate 'Select all objects on this page for an action' %}">
15
- </span>
16
- </div>
17
- <div class="clear"></div>
18
- {% else %}
19
- {% if h.sortable %}
20
- <div class="sortoptions">
21
- {% if h.url_remove %}
22
- <a class="sortremove" href="{{ h.url_remove }}" title="{% translate 'Remove from sorting' %}"></a>
23
- {% endif %}
24
- {% if h.url_toggle %}
25
- <a href="{{ h.url_toggle }}" class="toggle {% if h.ascending %}ascending{% else %}descending{% endif %}" title="{% translate 'Toggle sorting' %}"></a>
26
- {% endif %}
27
- </div>
28
- {% else %}
29
- <div class="sortoptions"></div>
30
- {% endif %}
31
-
32
- <div class="text">
33
- {% if h.sortable %}
34
- <a href="{{ h.url_primary }}">{{ h.text|safe }}</a>
5
+ <thead>
6
+ <tr>
7
+ {% for h in headers %}
8
+ <th scope="col"{{ h.class_attrib|safe }}>
9
+ {% if "action-checkbox-column" in h.class_attrib %}
10
+ <div class="text">
11
+ <span>
12
+ <input type="checkbox" id="action-toggle" aria-label="{% translate 'Select all objects on this page for an action' %}">
13
+ </span>
14
+ </div>
15
+ <div class="clear"></div>
35
16
  {% else %}
36
- <a href="#">{{ h.text|safe }}</a>
17
+ {% if h.sortable %}
18
+ <div class="sortoptions">
19
+ {% if h.url_remove %}
20
+ <a class="sortremove" href="{{ h.url_remove }}" title="{% translate 'Remove from sorting' %}"></a>
21
+ {% endif %}
22
+ {% if h.url_toggle %}
23
+ <a href="{{ h.url_toggle }}" class="toggle {% if h.ascending %}ascending{% else %}descending{% endif %}" title="{% translate 'Toggle sorting' %}"></a>
24
+ {% endif %}
25
+ </div>
26
+ {% else %}
27
+ <div class="sortoptions"></div>
28
+ {% endif %}
29
+ <div class="text">
30
+ {% if h.sortable %}
31
+ <a href="{{ h.url_primary }}">{{ h.text|safe }}</a>
32
+ {% else %}
33
+ <a href="#">{{ h.text|safe }}</a>
34
+ {% endif %}
35
+ </div>
36
+ <div class="clear"></div>
37
37
  {% endif %}
38
- </div>
39
- <div class="clear"></div>
40
- {% endif %}
41
- </th>
42
- {% endfor %}
43
- </tr>
44
- </thead>
38
+ </th>
39
+ {% endfor %}
40
+ </tr>
41
+ </thead>
45
42
 
46
-
47
- <tbody>
43
+ <tbody id="treenode-table">
48
44
  {% for row in rows %}
49
45
  <tr {{ row.attrs|safe }}>
50
46
  {% for cell in row.cells %}
@@ -53,5 +49,6 @@
53
49
  </tr>
54
50
  {% endfor %}
55
51
  </tbody>
52
+
56
53
  </table>
57
54
  </div>
@@ -1,8 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- Custon tags for changelist tamplate.
3
+ Custom tags for changelist template.
4
4
 
5
- Version: 3.0.0
5
+ Version: 3.1.0
6
6
  Author: Timur Kady
7
7
  Email: timurkady@yandex.com
8
8
  """
@@ -10,30 +10,73 @@ Email: timurkady@yandex.com
10
10
 
11
11
  from django import template
12
12
  from django.contrib.admin.templatetags import admin_list
13
+ from django.utils.html import format_html, mark_safe
13
14
 
14
15
  register = template.Library()
15
16
 
16
17
 
17
- @register.inclusion_tag(
18
- "treenode/admin/treenode_rows.html",
19
- takes_context=True,
20
- )
18
+ @register.inclusion_tag("treenode/admin/treenode_rows.html", takes_context=True)
21
19
  def tree_result_list(context, cl):
22
- """
23
- Return custom results for change_list.
24
-
25
- Заголовки берём из стандартного admin_list.result_headers(),
26
- а строки формируем как угодно.
27
- """
20
+ """Get result list."""
28
21
  headers = list(admin_list.result_headers(cl))
29
22
 
23
+ # Add a checkbox title manually if it is missing
24
+ if cl.actions and not any("action-checkbox-column" in h["class_attrib"] for h in headers):
25
+ headers.insert(0, {
26
+ "text": "",
27
+ "class_attrib": ' class="action-checkbox-column"',
28
+ "sortable": False
29
+ })
30
+
30
31
  rows = []
32
+
31
33
  for obj in cl.result_list:
32
34
  cells = list(admin_list.items_for_result(cl, obj, None))
35
+
36
+ # Insert checkbox manually
37
+ checkbox = format_html(
38
+ '<td class="action-checkbox">'
39
+ '<input type="checkbox" name="_selected_action" value="{}" class="action-select" /></td>',
40
+ obj.pk
41
+ )
42
+ cells.insert(0, checkbox)
43
+
44
+ # Replace the toggle cell (3rd after inserting checkbox and move)
45
+ is_leaf = getattr(obj, "is_leaf", lambda: True)()
46
+ toggle_html = format_html(
47
+ '<td class="field-toggle">{}</td>',
48
+ format_html(
49
+ '<button class="treenode-toggle" data-node-id="{}">►</button>',
50
+ obj.pk
51
+ ) if not is_leaf else mark_safe('<div class="treenode-space">&nbsp;</div>')
52
+ )
53
+ if len(cells) >= 3:
54
+ cells.pop(2)
55
+ cells.insert(2, toggle_html)
56
+
57
+ depth = getattr(obj, "get_depth", lambda: 0)()
58
+ parent_id = getattr(obj, "parent_id", "")
59
+ is_root = not parent_id
60
+
61
+ classes = ["treenode-row"]
62
+ if is_root:
63
+ classes.append("treenode-root")
64
+ else:
65
+ classes.append("treenode-hidden")
66
+
67
+ row_attrs = {
68
+ "class": " ".join(classes),
69
+ "data-node-id": obj.pk,
70
+ "data-parent-id": parent_id or "",
71
+ "data-depth": depth,
72
+ }
73
+
33
74
  rows.append({
34
- "attrs": getattr(obj, "row_attrs", ""),
75
+ "attrs": " ".join(f'{k}="{v}"' for k, v in row_attrs.items()),
35
76
  "cells": cells,
36
- "form": None, # поддержка list_editable, если нужно
77
+ "form": None,
78
+ "is_leaf": is_leaf,
79
+ "node_id": obj.pk,
37
80
  })
38
81
 
39
82
  return {
@@ -125,44 +125,12 @@ class SQLCompat:
125
125
  {set_clause};
126
126
  """
127
127
 
128
- elif connection.vendor == "sqlite":
129
- # SQLite workaround via temporary table
130
- temp_table = "temp_tree_update"
131
- cols = ["id"] + [cte_alias.get(f, f) for f in update_fields]
132
- col_defs = ", ".join(f"{c} TEXT" for c in cols)
133
- insert_cols = ", ".join(cols)
134
- select_cols = ", ".join(cols)
135
-
136
- set_clause = ", ".join(
137
- f"{qf(f)} = (SELECT t.{cte_alias.get(f, f)} FROM {temp_table} t WHERE t.id = {qt}.id)" # noqa
138
- for f in update_fields
139
- )
140
-
141
- return f"""
142
- DROP TABLE IF EXISTS {temp_table};
143
- CREATE TEMP TABLE {temp_table} ({col_defs});
144
-
145
- WITH RECURSIVE tree_cte {cte_header} AS (
146
- {base_sql}
147
- UNION ALL
148
- {recursive_sql}
149
- )
150
- INSERT INTO {temp_table} ({insert_cols})
151
- SELECT {select_cols} FROM tree_cte;
152
-
153
- UPDATE {qt}
154
- SET {set_clause}
155
- WHERE id IN (SELECT id FROM {temp_table});
156
- """
157
-
158
128
  else:
159
- # Fallback: subqueries
160
- # (still buggy in SQLite, hence above workaround)
161
129
  set_clause = ", ".join(
162
130
  f"{qf(f)} = (SELECT t.{f} FROM tree_cte t WHERE t.id = {qt}.id)"
163
131
  for f in update_fields
164
132
  )
165
- where_clause = "id IN (SELECT id FROM tree_cte)"
133
+ where_clause = f"id IN (SELECT id FROM tree_cte)"
166
134
  return f"""
167
135
  WITH RECURSIVE tree_cte {cte_header} AS (
168
136
  {base_sql}
@@ -66,29 +66,5 @@ class SQLQueue:
66
66
  raise
67
67
  self._items.clear()
68
68
 
69
- @staticmethod
70
- def wrap_union_all(queries):
71
- """
72
- Combine multiple SQL queries using UNION ALL with vendor-specific handling.
73
- Each query is a tuple: (sql, params).
74
- Returns a tuple: (combined_sql, combined_params).
75
- """
76
- if is_sqlite():
77
- # SQLite требует одинаковое число и порядок столбцов. Добавим к каждому SELECT псевдонимы.
78
- def alias_select(sql, alias_prefix, idx):
79
- return f"SELECT * FROM ({sql}) AS {alias_prefix}_{idx}"
80
-
81
- wrapped_queries = [
82
- alias_select(q[0], "q", i) for i, q in enumerate(queries)
83
- ]
84
- combined_sql = " UNION ALL ".join(wrapped_queries)
85
- else:
86
- combined_sql = " UNION ALL ".join(f"({q[0]})" for q in queries)
87
-
88
- combined_params = []
89
- for q in queries:
90
- combined_params.extend(q[1])
91
-
92
- return combined_sql, combined_params
93
69
 
94
70
  # The End
treenode/version.py CHANGED
@@ -4,9 +4,9 @@ TreeNode Version Module
4
4
 
5
5
  This module defines the current version of the TreeNode package.
6
6
 
7
- Version: 3.0.6
7
+ Version: 3.0.8
8
8
  Author: Timur Kady
9
9
  Email: timurkady@yandex.com
10
10
  """
11
11
 
12
- __version__ = '3.0.6'
12
+ __version__ = '3.0.8'