FossilRepo

fossilrepo / assets / admin / js / actions.js
Blame History Raw 205 lines
1
/*global gettext, interpolate, ngettext, Actions*/
2
'use strict';
3
{
4
function show(selector) {
5
document.querySelectorAll(selector).forEach(function(el) {
6
el.classList.remove('hidden');
7
});
8
}
9
10
function hide(selector) {
11
document.querySelectorAll(selector).forEach(function(el) {
12
el.classList.add('hidden');
13
});
14
}
15
16
function showQuestion(options) {
17
hide(options.acrossClears);
18
show(options.acrossQuestions);
19
hide(options.allContainer);
20
}
21
22
function showClear(options) {
23
show(options.acrossClears);
24
hide(options.acrossQuestions);
25
document.querySelector(options.actionContainer).classList.remove(options.selectedClass);
26
show(options.allContainer);
27
hide(options.counterContainer);
28
}
29
30
function reset(options) {
31
hide(options.acrossClears);
32
hide(options.acrossQuestions);
33
hide(options.allContainer);
34
show(options.counterContainer);
35
}
36
37
function clearAcross(options) {
38
reset(options);
39
const acrossInputs = document.querySelectorAll(options.acrossInput);
40
acrossInputs.forEach(function(acrossInput) {
41
acrossInput.value = 0;
42
});
43
document.querySelector(options.actionContainer).classList.remove(options.selectedClass);
44
}
45
46
function checker(actionCheckboxes, options, checked) {
47
if (checked) {
48
showQuestion(options);
49
} else {
50
reset(options);
51
}
52
actionCheckboxes.forEach(function(el) {
53
el.checked = checked;
54
el.closest('tr').classList.toggle(options.selectedClass, checked);
55
});
56
}
57
58
function updateCounter(actionCheckboxes, options) {
59
const sel = Array.from(actionCheckboxes).filter(function(el) {
60
return el.checked;
61
}).length;
62
const counter = document.querySelector(options.counterContainer);
63
// data-actions-icnt is defined in the generated HTML
64
// and contains the total amount of objects in the queryset
65
const actions_icnt = Number(counter.dataset.actionsIcnt);
66
counter.textContent = interpolate(
67
ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {
68
sel: sel,
69
cnt: actions_icnt
70
}, true);
71
const allToggle = document.getElementById(options.allToggleId);
72
allToggle.checked = sel === actionCheckboxes.length;
73
if (allToggle.checked) {
74
showQuestion(options);
75
} else {
76
clearAcross(options);
77
}
78
}
79
80
const defaults = {
81
actionContainer: "div.actions",
82
counterContainer: "span.action-counter",
83
allContainer: "div.actions span.all",
84
acrossInput: "div.actions input.select-across",
85
acrossQuestions: "div.actions span.question",
86
acrossClears: "div.actions span.clear",
87
allToggleId: "action-toggle",
88
selectedClass: "selected"
89
};
90
91
window.Actions = function(actionCheckboxes, options) {
92
options = Object.assign({}, defaults, options);
93
let list_editable_changed = false;
94
let lastChecked = null;
95
let shiftPressed = false;
96
97
document.addEventListener('keydown', (event) => {
98
shiftPressed = event.shiftKey;
99
});
100
101
document.addEventListener('keyup', (event) => {
102
shiftPressed = event.shiftKey;
103
});
104
105
document.getElementById(options.allToggleId).addEventListener('click', function(event) {
106
checker(actionCheckboxes, options, this.checked);
107
updateCounter(actionCheckboxes, options);
108
});
109
110
document.querySelectorAll(options.acrossQuestions + " a").forEach(function(el) {
111
el.addEventListener('click', function(event) {
112
event.preventDefault();
113
const acrossInputs = document.querySelectorAll(options.acrossInput);
114
acrossInputs.forEach(function(acrossInput) {
115
acrossInput.value = 1;
116
});
117
showClear(options);
118
});
119
});
120
121
document.querySelectorAll(options.acrossClears + " a").forEach(function(el) {
122
el.addEventListener('click', function(event) {
123
event.preventDefault();
124
document.getElementById(options.allToggleId).checked = false;
125
clearAcross(options);
126
checker(actionCheckboxes, options, false);
127
updateCounter(actionCheckboxes, options);
128
});
129
});
130
131
function affectedCheckboxes(target, withModifier) {
132
const multiSelect = (lastChecked && withModifier && lastChecked !== target);
133
if (!multiSelect) {
134
return [target];
135
}
136
const checkboxes = Array.from(actionCheckboxes);
137
const targetIndex = checkboxes.findIndex(el => el === target);
138
const lastCheckedIndex = checkboxes.findIndex(el => el === lastChecked);
139
const startIndex = Math.min(targetIndex, lastCheckedIndex);
140
const endIndex = Math.max(targetIndex, lastCheckedIndex);
141
const filtered = checkboxes.filter((el, index) => (startIndex <= index) && (index <= endIndex));
142
return filtered;
143
};
144
145
Array.from(document.getElementById('result_list').tBodies).forEach(function(el) {
146
el.addEventListener('change', function(event) {
147
const target = event.target;
148
if (target.classList.contains('action-select')) {
149
const checkboxes = affectedCheckboxes(target, shiftPressed);
150
checker(checkboxes, options, target.checked);
151
updateCounter(actionCheckboxes, options);
152
lastChecked = target;
153
} else {
154
list_editable_changed = true;
155
}
156
});
157
});
158
159
document.querySelector('#changelist-form button[name=index]').addEventListener('click', function(event) {
160
if (list_editable_changed) {
161
const confirmed = confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
162
if (!confirmed) {
163
event.preventDefault();
164
}
165
}
166
});
167
168
const el = document.querySelector('#changelist-form input[name=_save]');
169
// The button does not exist if no fields are editable.
170
if (el) {
171
el.addEventListener('click', function(event) {
172
if (document.querySelector('[name=action]').value) {
173
const text = list_editable_changed
174
? gettext("You have selected an action, but you haven’t saved your changes to individual fields yet. Please click OK to save. You’ll need to re-run the action.")
175
: gettext("You have selected an action, and you haven’t made any changes on individual fields. You’re probably looking for the Go button rather than the Save button.");
176
if (!confirm(text)) {
177
event.preventDefault();
178
}
179
}
180
});
181
}
182
// Sync counter when navigating to the page, such as through the back
183
// button.
184
window.addEventListener('pageshow', (event) => updateCounter(actionCheckboxes, options));
185
};
186
187
// Call function fn when the DOM is loaded and ready. If it is already
188
// loaded, call the function now.
189
// http://youmightnotneedjquery.com/#ready
190
function ready(fn) {
191
if (document.readyState !== 'loading') {
192
fn();
193
} else {
194
document.addEventListener('DOMContentLoaded', fn);
195
}
196
}
197
198
ready(function() {
199
const actionsEls = document.querySelectorAll('tr input.action-select');
200
if (actionsEls.length > 0) {
201
Actions(actionsEls);
202
}
203
});
204
}
205

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button