accrete 0.0.23__py3-none-any.whl → 0.0.25__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.
- accrete/contrib/ui/__init__.py +1 -4
- accrete/contrib/ui/components.py +7 -5
- accrete/contrib/ui/context.py +11 -11
- accrete/contrib/ui/filter.py +9 -16
- accrete/contrib/ui/querystring.py +3 -77
- accrete/contrib/ui/static/css/accrete.css +131 -63
- accrete/contrib/ui/static/css/accrete.css.map +1 -1
- accrete/contrib/ui/static/css/accrete.scss +116 -22
- accrete/contrib/ui/static/css/icons.css +18 -0
- accrete/contrib/ui/static/js/filter.js +563 -476
- accrete/contrib/ui/static/js/filter_old.js +734 -0
- accrete/contrib/ui/templates/ui/layout.html +7 -7
- accrete/contrib/ui/templates/ui/partials/filter.html +15 -9
- accrete/contrib/ui/templates/ui/partials/header.html +5 -3
- accrete/contrib/ui/templates/ui/partials/pagination_detail.html +2 -2
- accrete/contrib/ui/templates/ui/partials/pagination_list.html +2 -2
- accrete/contrib/ui/templates/ui/partials/table_field.html +1 -0
- accrete/contrib/ui/templates/ui/table.html +14 -12
- accrete/contrib/user/models.py +5 -0
- accrete/contrib/user/views.py +1 -1
- accrete/forms.py +7 -5
- accrete/models.py +21 -0
- accrete/queries.py +0 -1
- accrete/querystring.py +89 -0
- accrete/tenant.py +4 -0
- accrete/utils/dates.py +2 -1
- {accrete-0.0.23.dist-info → accrete-0.0.25.dist-info}/METADATA +1 -1
- {accrete-0.0.23.dist-info → accrete-0.0.25.dist-info}/RECORD +30 -29
- {accrete-0.0.23.dist-info → accrete-0.0.25.dist-info}/WHEEL +1 -1
- accrete/shortcuts.py +0 -8
- {accrete-0.0.23.dist-info → accrete-0.0.25.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,734 @@
|
|
1
|
+
const queryBlock = document.getElementById('query-block');
|
2
|
+
const queryInput = document.getElementById('query-input');
|
3
|
+
const queryInputControl = document.getElementById('query-input-control');
|
4
|
+
const queryInputSelect = document.getElementById('query-input-select');
|
5
|
+
const queryInputSelectControl = document.getElementById('query-input-select-control');
|
6
|
+
const queryInputApply = document.getElementById('query-input-apply');
|
7
|
+
const queryParamsDropdown = document.getElementById('query-params-dropdown');
|
8
|
+
const queryParamElements = document.querySelectorAll('.query-param');
|
9
|
+
const queryParamsElements = document.querySelectorAll('.query-params');
|
10
|
+
const queryTags = document.getElementById('query-tags');
|
11
|
+
const modalFilterButton = document.getElementById('modal-filter-button');
|
12
|
+
const filterPanel = document.getElementById('filter-panel');
|
13
|
+
const filterModal = document.getElementById('filter-modal');
|
14
|
+
const modalContent = document.getElementById('modal-content');
|
15
|
+
const queryTextElement = document.getElementById('query-text');
|
16
|
+
const queryTextNotificationParameterElement = document.getElementById('query-notification-parameter');
|
17
|
+
let activeInput = queryInput;
|
18
|
+
const orLabel = queryTags.getAttribute('data-or-label')
|
19
|
+
const andLabel = queryTags.getAttribute('data-and-label')
|
20
|
+
const xorLabel = queryTags.getAttribute('data-xor-label')
|
21
|
+
const query = new URL(window.location.href).searchParams.get('q') || '[]';
|
22
|
+
const normalizedQuery = normalizeQueryString(JSON.parse(query));
|
23
|
+
|
24
|
+
queryInput.addEventListener('focus', showQueryParams);
|
25
|
+
queryInput.addEventListener('keyup', navigateQueryInput);
|
26
|
+
queryInputApply.addEventListener('click', applyQueryInput);
|
27
|
+
queryParamElements.forEach((element) => {
|
28
|
+
element.addEventListener('keyup', navigateQueryParams);
|
29
|
+
})
|
30
|
+
queryParamElements.forEach((element) => {
|
31
|
+
element.addEventListener('mouseup', clickQueryParams);
|
32
|
+
})
|
33
|
+
window.onclick = function(event) {
|
34
|
+
const dontHide = [
|
35
|
+
'#query-block', '#query-input', '#query-params-dropdown', '#param-input',
|
36
|
+
'.query-param', '.query-params', '.query-param > p', '#query-operation',
|
37
|
+
'#query-operation > span', '#query-operation-select',
|
38
|
+
'#query-operation-select > option', '#query-params-dropdown > p > label',
|
39
|
+
'#query-params-dropdown > p', '#query-params-dropdown > p > label > input',
|
40
|
+
'#query-input-select', '#query-input-select > option'
|
41
|
+
];
|
42
|
+
if (!event.target.matches(dontHide)) {
|
43
|
+
queryParamsElements.forEach((element) => {
|
44
|
+
element.classList.add('is-hidden');
|
45
|
+
})
|
46
|
+
if (!filterModal.classList.contains('is-active')) {
|
47
|
+
queryParamsDropdown.classList.add('is-hidden');
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
modalFilterButton.onclick = function () {
|
53
|
+
modalContent.appendChild(queryBlock);
|
54
|
+
filterModal.classList.add('is-active');
|
55
|
+
queryParamsDropdown.classList.remove('is-hidden');
|
56
|
+
activeInput.select()
|
57
|
+
}
|
58
|
+
|
59
|
+
buildActiveQuery();
|
60
|
+
setDefaultTerm();
|
61
|
+
|
62
|
+
|
63
|
+
function normalizeQueryString(queryString, left=null) {
|
64
|
+
let normalizedQueryString = []
|
65
|
+
for (let item of queryString) {
|
66
|
+
if (isString(item)) {
|
67
|
+
normalizedQueryString.push(item)
|
68
|
+
left = item
|
69
|
+
}
|
70
|
+
else if (isObject(item)) {
|
71
|
+
for (let k in item) {
|
72
|
+
if (left && !isString(left)) {
|
73
|
+
normalizedQueryString.push('&')
|
74
|
+
}
|
75
|
+
normalizedQueryString.push({[k]: item[k]})
|
76
|
+
left = item
|
77
|
+
}
|
78
|
+
}
|
79
|
+
else if (isArray(item)) {
|
80
|
+
if (left && !isString(left)) {
|
81
|
+
normalizedQueryString.push('&')
|
82
|
+
}
|
83
|
+
normalizedQueryString.push([normalizeQueryString(item)])
|
84
|
+
left = item
|
85
|
+
}
|
86
|
+
}
|
87
|
+
return normalizedQueryString
|
88
|
+
}
|
89
|
+
|
90
|
+
function isObject(item) {
|
91
|
+
return Object.prototype.toString.apply(item) === '[object Object]'
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
function isArray(item) {
|
96
|
+
return Object.prototype.toString.apply(item) === '[object Array]'
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
function isString(item) {
|
101
|
+
return Object.prototype.toString.apply(item) === '[object String]'
|
102
|
+
}
|
103
|
+
|
104
|
+
|
105
|
+
function closeFilterModal() {
|
106
|
+
buildActiveQuery();
|
107
|
+
filterModal.classList.remove('is-active');
|
108
|
+
filterPanel.appendChild(queryBlock);
|
109
|
+
}
|
110
|
+
|
111
|
+
|
112
|
+
function setDefaultTerm() {
|
113
|
+
const defaultTerm = queryInput.getAttribute('data-default-term');
|
114
|
+
if (defaultTerm) {
|
115
|
+
const element = getParamElement(defaultTerm);
|
116
|
+
setParam(element);
|
117
|
+
} else {
|
118
|
+
// activeInput.select();
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
function buildActiveQuery() {
|
123
|
+
removeQueryTags();
|
124
|
+
let currentTagBlock = getOrCreateQueryGroup();
|
125
|
+
queryTags.appendChild(currentTagBlock)
|
126
|
+
buildQueryFromQueryString(normalizeQueryString(JSON.parse(query)), currentTagBlock, '&');
|
127
|
+
}
|
128
|
+
|
129
|
+
function buildQueryFromQueryString(jsonQuery, queryGroup, operator='&', left=null, offset=0) {
|
130
|
+
for (let i = 0; i < jsonQuery.length; i++) {
|
131
|
+
if (isString(jsonQuery[i])) {
|
132
|
+
operator = jsonQuery[i]
|
133
|
+
}
|
134
|
+
// if (left && !(isObject(left) && isObject(jsonQuery[i]) && operator === '&')) {
|
135
|
+
// addOperatorElement(queryGroup, operator, i + offset);
|
136
|
+
// left = null;
|
137
|
+
// operator = '&'
|
138
|
+
// }
|
139
|
+
if (isObject(jsonQuery[i])) {
|
140
|
+
buildTagFromObject(queryGroup, jsonQuery[i], i + offset, left)
|
141
|
+
left = jsonQuery[i]
|
142
|
+
// left = null
|
143
|
+
}
|
144
|
+
else if (isArray(jsonQuery[i])) {
|
145
|
+
let subQueryGroup = buildQueryGroup(operator);
|
146
|
+
queryGroup.appendChild(subQueryGroup);
|
147
|
+
let new_offset = buildQueryFromQueryString(jsonQuery[i], subQueryGroup, operator, null, offset)
|
148
|
+
offset += new_offset
|
149
|
+
left = jsonQuery[i]
|
150
|
+
}
|
151
|
+
offset++
|
152
|
+
}
|
153
|
+
return offset
|
154
|
+
}
|
155
|
+
|
156
|
+
function addOperatorElement(queryGroup, operator, idx) {
|
157
|
+
queryGroup.appendChild(createOperatorElement(operator, idx))
|
158
|
+
}
|
159
|
+
|
160
|
+
function createOperatorElement(operator, idx) {
|
161
|
+
let opElement = document.createElement('div')
|
162
|
+
opElement.classList.add('mb-1')
|
163
|
+
opElement.setAttribute('queryIdx', idx)
|
164
|
+
if (operator === '&') {opElement.innerText = andLabel}
|
165
|
+
else if (operator === '|') {opElement.innerText = orLabel}
|
166
|
+
else if (operator === '^') {opElement.innerText = xorLabel}
|
167
|
+
return opElement
|
168
|
+
}
|
169
|
+
|
170
|
+
function buildTagFromObject(queryGroup, object, idx, operator) {
|
171
|
+
for (let term in object) {
|
172
|
+
const tag = buildQueryTag(term, object[term], operator);
|
173
|
+
tag.setAttribute('queryIdx', idx)
|
174
|
+
queryGroup.appendChild(tag);
|
175
|
+
// queryGroup.innerHTML += tag
|
176
|
+
operator = '&'
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
function getOrCreateQueryGroup() {
|
181
|
+
if (queryTags.firstElementChild?.classList.contains('query-group')) {
|
182
|
+
return queryTags.firstElementChild
|
183
|
+
}
|
184
|
+
const queryGroup = buildQueryGroup()
|
185
|
+
queryTags.appendChild(queryGroup)
|
186
|
+
return queryGroup
|
187
|
+
}
|
188
|
+
|
189
|
+
function buildQueryTag(term, operator, value=null) {
|
190
|
+
let tag = null;
|
191
|
+
let displayValue = '';
|
192
|
+
const element = getParamElement(term, value);
|
193
|
+
const dataType = element.getAttribute('data-type');
|
194
|
+
const text = getCompleteQueryText(element);
|
195
|
+
if (dataType === 'bool') {
|
196
|
+
displayValue = element.firstElementChild.text;
|
197
|
+
}
|
198
|
+
else if (dataType === 'selection') {
|
199
|
+
const option = element.querySelector(
|
200
|
+
`.param-options option[value="${param[p]}"]`
|
201
|
+
);
|
202
|
+
displayValue = option.textContent;
|
203
|
+
}
|
204
|
+
else {
|
205
|
+
displayValue = value;
|
206
|
+
}
|
207
|
+
tag = buildTag(text, term, value, displayValue, operator);
|
208
|
+
|
209
|
+
return tag
|
210
|
+
}
|
211
|
+
|
212
|
+
|
213
|
+
function removeQueryTags() {
|
214
|
+
while (queryTags.firstElementChild) {
|
215
|
+
queryTags.firstElementChild.remove();
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
function buildActiveQueryTag(param) {
|
220
|
+
let tag = null;
|
221
|
+
let displayValue = '';
|
222
|
+
let value = null;
|
223
|
+
for (let p in param) {
|
224
|
+
if (typeof param[p] == 'boolean') {
|
225
|
+
value = param[p]
|
226
|
+
}
|
227
|
+
const element = getParamElement(p, value);
|
228
|
+
const dataType = element.getAttribute('data-type');
|
229
|
+
const text = getCompleteQueryText(element);
|
230
|
+
if (dataType === 'bool') {
|
231
|
+
displayValue = element.firstElementChild.text;
|
232
|
+
}
|
233
|
+
else if (dataType === 'selection') {
|
234
|
+
const option = element.querySelector(
|
235
|
+
`.param-options option[value="${param[p]}"]`
|
236
|
+
);
|
237
|
+
displayValue = option.textContent;
|
238
|
+
}
|
239
|
+
else {
|
240
|
+
displayValue = param[p];
|
241
|
+
}
|
242
|
+
tag = buildTag(text, p, param[p], displayValue);
|
243
|
+
}
|
244
|
+
return tag
|
245
|
+
}
|
246
|
+
|
247
|
+
function apply() {
|
248
|
+
const tagBlocks = document.querySelectorAll('.query-tag-block');
|
249
|
+
let url = new URL(window.location)
|
250
|
+
let completeQuery = [];
|
251
|
+
tagBlocks.forEach((tagBlock) => {
|
252
|
+
let query = [];
|
253
|
+
for (let tag of tagBlock.children) {
|
254
|
+
if (tag.classList.contains('query-tag')) {
|
255
|
+
const param = tag.getAttribute('data-param');
|
256
|
+
let value = tag.getAttribute('data-value');
|
257
|
+
if (tag.getAttribute('data-is-bool') === 'true') {
|
258
|
+
value = value === 'true'
|
259
|
+
}
|
260
|
+
query.push({[param]: value})
|
261
|
+
}
|
262
|
+
else if (tag.classList.contains('query-tag-group')) {
|
263
|
+
let orQuery = [];
|
264
|
+
for (let subTag of tag.children) {
|
265
|
+
if (subTag.classList.contains('query-tag')) {
|
266
|
+
const param = subTag.getAttribute('data-param');
|
267
|
+
let value = subTag.getAttribute('data-value');
|
268
|
+
if (subTag.getAttribute('data-is-bool') === 'true') {
|
269
|
+
value = value === 'true'
|
270
|
+
}
|
271
|
+
orQuery.push({[param]: value});
|
272
|
+
}
|
273
|
+
}
|
274
|
+
if (orQuery.length) {
|
275
|
+
query.push(orQuery);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
}
|
279
|
+
completeQuery.push(query);
|
280
|
+
})
|
281
|
+
url.searchParams.set('q', JSON.stringify(completeQuery));
|
282
|
+
let queryApply = document.getElementById('query-apply');
|
283
|
+
let queryApplyEvent = new Event('click');
|
284
|
+
queryApply.setAttribute('hx-get', url.toString());
|
285
|
+
htmx.process(queryApply);
|
286
|
+
queryApply.dispatchEvent(queryApplyEvent);
|
287
|
+
}
|
288
|
+
|
289
|
+
|
290
|
+
function resetFilter() {
|
291
|
+
const baseURl = window.location.href.split('?')[0];
|
292
|
+
window.location.assign(baseURl);
|
293
|
+
}
|
294
|
+
|
295
|
+
function applyQueryInput(event) {
|
296
|
+
event.stopPropagation();
|
297
|
+
const text = queryInput.getAttribute('data-text');
|
298
|
+
const param = queryInput.getAttribute('data-param');
|
299
|
+
const value = activeInput.value;
|
300
|
+
if (!activeInput.reportValidity()) {return}
|
301
|
+
let displayValue = value;
|
302
|
+
if (activeInput === queryInputSelect) {
|
303
|
+
displayValue = activeInput.selectedOptions[0].textContent;
|
304
|
+
}
|
305
|
+
if (value && param) {
|
306
|
+
addQueryTag(text, param, value, displayValue);
|
307
|
+
// setDefaultTerm();
|
308
|
+
} else if (value && !param) {
|
309
|
+
queryTextElement.classList.add('is-hidden');
|
310
|
+
queryTextNotificationParameterElement.classList.remove('is-hidden');
|
311
|
+
resetQueryInput();
|
312
|
+
} else if (!value && param) {
|
313
|
+
activeInput.select();
|
314
|
+
} else if (!value && !param) {
|
315
|
+
resetQueryInput();
|
316
|
+
}
|
317
|
+
}
|
318
|
+
|
319
|
+
function showQueryParams() {
|
320
|
+
document.getElementById('query-params-dropdown').classList.remove(
|
321
|
+
'is-hidden'
|
322
|
+
);
|
323
|
+
}
|
324
|
+
|
325
|
+
function navigateQueryInput(event) {
|
326
|
+
if (event.key === 'Enter') {
|
327
|
+
applyQueryInput(event);
|
328
|
+
}
|
329
|
+
if (event.key === 'Escape') {
|
330
|
+
queryParamsDropdown.classList.add('is-hidden');
|
331
|
+
}
|
332
|
+
if (event.key === 'ArrowDown') {
|
333
|
+
if (queryParamsDropdown.classList.contains('is-hidden')) {
|
334
|
+
queryParamsDropdown.classList.remove('is-hidden');
|
335
|
+
}
|
336
|
+
if (!queryInput.type in ['date', 'datetime-local', 'number']) {
|
337
|
+
queryParamsDropdown.firstElementChild.focus({ focusVisible: true });
|
338
|
+
}
|
339
|
+
|
340
|
+
}
|
341
|
+
}
|
342
|
+
|
343
|
+
function clickQueryParams(event) {
|
344
|
+
event.stopPropagation();
|
345
|
+
const queryParam = event.target.parentElement;
|
346
|
+
const queryParams = queryParam.querySelector(
|
347
|
+
'.query-params'
|
348
|
+
);
|
349
|
+
if (queryParams && queryParams.classList.contains('is-hidden')) {
|
350
|
+
queryParams.classList.remove('is-hidden');
|
351
|
+
}
|
352
|
+
else {
|
353
|
+
const subQueryParams = queryParam.querySelectorAll(
|
354
|
+
'.query-params'
|
355
|
+
);
|
356
|
+
subQueryParams.forEach((element) => {
|
357
|
+
element.classList.add('is-hidden');
|
358
|
+
})
|
359
|
+
}
|
360
|
+
if (!queryParam.querySelector('.query-params')) {
|
361
|
+
setParam(queryParam)
|
362
|
+
}
|
363
|
+
}
|
364
|
+
|
365
|
+
function setParam(queryParam) {
|
366
|
+
const completeParam = getCompleteQueryParam(queryParam);
|
367
|
+
const dataType = queryParam.getAttribute('data-type');
|
368
|
+
const text = getCompleteQueryText(queryParam);
|
369
|
+
resetQueryInput();
|
370
|
+
setInputType(dataType, completeParam, text,
|
371
|
+
queryParam.getAttribute('data-step') || null
|
372
|
+
);
|
373
|
+
if (dataType === 'bool') {
|
374
|
+
let value = queryParam.getAttribute('data-value');
|
375
|
+
value = value === 'True';
|
376
|
+
addQueryTag(text, completeParam, value, queryParam.firstElementChild.text);
|
377
|
+
setInputType('text', '', '');
|
378
|
+
queryTextNotificationParameterElement.classList.add('is-hidden')
|
379
|
+
queryTextElement.innerText = '';
|
380
|
+
queryTextElement.classList.add('is-hidden')
|
381
|
+
}
|
382
|
+
else if (dataType === 'selection') {
|
383
|
+
const options = queryParam.querySelector('.param-options');
|
384
|
+
activeInput = queryInputSelect;
|
385
|
+
queryInputSelect.innerHTML = options.innerHTML;
|
386
|
+
queryInputSelectControl.classList.remove('is-hidden');
|
387
|
+
queryInputControl.classList.add('is-hidden');
|
388
|
+
queryInput.setAttribute('data-param', completeParam);
|
389
|
+
queryInput.setAttribute('data-text', text);
|
390
|
+
queryTextNotificationParameterElement.classList.add('is-hidden')
|
391
|
+
queryTextElement.innerText = text;
|
392
|
+
queryTextElement.classList.remove('is-hidden')
|
393
|
+
|
394
|
+
}
|
395
|
+
queryInput.select();
|
396
|
+
}
|
397
|
+
|
398
|
+
function navigateQueryParams(event) {
|
399
|
+
event.stopPropagation();
|
400
|
+
let elementToFocus = null;
|
401
|
+
const isSubQuery = event.target.parentElement.classList.contains(
|
402
|
+
'query-params'
|
403
|
+
);
|
404
|
+
const hasSubQuery= event.target.querySelectorAll('.query-params');
|
405
|
+
|
406
|
+
if (event.key === 'ArrowUp') {
|
407
|
+
if (event.target.previousElementSibling) {
|
408
|
+
elementToFocus = event.target.previousElementSibling;
|
409
|
+
}
|
410
|
+
else if (event.target.parentElement.id === 'query-params-dropdown') {
|
411
|
+
elementToFocus = queryInput;
|
412
|
+
elementToFocus.select();
|
413
|
+
}
|
414
|
+
else if (event.target.parentElement.classList.contains('query-param')) {}
|
415
|
+
}
|
416
|
+
else if (event.key === 'ArrowDown') {
|
417
|
+
elementToFocus = event.target.nextElementSibling;
|
418
|
+
}
|
419
|
+
else if (event.key === 'Escape') {
|
420
|
+
elementToFocus = queryInput;
|
421
|
+
elementToFocus.select();
|
422
|
+
queryParamsElements.forEach((element) => {
|
423
|
+
element.classList.add('is-hidden');
|
424
|
+
})
|
425
|
+
|
426
|
+
}
|
427
|
+
else if (event.key === 'ArrowRight') {
|
428
|
+
if (hasSubQuery) {
|
429
|
+
const queryParams= event.target.querySelector('.query-params');
|
430
|
+
if (queryParams) {
|
431
|
+
queryParams.classList.remove('is-hidden');
|
432
|
+
elementToFocus = queryParams.firstElementChild;
|
433
|
+
}
|
434
|
+
}
|
435
|
+
}
|
436
|
+
else if (event.key === 'ArrowLeft') {
|
437
|
+
if (isSubQuery) {
|
438
|
+
elementToFocus = event.target.parentElement.parentElement;
|
439
|
+
event.target.parentElement.classList.add('is-hidden');
|
440
|
+
}
|
441
|
+
}
|
442
|
+
if (elementToFocus) {
|
443
|
+
elementToFocus.focus();
|
444
|
+
}
|
445
|
+
|
446
|
+
if (event.key === 'Enter') {
|
447
|
+
const param = event.target.getAttribute('data-param');
|
448
|
+
const value = queryInput.value;
|
449
|
+
const text = getCompleteQueryText(event.target)
|
450
|
+
addQueryTag(text, param, value);
|
451
|
+
}
|
452
|
+
}
|
453
|
+
|
454
|
+
function getParamElement(param, value=null) {
|
455
|
+
const invert = param.startsWith('~');
|
456
|
+
if (invert) {
|
457
|
+
param = param.slice(1);
|
458
|
+
}
|
459
|
+
const parts = param.split('__');
|
460
|
+
let paramElement = queryParamsDropdown.querySelector(
|
461
|
+
`:scope > div[data-param="${parts[0]}"]`
|
462
|
+
);
|
463
|
+
for (let i = 1; i < parts.length; i++) {
|
464
|
+
let selector = `:scope * div[data-param="${parts[i]}"]`;
|
465
|
+
if (i + 1 === parts.length) {
|
466
|
+
if (invert) {
|
467
|
+
selector += `[data-param-invert="true"]`;
|
468
|
+
}
|
469
|
+
if (typeof value === 'boolean') {
|
470
|
+
if (value) {
|
471
|
+
selector += `[data-value="True"]`;
|
472
|
+
} else {
|
473
|
+
selector += `[data-value="False"]`;
|
474
|
+
}
|
475
|
+
}
|
476
|
+
// else if (value) {
|
477
|
+
// selector += `[data-value="${value}"]`;
|
478
|
+
// }
|
479
|
+
}
|
480
|
+
paramElement = paramElement.querySelector(selector);
|
481
|
+
}
|
482
|
+
return paramElement
|
483
|
+
}
|
484
|
+
|
485
|
+
function getQueryTextParts(element) {
|
486
|
+
let currentElement = element;
|
487
|
+
let names = [];
|
488
|
+
names.push(currentElement.firstElementChild.innerText);
|
489
|
+
while (currentElement.parentElement.parentElement.classList.contains('query-param')) {
|
490
|
+
currentElement = currentElement.parentElement.parentElement;
|
491
|
+
names.push(currentElement.firstElementChild.innerText);
|
492
|
+
}
|
493
|
+
return names.reverse()
|
494
|
+
}
|
495
|
+
|
496
|
+
function getCompleteQueryText(element) {
|
497
|
+
let names = getQueryTextParts(element);
|
498
|
+
return names.join(' \u2192 ')
|
499
|
+
}
|
500
|
+
|
501
|
+
function getCompleteQueryParam(element) {
|
502
|
+
let currentElement = element;
|
503
|
+
const invert = currentElement.getAttribute('data-param-invert');
|
504
|
+
let params = [];
|
505
|
+
params.push(currentElement.getAttribute('data-param'));
|
506
|
+
while (currentElement.parentElement.parentElement.classList.contains('query-param')) {
|
507
|
+
currentElement = currentElement.parentElement.parentElement;
|
508
|
+
params.push(currentElement.getAttribute('data-param'))
|
509
|
+
}
|
510
|
+
let paramString = params.reverse().join('__')
|
511
|
+
|
512
|
+
if (invert === 'true') {
|
513
|
+
paramString = '~'.concat(paramString)
|
514
|
+
}
|
515
|
+
return paramString
|
516
|
+
}
|
517
|
+
|
518
|
+
function addQueryTag(text, param, value, displayValue) {
|
519
|
+
const operation = document.getElementById('query-operation-select').value;
|
520
|
+
const selectedTag= queryTags.querySelector('.selected-query-tag');
|
521
|
+
if (!queryTags.childElementCount) {
|
522
|
+
let tagBlock = buildTagBlock();
|
523
|
+
let tag = buildTag(text, param, value, displayValue);
|
524
|
+
tagBlock.appendChild(tag);
|
525
|
+
queryTags.appendChild(tagBlock);
|
526
|
+
}
|
527
|
+
else if (operation === 'and' && selectedTag) {
|
528
|
+
selectedTag.parentElement.appendChild(buildTag(text, param, value, displayValue));
|
529
|
+
}
|
530
|
+
else if (operation === 'and' && !selectedTag) {
|
531
|
+
queryTags.lastElementChild.appendChild(buildTag(text, param, value, displayValue));
|
532
|
+
}
|
533
|
+
else if (operation === 'or' && selectedTag) {
|
534
|
+
if (selectedTag.classList.contains('query-tag-group')) {
|
535
|
+
let tag = buildTag(text, param, value, displayValue);
|
536
|
+
selectedTag.appendChild(tag);
|
537
|
+
}
|
538
|
+
else {
|
539
|
+
let tagGroup = buildTagGroup();
|
540
|
+
let tag = buildTag(text, param, value, displayValue);
|
541
|
+
selectedTag.parentElement.insertBefore(tagGroup, selectedTag);
|
542
|
+
tagGroup.appendChild(selectedTag);
|
543
|
+
tagGroup.appendChild(tag);
|
544
|
+
selectedTag.classList.remove('selected-query-tag');
|
545
|
+
tagGroup.classList.add('selected-query-tag');
|
546
|
+
}
|
547
|
+
}
|
548
|
+
else if (operation === 'or' && !selectedTag) {
|
549
|
+
const tagBlock = buildTagBlock();
|
550
|
+
const tag = buildTag(text, param, value, displayValue)
|
551
|
+
const tagBlockLabel = buildTagBlockLabel();
|
552
|
+
tagBlock.appendChild(tag);
|
553
|
+
queryTags.appendChild(tagBlockLabel);
|
554
|
+
queryTags.appendChild(tagBlock);
|
555
|
+
}
|
556
|
+
// if (!filterModal.classList.contains('is-active')) {
|
557
|
+
// apply();
|
558
|
+
// }
|
559
|
+
apply();
|
560
|
+
}
|
561
|
+
|
562
|
+
function unselectSingleObject(pk) {
|
563
|
+
const tag = buildActiveQueryTag(JSON.parse(`{"~id__exact": ${pk}}`));
|
564
|
+
if (!queryTags.childElementCount) {
|
565
|
+
const tagBlock = buildTagBlock();
|
566
|
+
tagBlock.appendChild(tag);
|
567
|
+
queryTags.appendChild(tagBlock);
|
568
|
+
} else {
|
569
|
+
queryTags.lastElementChild.appendChild(tag);
|
570
|
+
}
|
571
|
+
// if (!filterModal.classList.contains('is-active')) {
|
572
|
+
// apply();
|
573
|
+
// }
|
574
|
+
apply();
|
575
|
+
}
|
576
|
+
|
577
|
+
function buildTagBlock() {
|
578
|
+
let container = document.createElement('div');
|
579
|
+
container.classList.add('query-group');
|
580
|
+
return container
|
581
|
+
}
|
582
|
+
|
583
|
+
function buildQueryGroup(operator=null, title=null) {
|
584
|
+
let container = document.createElement('div');
|
585
|
+
container.classList.add('query-group');
|
586
|
+
container.setAttribute('data-operator', operator || '&')
|
587
|
+
// container.innerText = title;
|
588
|
+
return container
|
589
|
+
}
|
590
|
+
|
591
|
+
function buildTagBlockLabel() {
|
592
|
+
const blockLabel = document.createElement('span');
|
593
|
+
blockLabel.innerText = queryTags.getAttribute('data-or-label');
|
594
|
+
blockLabel.classList.add('query-or-label');
|
595
|
+
return blockLabel
|
596
|
+
}
|
597
|
+
|
598
|
+
function buildTagGroup() {
|
599
|
+
let container= document.createElement('div');
|
600
|
+
container.classList.add('query-tag-group');
|
601
|
+
container.addEventListener('click', setSelectedTag);
|
602
|
+
return container
|
603
|
+
}
|
604
|
+
|
605
|
+
function buildTag(text, param, value, displayValue, operator) {
|
606
|
+
let container = document.createElement('div');
|
607
|
+
let operatorSpan = document.createElement('span');
|
608
|
+
let operatorSelection = document.createElement('select')
|
609
|
+
let textSpan = document.createElement('span');
|
610
|
+
let deleteSpan = document.createElement('span');
|
611
|
+
let deleteButton = document.createElement('button');
|
612
|
+
container.classList.add('query-tag');
|
613
|
+
container.tabIndex = -1;
|
614
|
+
textSpan.classList.add('query-tag-text', 'is-size-7', 'is-unselectable');
|
615
|
+
if (displayValue) {
|
616
|
+
text = text.concat(': ', displayValue);
|
617
|
+
}
|
618
|
+
textSpan.innerText = text;
|
619
|
+
deleteSpan.classList.add(
|
620
|
+
'is-flex', 'is-flex-direction-column',
|
621
|
+
'is-justify-content-space-around', 'ml-1'
|
622
|
+
);
|
623
|
+
deleteButton.classList.add('delete');
|
624
|
+
deleteSpan.appendChild(deleteButton);
|
625
|
+
container.appendChild(operatorSpan);
|
626
|
+
container.appendChild(textSpan);
|
627
|
+
container.appendChild(deleteSpan);
|
628
|
+
container.addEventListener('click', setSelectedTag);
|
629
|
+
deleteButton.addEventListener('click', deleteTag);
|
630
|
+
container.setAttribute('data-param', param);
|
631
|
+
container.setAttribute('data-value', value);
|
632
|
+
container.setAttribute('data-is-bool', String(typeof value === 'boolean'));
|
633
|
+
return container
|
634
|
+
// return new DOMParser().parseFromString(templateTag(text), 'text/html')
|
635
|
+
// return templateTag(text);
|
636
|
+
}
|
637
|
+
|
638
|
+
function templateTag(text) {
|
639
|
+
return `
|
640
|
+
<div class="query-tag" tabindex="-1" onclick="setSelectedTag()">
|
641
|
+
<span>
|
642
|
+
<select class="select">
|
643
|
+
<option>AND</option>
|
644
|
+
<option>OR</option>
|
645
|
+
</select>
|
646
|
+
</span>
|
647
|
+
<span class="query-tag-text is-size-7 is-unselectable">
|
648
|
+
${text}
|
649
|
+
</span>
|
650
|
+
<span class="is-flex is-flex-direction-column is-justify-content-space-around ml-1">
|
651
|
+
<button class="delete" onclick="deleteTag()"/>
|
652
|
+
</span>
|
653
|
+
</div>
|
654
|
+
`
|
655
|
+
}
|
656
|
+
|
657
|
+
function setSelectedTag(event) {
|
658
|
+
event.stopPropagation();
|
659
|
+
let target = event.currentTarget
|
660
|
+
if (target.parentElement.classList.contains('query-tag-group')) {
|
661
|
+
target = event.currentTarget.parentElement;
|
662
|
+
}
|
663
|
+
const toDeactivate = target.classList.contains('selected-query-tag');
|
664
|
+
const selectedTags= queryBlock.querySelectorAll('.selected-query-tag');
|
665
|
+
selectedTags.forEach((element) => {
|
666
|
+
element.classList.remove('selected-query-tag');
|
667
|
+
})
|
668
|
+
if (!toDeactivate) {
|
669
|
+
target.classList.add('selected-query-tag');
|
670
|
+
}
|
671
|
+
}
|
672
|
+
|
673
|
+
function deleteTag(event) {
|
674
|
+
event.stopPropagation();
|
675
|
+
const tag = event.target.closest('.query-tag');
|
676
|
+
let tagGroup = tag.parentElement;
|
677
|
+
tagGroup.removeChild(tag);
|
678
|
+
while (tagGroup.classList.contains('query-tag-group')) {
|
679
|
+
if (!tagGroup.childElementCount) {
|
680
|
+
let parent = tagGroup.parentElement;
|
681
|
+
parent.removeChild(tagGroup);
|
682
|
+
tagGroup = parent;
|
683
|
+
}
|
684
|
+
else if (tagGroup.childElementCount === 1) {
|
685
|
+
let parent = tagGroup.parentElement
|
686
|
+
let child = tagGroup.firstElementChild
|
687
|
+
if (tagGroup.classList.contains('selected-query-tag')) {
|
688
|
+
child.classList.add('selected-query-tag');
|
689
|
+
}
|
690
|
+
parent.appendChild(child);
|
691
|
+
parent.removeChild(tagGroup);
|
692
|
+
tagGroup = parent.parentElement;
|
693
|
+
}
|
694
|
+
else {
|
695
|
+
break
|
696
|
+
}
|
697
|
+
|
698
|
+
}
|
699
|
+
if (tagGroup.classList.contains('query-tag-block') && !tagGroup.childElementCount) {
|
700
|
+
const previousSibling = tagGroup.previousElementSibling;
|
701
|
+
const nextSibling = tagGroup.nextElementSibling;
|
702
|
+
if (previousSibling && previousSibling.classList.contains('query-or-label')) {
|
703
|
+
tagGroup.parentElement.removeChild(previousSibling);
|
704
|
+
}
|
705
|
+
if (nextSibling && nextSibling.classList.contains('query-or-label')) {
|
706
|
+
nextSibling.remove();
|
707
|
+
}
|
708
|
+
tagGroup.parentElement.removeChild(tagGroup);
|
709
|
+
}
|
710
|
+
// if (!filterModal.classList.contains('is-active')) {
|
711
|
+
// apply();
|
712
|
+
// }
|
713
|
+
apply()
|
714
|
+
}
|
715
|
+
|
716
|
+
function setInputType(inputType, param, text, step=null) {
|
717
|
+
queryInput.setAttribute('type', inputType);
|
718
|
+
queryInput.setAttribute('data-param', param);
|
719
|
+
queryInput.setAttribute('data-text', text);
|
720
|
+
queryTextNotificationParameterElement.classList.add('is-hidden');
|
721
|
+
queryTextElement.classList.remove('is-hidden');
|
722
|
+
queryTextElement.innerText = text;
|
723
|
+
if (step) {
|
724
|
+
queryInput.step = step
|
725
|
+
}
|
726
|
+
}
|
727
|
+
|
728
|
+
function resetQueryInput() {
|
729
|
+
queryInput.setAttribute('type', 'text');
|
730
|
+
queryInputSelectControl.classList.add('is-hidden');
|
731
|
+
queryInputControl.classList.remove('is-hidden');
|
732
|
+
activeInput = queryInput;
|
733
|
+
// queryInput.select();
|
734
|
+
}
|