django-smartbase-admin 0.2.91__py3-none-any.whl → 0.2.92__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.
- django_smartbase_admin/actions/admin_action_list.py +0 -6
- django_smartbase_admin/admin/admin_base.py +1 -0
- django_smartbase_admin/admin/widgets.py +70 -0
- django_smartbase_admin/engine/admin_base_view.py +4 -1
- django_smartbase_admin/engine/filter_widgets.py +182 -1
- django_smartbase_admin/locale/sk/LC_MESSAGES/django.mo +0 -0
- django_smartbase_admin/locale/sk/LC_MESSAGES/django.po +241 -28
- django_smartbase_admin/services/views.py +2 -2
- django_smartbase_admin/static/sb_admin/build/webpack.common.js +9 -8
- django_smartbase_admin/static/sb_admin/fancytree/jquery.fancytree-all-deps.min.js +2 -0
- django_smartbase_admin/static/sb_admin/src/css/_base.css +4 -0
- django_smartbase_admin/static/sb_admin/src/css/_inlines.css +3 -3
- django_smartbase_admin/static/sb_admin/src/css/_tabulator.css +6 -0
- django_smartbase_admin/static/sb_admin/src/css/components/_toggle.css +2 -1
- django_smartbase_admin/static/sb_admin/src/css/tree_widget.css +405 -0
- django_smartbase_admin/static/sb_admin/src/js/datepicker.js +1 -0
- django_smartbase_admin/static/sb_admin/src/js/table.js +18 -2
- django_smartbase_admin/static/sb_admin/src/js/table_modules/filter_module.js +3 -1
- django_smartbase_admin/static/sb_admin/src/js/table_modules/selection_module.js +20 -2
- django_smartbase_admin/static/sb_admin/src/js/table_modules/table_params_module.js +6 -0
- django_smartbase_admin/static/sb_admin/src/js/tree_widget.js +376 -0
- django_smartbase_admin/templates/sb_admin/actions/tree_list.html +63 -0
- django_smartbase_admin/templates/sb_admin/components/columns.html +1 -1
- django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/tree_select_filter.html +2 -0
- django_smartbase_admin/templates/sb_admin/filter_widgets/tree_select_filter.html +16 -0
- django_smartbase_admin/templates/sb_admin/sb_admin_base_no_sidebar.html +7 -5
- django_smartbase_admin/templates/sb_admin/sb_admin_js_trans.html +1 -0
- django_smartbase_admin/templates/sb_admin/widgets/filer_file.html +1 -1
- django_smartbase_admin/templates/sb_admin/widgets/tree_base.html +54 -0
- django_smartbase_admin/templates/sb_admin/widgets/tree_select.html +24 -0
- django_smartbase_admin/templates/sb_admin/widgets/tree_select_inline.html +12 -0
- {django_smartbase_admin-0.2.91.dist-info → django_smartbase_admin-0.2.92.dist-info}/METADATA +2 -2
- {django_smartbase_admin-0.2.91.dist-info → django_smartbase_admin-0.2.92.dist-info}/RECORD +35 -36
- {django_smartbase_admin-0.2.91.dist-info → django_smartbase_admin-0.2.92.dist-info}/WHEEL +1 -1
- django_smartbase_admin/static/sb_admin/dist/chart.js +0 -2
- django_smartbase_admin/static/sb_admin/dist/chart.js.LICENSE.txt +0 -13
- django_smartbase_admin/static/sb_admin/dist/confirmation_modal.js +0 -1
- django_smartbase_admin/static/sb_admin/dist/main.js +0 -2
- django_smartbase_admin/static/sb_admin/dist/main.js.LICENSE.txt +0 -131
- django_smartbase_admin/static/sb_admin/dist/main_style.css +0 -1
- django_smartbase_admin/static/sb_admin/dist/main_style.js +0 -0
- django_smartbase_admin/static/sb_admin/dist/table.js +0 -2
- django_smartbase_admin/static/sb_admin/dist/table.js.LICENSE.txt +0 -15
- django_smartbase_admin/static/sb_admin/dist/translations.js +0 -1
- {django_smartbase_admin-0.2.91.dist-info → django_smartbase_admin-0.2.92.dist-info}/LICENSE.md +0 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
const loadValue = function ($inputEl, treeWidgetData, treeInstance) {
|
|
2
|
+
let value = $inputEl.val()
|
|
3
|
+
if (value !== undefined) {
|
|
4
|
+
treeInstance.selectAll(false)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let selectedKeys = [value]
|
|
8
|
+
if (treeWidgetData.filter === true) {
|
|
9
|
+
let selectedData = []
|
|
10
|
+
selectedKeys = []
|
|
11
|
+
try {
|
|
12
|
+
selectedData = JSON.parse(value)
|
|
13
|
+
} catch(e) {
|
|
14
|
+
selectedData = []
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
selectedData.forEach(function (item) {
|
|
18
|
+
selectedKeys.push(item.value)
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
} else if (treeWidgetData.multiselect === 2) {
|
|
22
|
+
try {
|
|
23
|
+
selectedKeys = JSON.parse(value)
|
|
24
|
+
} catch (e) {
|
|
25
|
+
selectedKeys = []
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
selectedKeys.forEach(function (key) {
|
|
29
|
+
let selectedNode = treeInstance.getNodeByKey(key)
|
|
30
|
+
if (selectedNode) {
|
|
31
|
+
selectedNode.getParentList().forEach(function (node) {
|
|
32
|
+
// Expand all parents of selected node
|
|
33
|
+
node.setExpanded(true)
|
|
34
|
+
})
|
|
35
|
+
selectedNode.setSelected(true)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
'use strict'
|
|
42
|
+
{
|
|
43
|
+
$(function () {
|
|
44
|
+
const initTree = function ($treeEl) {
|
|
45
|
+
if ($treeEl.hasClass('fancytree-container')) {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
$treeEl.on('change', (e) => {
|
|
49
|
+
const changeTarget = e.target.dataset['changeTarget']
|
|
50
|
+
if(changeTarget) {
|
|
51
|
+
const changeTargetEl = document.querySelector(changeTarget)
|
|
52
|
+
if(changeTargetEl) {
|
|
53
|
+
changeTargetEl.value = e.target.value
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
let filterData = {}
|
|
58
|
+
const filterByTableData = (treeInstance) => {
|
|
59
|
+
if(!filterData["isFiltered"]) {
|
|
60
|
+
treeInstance.filterNodes((node) => {
|
|
61
|
+
node.setExpanded(false)
|
|
62
|
+
return true
|
|
63
|
+
}, { autoExpand: false })
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const tableData = {}
|
|
68
|
+
filterData['data'].forEach(item => tableData[item.path] = item)
|
|
69
|
+
|
|
70
|
+
treeInstance.filterNodes((node) => {
|
|
71
|
+
if(tableData[node.key]) {
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
}, { autoExpand: true })
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const $treeDataEl = $('#' + $treeEl.data('tree-data-id'))
|
|
78
|
+
const $treeAdditionalColumnsDataEl = $('#' + $treeEl.data('tree-additional-columns-id'))
|
|
79
|
+
const $treeStringsDataEl = $('#' + $treeEl.data('tree-strings-id'))
|
|
80
|
+
let treeWidgetData = {}
|
|
81
|
+
let additionalColumns = []
|
|
82
|
+
let treeStrings = {loading: "Loading...", loadError: "Load error!", moreData: "More...", noData: "No data."}
|
|
83
|
+
try {
|
|
84
|
+
treeWidgetData = JSON.parse($treeDataEl.text()) || {}
|
|
85
|
+
additionalColumns = JSON.parse($treeAdditionalColumnsDataEl.text()) || []
|
|
86
|
+
treeStrings = JSON.parse($treeStringsDataEl.text())
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error(e)
|
|
89
|
+
}
|
|
90
|
+
const $inputEl = $('#' + treeWidgetData.input_id)
|
|
91
|
+
const $searchEl = $('#' + treeWidgetData.input_id + '_search')
|
|
92
|
+
const $matchesEl = $('#' + treeWidgetData.input_id + '_matches')
|
|
93
|
+
const $label = $('#' + treeWidgetData.input_id + '_label')
|
|
94
|
+
const tableConfig = {
|
|
95
|
+
indentation: 32,
|
|
96
|
+
nodeColumnIdx: 0,
|
|
97
|
+
}
|
|
98
|
+
if (treeWidgetData.checkbox) {
|
|
99
|
+
tableConfig.checkboxColumnIdx = 0
|
|
100
|
+
tableConfig.nodeColumnIdx = 1
|
|
101
|
+
}
|
|
102
|
+
let extensions = ["table", "gridnav", "filter"]
|
|
103
|
+
if (treeWidgetData.reorder_url) {
|
|
104
|
+
extensions.push("dnd5")
|
|
105
|
+
}
|
|
106
|
+
$treeEl.fancytree({
|
|
107
|
+
source: {
|
|
108
|
+
url: treeWidgetData.data_url,
|
|
109
|
+
},
|
|
110
|
+
extensions: extensions,
|
|
111
|
+
checkbox: treeWidgetData.checkbox,
|
|
112
|
+
selectMode: treeWidgetData.multiselect,
|
|
113
|
+
dnd5: {
|
|
114
|
+
preventVoidMoves: true,
|
|
115
|
+
preventRecursion: true,
|
|
116
|
+
autoExpandMS: 400,
|
|
117
|
+
dropMarkerParent: '.tree-list-view',
|
|
118
|
+
dropMarkerOffsetX: -8,
|
|
119
|
+
dropMarkerInsertOffsetX: 0,
|
|
120
|
+
dragStart: function () {
|
|
121
|
+
return true
|
|
122
|
+
},
|
|
123
|
+
dragEnter: function () {
|
|
124
|
+
return true
|
|
125
|
+
},
|
|
126
|
+
dragDrop: function (node, data) {
|
|
127
|
+
data.otherNode.moveTo(node, data.hitMode)
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
filter: {
|
|
131
|
+
autoApply: true, // Re-apply last filter if lazy data is loaded
|
|
132
|
+
autoExpand: true, // Expand all branches that contain matches while filtered
|
|
133
|
+
counter: false, // Show a badge with number of matching child nodes near parent icons
|
|
134
|
+
fuzzy: true, // Match single characters in order, e.g. 'fb' will match 'FooBar'
|
|
135
|
+
hideExpandedCounter: true, // Hide counter badge if parent is expanded
|
|
136
|
+
hideExpanders: true, // Hide expanders if all child nodes are hidden by filter
|
|
137
|
+
highlight: true, // Highlight matches by wrapping inside <mark> tags
|
|
138
|
+
leavesOnly: false, // Match end nodes only
|
|
139
|
+
nodata: true, // Display a 'no data' status node if result is empty
|
|
140
|
+
mode: "hide" // Grayout unmatched nodes (pass "hide" to remove unmatched node instead)
|
|
141
|
+
},
|
|
142
|
+
table: tableConfig,
|
|
143
|
+
gridnav: {
|
|
144
|
+
autofocusInput: false,
|
|
145
|
+
handleCursorKeys: true,
|
|
146
|
+
},
|
|
147
|
+
strings: treeStrings,
|
|
148
|
+
postProcess: function (event, data) {
|
|
149
|
+
setTimeout(function () {
|
|
150
|
+
loadValue($inputEl, treeWidgetData, data.tree)
|
|
151
|
+
}, 1)
|
|
152
|
+
},
|
|
153
|
+
select: function (event, data) {
|
|
154
|
+
if($inputEl.length > 0) {
|
|
155
|
+
let value = null
|
|
156
|
+
if (treeWidgetData.filter) {
|
|
157
|
+
value = data.tree.getSelectedNodes().map(function (node) {
|
|
158
|
+
return {'value': node.key, 'label': node.title}
|
|
159
|
+
})
|
|
160
|
+
$inputEl.val(JSON.stringify(value))
|
|
161
|
+
} else {
|
|
162
|
+
value = data.tree.getSelectedNodes().map(function (node) {
|
|
163
|
+
return node.key
|
|
164
|
+
}).join(", ")
|
|
165
|
+
if (treeWidgetData.multiselect === 2) {
|
|
166
|
+
value = JSON.stringify(data.tree.getSelectedNodes().map(function (node) {
|
|
167
|
+
return node.key
|
|
168
|
+
}))
|
|
169
|
+
}
|
|
170
|
+
let label = data.tree.getSelectedNodes().map(function (node) {
|
|
171
|
+
return node.title
|
|
172
|
+
}).join(", ")
|
|
173
|
+
$label.text(label)
|
|
174
|
+
$inputEl.val(value)
|
|
175
|
+
}
|
|
176
|
+
$inputEl[0].dispatchEvent(new CustomEvent('SBAutocompleteChange'))
|
|
177
|
+
$inputEl[0].dispatchEvent(new Event('change', {bubbles: true}))
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if(treeWidgetData.filter_by_table_data && data.originalEvent) {
|
|
182
|
+
const selectedKeys = data.tree.getSelectedNodes().map(function (node) {
|
|
183
|
+
return node.data.id
|
|
184
|
+
})
|
|
185
|
+
document.body.dispatchEvent(new CustomEvent("treeRowSelected", {detail: {data: selectedKeys}}))
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
enhanceTitle: function(event, data) {
|
|
189
|
+
const reorderActive = treeWidgetData.reorder_url
|
|
190
|
+
const nodeRendered = data.node.rendered
|
|
191
|
+
const filteringActive = data.node.tree.enableFilter
|
|
192
|
+
const detailUrlPresent = treeWidgetData.detail_url
|
|
193
|
+
const validVisibleNode = data.node.span && data.node.span.classList.contains("fancytree-node") && !data.node.tr.classList.contains("fancytree-hide")
|
|
194
|
+
if (detailUrlPresent && (!nodeRendered || filteringActive) && !reorderActive && validVisibleNode) {
|
|
195
|
+
const title = data.node.span.querySelector('.fancytree-title')
|
|
196
|
+
const titleLink = document.createElement('a')
|
|
197
|
+
const url = treeWidgetData.detail_url.replace(-1, data.node.data.id)
|
|
198
|
+
titleLink.innerHTML = title.innerHTML
|
|
199
|
+
titleLink.classList.add('link')
|
|
200
|
+
titleLink.href = url
|
|
201
|
+
title.innerHTML = ''
|
|
202
|
+
title.append(titleLink)
|
|
203
|
+
title.addEventListener('mousedown', function (e) {
|
|
204
|
+
e.preventDefault()
|
|
205
|
+
e.stopPropagation()
|
|
206
|
+
}, true)
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
renderNode: function (event, data) {
|
|
210
|
+
const reorderActive = treeWidgetData.reorder_url
|
|
211
|
+
const nodeRendered = data.node.rendered
|
|
212
|
+
const validVisibleNode = data.node.span && data.node.span.classList.contains("fancytree-node") && !data.node.tr.classList.contains("fancytree-hide")
|
|
213
|
+
if (nodeRendered && !reorderActive) {
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
let isLastSib = data.node && data.node.tr && data.node.tr.classList.contains('fancytree-lastsib')
|
|
217
|
+
isLastSib = isLastSib === undefined ? false : isLastSib
|
|
218
|
+
if (data.node.parent) {
|
|
219
|
+
data.node.treeLevel = data.node.parent.treeLevel + 1
|
|
220
|
+
data.node.treeAdditionalLevel = [{
|
|
221
|
+
level: data.node.treeLevel,
|
|
222
|
+
lastSib: isLastSib
|
|
223
|
+
}, ...data.node.parent.treeAdditionalLevel]
|
|
224
|
+
} else {
|
|
225
|
+
data.node.treeLevel = 0
|
|
226
|
+
data.node.treeAdditionalLevel = []
|
|
227
|
+
}
|
|
228
|
+
data.node.rendered = true
|
|
229
|
+
if (validVisibleNode) {
|
|
230
|
+
const expander = data.node.span.querySelector('.fancytree-expander')
|
|
231
|
+
const level = data.node.treeLevel
|
|
232
|
+
const additionalLevel = data.node.treeAdditionalLevel
|
|
233
|
+
expander.innerHTML = ""
|
|
234
|
+
expander.className = 'fancytree-expander'
|
|
235
|
+
expander.classList.add('level-' + level)
|
|
236
|
+
if (data.node.parent.expanded) {
|
|
237
|
+
expander.classList.add('expanded-parent')
|
|
238
|
+
}
|
|
239
|
+
additionalLevel.forEach((item, i) => {
|
|
240
|
+
if (i !== 0 && item.lastSib) {
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
const expanderAdditional = document.createElement('span')
|
|
244
|
+
expanderAdditional.classList.add('expander-additional')
|
|
245
|
+
if (i === 0) {
|
|
246
|
+
expanderAdditional.classList.add('expander-additional-last')
|
|
247
|
+
}
|
|
248
|
+
expanderAdditional.style.left = -(50 + 100 * i) + '%'
|
|
249
|
+
expander.append(expanderAdditional)
|
|
250
|
+
})
|
|
251
|
+
const expanderBorder = document.createElement('span')
|
|
252
|
+
expanderBorder.classList.add('expander-border')
|
|
253
|
+
expander.append(expanderBorder)
|
|
254
|
+
expander.append(document.createElement('div'))
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
renderColumns: function (event, data) {
|
|
258
|
+
const $tdList = $(data.node.tr).find(">td")
|
|
259
|
+
additionalColumns.forEach(function (column, index) {
|
|
260
|
+
let value = data.node.data[column.key]
|
|
261
|
+
if (column.hide_zero && value === 0) {
|
|
262
|
+
value = ""
|
|
263
|
+
}
|
|
264
|
+
$tdList.eq(1 + tableConfig.nodeColumnIdx + index).html(value)
|
|
265
|
+
})
|
|
266
|
+
},
|
|
267
|
+
init: function (event, data) {
|
|
268
|
+
if(treeWidgetData.filter_by_table_data) {
|
|
269
|
+
filterByTableData(data.tree)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
const clearSearchInput = function () {
|
|
275
|
+
$searchEl.val("")
|
|
276
|
+
$matchesEl.text("")
|
|
277
|
+
treeInstance.visit(function (node) {
|
|
278
|
+
node.rendered = false
|
|
279
|
+
})
|
|
280
|
+
treeInstance.clearFilter()
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const treeInstance = $.ui.fancytree.getTree('#' + treeWidgetData.input_id + '_tree')
|
|
284
|
+
$inputEl.on('SBTableFilterFormLoad', () => {
|
|
285
|
+
loadValue($inputEl, treeWidgetData, treeInstance)
|
|
286
|
+
})
|
|
287
|
+
$inputEl.on('clear', () => {
|
|
288
|
+
treeInstance.getSelectedNodes().map(node => {
|
|
289
|
+
node.setSelected(false)
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
$searchEl.on("keyup", function (e) {
|
|
293
|
+
let match = $(this).val()
|
|
294
|
+
let n = treeInstance.filterNodes(match)
|
|
295
|
+
|
|
296
|
+
if (e && e.which === $.ui.keyCode.ESCAPE || $.trim(match) === "") {
|
|
297
|
+
clearSearchInput()
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
$matchesEl.text("(" + n + " matches)")
|
|
301
|
+
}).trigger("focus")
|
|
302
|
+
|
|
303
|
+
$searchEl.on('search', function (e) {
|
|
304
|
+
// handle clear event of search input only if clicked on X
|
|
305
|
+
if (e.target.value) {
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
clearSearchInput()
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
treeInstance.saveTreeOrder = function () {
|
|
312
|
+
const order = JSON.stringify(treeInstance.toDict())
|
|
313
|
+
fetch(treeWidgetData.reorder_url, {
|
|
314
|
+
method: 'POST',
|
|
315
|
+
headers: {
|
|
316
|
+
"X-CSRFToken": window.csrf_token,
|
|
317
|
+
},
|
|
318
|
+
body: order
|
|
319
|
+
}).then(response => response.json())
|
|
320
|
+
.then(res => {
|
|
321
|
+
document.getElementById("notification-messages").innerHTML = res.messages
|
|
322
|
+
window.htmx.process(document.getElementById("notification-messages"))
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if(treeWidgetData.filter_by_table_data) {
|
|
327
|
+
document.body.addEventListener('tableDataProcessed', (e) => {
|
|
328
|
+
filterData = e.detail
|
|
329
|
+
if(treeInstance.getRootNode().getChildren()[0]["statusNodeType"] === "loading") {
|
|
330
|
+
return
|
|
331
|
+
}
|
|
332
|
+
filterByTableData(treeInstance)
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
document.body.addEventListener('treeDeselectAllRows', () => {
|
|
336
|
+
treeInstance.selectAll(false)
|
|
337
|
+
})
|
|
338
|
+
document.body.addEventListener('treeSelectAllRows', () => {
|
|
339
|
+
treeInstance.selectAll(true)
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const initAllTrees = function () {
|
|
345
|
+
$('.js-tree-widget').each(function (index, element) {
|
|
346
|
+
const $treeEl = $(element)
|
|
347
|
+
if ($treeEl.hasClass('fancytree-container')) {
|
|
348
|
+
return
|
|
349
|
+
}
|
|
350
|
+
const $dropdownMenu = $treeEl.closest('.dropdown-menu')
|
|
351
|
+
if ($dropdownMenu.length > 0) {
|
|
352
|
+
const initTreeOnShow = function () {
|
|
353
|
+
initTree($treeEl)
|
|
354
|
+
$dropdownMenu.prev().off('show.bs.dropdown', initTreeOnShow)
|
|
355
|
+
}
|
|
356
|
+
$dropdownMenu.prev().on('show.bs.dropdown', initTreeOnShow)
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
initTree($treeEl)
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
initAllTrees()
|
|
363
|
+
|
|
364
|
+
document.addEventListener('formset:added', () => {
|
|
365
|
+
initAllTrees()
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
const queryBuilderEl$ = $(".query-builder-advanced")
|
|
369
|
+
queryBuilderEl$.on("afterCreateRuleInput.queryBuilder", function () {
|
|
370
|
+
setTimeout(() => {
|
|
371
|
+
//next tick
|
|
372
|
+
initAllTrees()
|
|
373
|
+
}, 0)
|
|
374
|
+
})
|
|
375
|
+
})
|
|
376
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{% extends "sb_admin/actions/list.html" %}
|
|
2
|
+
{% load static sb_admin_tags i18n %}
|
|
3
|
+
|
|
4
|
+
{% block extrahead %}
|
|
5
|
+
{{ block.super }}
|
|
6
|
+
<style>
|
|
7
|
+
#table-columns-dropdown-wrapper {
|
|
8
|
+
display: none;
|
|
9
|
+
}
|
|
10
|
+
</style>
|
|
11
|
+
{% endblock %}
|
|
12
|
+
|
|
13
|
+
{% block tabulator_card %}
|
|
14
|
+
{% with enable_table_filter=request.reorder_active|yesno:',True' %}
|
|
15
|
+
{% if enable_table_filter %}
|
|
16
|
+
{{ block.super }}
|
|
17
|
+
{% else %}
|
|
18
|
+
<div class="overflow-hidden pb-8 relative tree-list-view">
|
|
19
|
+
{{ block.super }}
|
|
20
|
+
</div>
|
|
21
|
+
{% endif %}
|
|
22
|
+
{% endwith %}
|
|
23
|
+
{% endblock %}
|
|
24
|
+
|
|
25
|
+
{% block tabulator_custom_header %}
|
|
26
|
+
{% if not request.reorder_active %}
|
|
27
|
+
{% include content_context.tabulator_header_template_name %}
|
|
28
|
+
{% endif %}
|
|
29
|
+
{% endblock %}
|
|
30
|
+
{% block tabulator_body %}
|
|
31
|
+
{% with view_id|add:'_tree' as tree_id %}
|
|
32
|
+
<div class="overflow-auto w-full relative">
|
|
33
|
+
{% include "sb_admin/widgets/tree_base.html" with tree_main_column_name=list_title tree_reorder_url=content_context.tabulator_definition.treeReorderUrl tree_additional_columns=additional_columns tree_component_id=tree_id tree_data_url=tree_json_url tree_detail_url=content_context.tabulator_definition.tableDetailUrl hide_tree_search=True filter_by_table_data=enable_table_filter tree_show_checkbox=enable_table_filter tree_multiselect=enable_table_filter search_wrapper_classes="py-16 md:p-16" %}
|
|
34
|
+
</div>
|
|
35
|
+
{% endwith %}
|
|
36
|
+
{% if not request.reorder_active %}
|
|
37
|
+
<div class="hidden">
|
|
38
|
+
{{ block.super }}
|
|
39
|
+
</div>
|
|
40
|
+
{% endif %}
|
|
41
|
+
{% endblock %}
|
|
42
|
+
{% block tabulator_custom_footer %}
|
|
43
|
+
{% endblock %}
|
|
44
|
+
|
|
45
|
+
{% block actions %}
|
|
46
|
+
{% with view_id|add:'_tree' as tree_id %}
|
|
47
|
+
{% if request.request_data.action == 'action_enter_reorder' %}
|
|
48
|
+
<li class="max-sm:hidden">
|
|
49
|
+
<button onclick="$.ui.fancytree.getTree('#' + '{{ tree_id }}' + '_tree').saveTreeOrder()"
|
|
50
|
+
class="btn btn-empty">
|
|
51
|
+
{% trans 'Save Order' %}
|
|
52
|
+
</button>
|
|
53
|
+
</li>
|
|
54
|
+
{% endif %}
|
|
55
|
+
{% endwith %}
|
|
56
|
+
{{ block.super }}
|
|
57
|
+
{% endblock %}
|
|
58
|
+
|
|
59
|
+
{% block additional_js %}
|
|
60
|
+
{% if not request.reorder_active %}
|
|
61
|
+
{{ block.super }}
|
|
62
|
+
{% endif %}
|
|
63
|
+
{% endblock %}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{% load sb_admin_tags %}
|
|
2
|
+
|
|
3
|
+
<div class="dropdown-menu max-h-none w-248">
|
|
4
|
+
<div class="px-12 pt-8 border-b border-dark-200">
|
|
5
|
+
{% with tree_widget_id=filter_widget.view_id|add:"-"|add:filter_widget.input_id|add:"_tree" %}
|
|
6
|
+
<div class="relative -mx-12">
|
|
7
|
+
<input form="{{ filter_widget.view_id }}-filter-form" type="hidden"
|
|
8
|
+
id="{{ filter_widget.input_id }}" name="{{ filter_widget.input_name }}"
|
|
9
|
+
{% if not all_filters_visible %}disabled{% endif %}{% if filter_widget.get_default_value %} value="{{ filter_widget.get_default_value|get_json }}"{% endif %}>
|
|
10
|
+
{% include "sb_admin/widgets/tree_base.html" with tree_additional_columns=filter_widget.additional_columns tree_strings=filter_widget.tree_strings tree_filter=True tree_value=filter_widget.get_default_value tree_multiselect=filter_widget.multiselect tree_component_id=filter_widget.input_id tree_data_url=filter_widget.to_json.autocomplete_url tree_show_checkbox=True search_wrapper_classes="pb-8 px-12" table_wrapper_classes="max-h-432 overflow-auto custom-scrollbar" %}
|
|
11
|
+
</div>
|
|
12
|
+
{% endwith %}
|
|
13
|
+
</div>
|
|
14
|
+
{% include "sb_admin/filter_widgets/partials/clear.html" %}
|
|
15
|
+
</div>
|
|
16
|
+
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
{% block style_init %}{% endblock %}
|
|
26
26
|
|
|
27
27
|
<script>window.csrf_token = "{{ csrf_token }}"</script>
|
|
28
|
+
|
|
29
|
+
{% block jquery %}
|
|
30
|
+
<script src="{% static 'sb_admin/js/jquery-3.7.1.min.js' %}"></script>
|
|
31
|
+
{% endblock %}
|
|
28
32
|
{% block js_init %}
|
|
29
33
|
<script>
|
|
30
34
|
{% if const %}
|
|
@@ -35,12 +39,10 @@
|
|
|
35
39
|
}
|
|
36
40
|
</script>
|
|
37
41
|
{% endblock %}
|
|
38
|
-
{% if content_context.is_jquery_required %}
|
|
39
|
-
<script src="{% static 'sb_admin/js/jquery-3.7.1.min.js' %}"></script>
|
|
40
|
-
{% endif %}
|
|
41
|
-
{% block jquery %}
|
|
42
|
-
{% endblock %}
|
|
43
42
|
{% block tree_widget_static %}
|
|
43
|
+
<script src="{% static 'sb_admin/fancytree/jquery.fancytree-all-deps.min.js' %}"></script>
|
|
44
|
+
<script src="{% static 'sb_admin/dist/tree_widget.js' %}"></script>
|
|
45
|
+
<link rel="stylesheet" href="{% static 'sb_admin/dist/tree_widget_style.css' %}">
|
|
44
46
|
{% endblock %}
|
|
45
47
|
{% block extrahead %}{% endblock %}
|
|
46
48
|
<style>@media (min-width: 1200px){.xl\:\!block {display: block !important;}}</style>
|
|
@@ -8,4 +8,5 @@
|
|
|
8
8
|
window.sb_admin_translation_strings["reorder"] = '{% trans "Reorder" %}';
|
|
9
9
|
window.sb_admin_translation_strings["page"] = '{% blocktrans %}<strong>${from} - ${to}</strong> of <strong>${total}</strong><span class="max-xs:hidden"> items</span>{% endblocktrans %}'
|
|
10
10
|
window.sb_admin_translation_strings["page_empty"] = '{% blocktrans %}<strong>0</strong> items{% endblocktrans %}'
|
|
11
|
+
window.sb_admin_translation_strings["selected"] = '{% blocktrans %}${value} selected{% endblocktrans %}'
|
|
11
12
|
</script>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{% load static sb_admin_tags i18n %}
|
|
2
|
+
|
|
3
|
+
{% if not hide_tree_search %}
|
|
4
|
+
<div class="border-b border-dark-200 {{ search_wrapper_classes }}">
|
|
5
|
+
<div class="js-tree-widget-search relative">
|
|
6
|
+
{% trans 'Search' as search_string %}
|
|
7
|
+
<input id="{{ tree_component_id }}_search" name="search" placeholder="{{ tree_filter_placeholder|default:search_string }}" autocomplete="off" class="input pl-36" type="search">
|
|
8
|
+
<div class="absolute pl-10 left-0 top-0 bottom-0 flex items-center gap-8 rounded-r">
|
|
9
|
+
<svg class="w-20 h-20">
|
|
10
|
+
<use xlink:href="#Search"></use>
|
|
11
|
+
</svg>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
{% endif %}
|
|
16
|
+
<div class="{{ table_wrapper_classes }}">
|
|
17
|
+
<table style="width: 100%;" id="{{ tree_component_id }}_tree" class="js-tree-widget fancytree-ext-table" data-tree-data-id="{{ tree_component_id }}_data" data-tree-additional-columns-id="{{ tree_component_id }}_additional_columns" data-tree-strings-id="{{ tree_component_id }}_tree_strings">
|
|
18
|
+
<thead>
|
|
19
|
+
<tr>
|
|
20
|
+
{% if tree_show_checkbox %}<th></th>{% endif %}
|
|
21
|
+
<th class="text-left">{{ tree_main_column_name }}<span id="{{ tree_component_id }}_matches" class="ml-4"></span></th>
|
|
22
|
+
{% for column in tree_additional_columns %}
|
|
23
|
+
<th>{{ column.title }}</th>
|
|
24
|
+
{% endfor %}
|
|
25
|
+
</tr>
|
|
26
|
+
</thead>
|
|
27
|
+
<tbody>
|
|
28
|
+
<tr>
|
|
29
|
+
{% if tree_show_checkbox %}<td class="alignCenter fancytree-checkbox-column"></td>{% endif %}
|
|
30
|
+
<td></td>
|
|
31
|
+
{% for column in tree_additional_columns %}
|
|
32
|
+
<td></td>
|
|
33
|
+
{% endfor %}
|
|
34
|
+
</tr>
|
|
35
|
+
</tbody>
|
|
36
|
+
</table>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<script id="{{ tree_component_id }}_data" type="application/json">
|
|
40
|
+
{
|
|
41
|
+
"filter": {% if tree_filter %}true{% else %}false{% endif %},
|
|
42
|
+
"input_id": "{{ tree_component_id }}",
|
|
43
|
+
"data_url": "{{ tree_data_url }}",
|
|
44
|
+
"checkbox": {% if tree_show_checkbox %}true{% else %}false{% endif %},
|
|
45
|
+
"multiselect": {% if tree_multiselect %}2{% else %}1{% endif %},
|
|
46
|
+
"detail_url":"{{ tree_detail_url }}",
|
|
47
|
+
"reorder_url":"{{ tree_reorder_url }}",
|
|
48
|
+
"filter_by_table_data": {% if filter_by_table_data %}true{% else %}false{% endif %}
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
<script id="{{ tree_component_id }}_additional_columns" type="application/json">{{ tree_additional_columns|get_json|safe }}</script>
|
|
52
|
+
<script id="{{ tree_component_id }}_tree_strings" type="application/json">
|
|
53
|
+
{{ tree_strings|get_json|safe }}
|
|
54
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{% load sb_admin_tags %}
|
|
2
|
+
|
|
3
|
+
<div class="relative">
|
|
4
|
+
{% include 'sb_admin/widgets/includes/field_label.html' %}
|
|
5
|
+
<div id="{{ widget.attrs.id }}-wrapper" class="tree-widget-wrapper">
|
|
6
|
+
<input type="hidden" id="{{ widget.attrs.id }}" name="{{ widget.name }}"{% if widget.raw_value %} value="{{ widget.raw_value|get_json }}"{% endif %}>
|
|
7
|
+
<button
|
|
8
|
+
data-bs-toggle="dropdown"
|
|
9
|
+
aria-expanded="false"
|
|
10
|
+
data-bs-offset="[0, 8]"
|
|
11
|
+
class="btn px-10 font-normal w-full"
|
|
12
|
+
>
|
|
13
|
+
<span id="{{ widget.attrs.id }}_label">{% get_item widget.value_dict widget.raw_value widget.form_field.empty_label %}</span>
|
|
14
|
+
<svg class="ml-8">
|
|
15
|
+
<use xlink:href="#Down"></use>
|
|
16
|
+
</svg>
|
|
17
|
+
</button>
|
|
18
|
+
<div class="dropdown-menu max-h-none w-248">
|
|
19
|
+
<div class="py-8">
|
|
20
|
+
{% include "sb_admin/widgets/tree_base.html" with tree_additional_columns=widget.additional_columns tree_strings=widget.tree_strings tree_value=widget.raw_value tree_multiselect=filter_widget.multiselect tree_component_id=widget.attrs.id tree_data_url=filter_widget.to_json.autocomplete_url tree_show_checkbox=True table_wrapper_classes="max-h-432 overflow-auto custom-scrollbar" %}
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{% load sb_admin_tags %}
|
|
2
|
+
|
|
3
|
+
<div class="relative -mb-2">
|
|
4
|
+
<script>
|
|
5
|
+
document.currentScript.closest('.djn-table').querySelector('.djn-thead').classList.add('hidden');
|
|
6
|
+
</script>
|
|
7
|
+
<div id="{{ widget.attrs.id }}-wrapper" class="tree-widget-wrapper">
|
|
8
|
+
<input type="hidden" id="{{ widget.attrs.id }}" name="{{ widget.name }}"{% if widget.raw_value %}
|
|
9
|
+
value="{{ widget.raw_value|get_json }}"{% endif %}>
|
|
10
|
+
{% include "sb_admin/widgets/tree_base.html" with tree_main_column_name=filter_widget.form_field.label tree_strings=widget.tree_strings tree_additional_columns=widget.additional_columns tree_value=widget.raw_value tree_multiselect=filter_widget.multiselect tree_component_id=widget.attrs.id tree_data_url=filter_widget.to_json.autocomplete_url tree_show_checkbox=True table_wrapper_classes="max-h-432 overflow-auto custom-scrollbar" search_wrapper_classes="pb-16 px-16" %}
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|