ogcp: improve sidebar logic in Commands

Disable all checkboxes of scopes of level higher than room in the
$(window).on('pageshow', function) callback.

Set checkboxes as "indeterminate" when not every children is
selected but have some of its children selected.

[x] center
  [x] room1
      [x] client1
      [x] client1

[-] center
  [ ] room1
  [-] room2
      [ ] client1
      [x] client1

Send all selected sidebar fields as form fields. This requires
setting disabled to false and replacing indeterminate = true
to checked = true in the .on('submit', function) callback.

When a checkbox is clicked:
1. Find the room branch of the checked input.
[ ] center
  [ ] room1
  [ ] room2 <- root of the room branch
      [ ] client1 <-- clicked item

2. Uncheck all the checkboxes outside of the room branch.
3. Set all the children of the clicked item to the same value
   as the clicked item.
4. Set the parent checked or indeterminate values.
5. Save checkbox status.
master
Alejandro Sirgo Rica 2024-07-19 20:33:19 +02:00
parent c3d2582aa6
commit c1d08df31d
3 changed files with 56 additions and 49 deletions

View File

@ -59,70 +59,79 @@ function storeCheckboxStatus(checkbox, context) {
localStorage.removeItem(context + checkbox.id);
}
function checkParentsCheckboxes() {
const checkboxes = $('input:checkbox[form|="scopesForm"]');
const reversedCheckboxes = $(checkboxes.get().reverse())
function findParentCheckboxes(element) {
const $element = $(element);
const parents = $element.parentsUntil('#scopes').not('ul');
reversedCheckboxes.each(function() {
const checkbox = this;
const checkboxChildren = $('input:checkbox', this.parentNode).not(this);
const checkboxes = parents
.map(function() {
return $(this).children('input[type="checkbox"][form="scopesForm"]').toArray();
})
.get()
.flat();
return $(checkboxes).not($element);;
}
function setParentStatus(checkboxes) {
checkboxes.each(function() {
const checkboxChildren = $(this).parent().find('input:checkbox[form="scopesForm"]').not(this);
if (checkboxChildren.length == 0) return;
if (this.name == "scope-server") {
const checkedChildren = checkboxChildren.filter(":checked");
checkbox.checked = checkedChildren.length > 0;
return;
}
const unCheckedChildren = checkboxChildren.filter(":not(:checked)");
checkbox.indeterminate =
this.indeterminate =
unCheckedChildren.length > 0 &&
unCheckedChildren.length < checkboxChildren.length;
checkbox.checked = unCheckedChildren.length === 0;
this.checked = unCheckedChildren.length === 0;
});
}
function checkChildrenCheckboxes(context) {
const checkboxes = $('input:checkbox[form|="scopesForm"]')
function configureCommandCheckboxes(context) {
const checkboxes = $('input:checkbox[form="scopesForm"]');
// Ensure the form fields are sent
$('#scopesForm').on('submit', function() {
checkboxes.each(function() {
if (this.indeterminate) {
this.checked = true;
this.disabled = false;
}
});
});
// disable checkboxes outside of scope-room branches
$(window).on('pageshow', function(event) {
const enabledCheckboxes = checkboxes.filter('[name="scope-room"]').parent().find('input:checkbox[form="scopesForm"]');
checkboxes.not(enabledCheckboxes).prop('disabled', true);
setParentStatus(checkboxes)
});
checkboxes.on('change', function () {
const checked = this.checked
const children = $('input:checkbox', this.parentNode).not(this)
const checked = this.checked;
const childrenCheckboxes = $('input:checkbox[form|="scopesForm"]', this.parentNode);
// Uncheck all other checkboxes outside of the actual room branch
if (checked) {
// Only for rooms, deselect other rooms
if (this.name === 'scope-room') {
const others = $('input:checkbox[form|="scopesForm"]').not(this);
others.prop('checked', false);
others.each(function() {
showSelectedClient(this);
storeCheckboxStatus(this, context);
});
//others.trigger('change');
} else {
// Look for room, deselect all other rooms
const selectedRoom = $('[data-room="' + $(this).data('parentRoom') + '"]');
const others = $('input:checkbox[name="scope-room"]').not(selectedRoom);
others.prop('checked', false).prop('indeterminate', false);
others.each(function() {
const checks = $(this).parent().find('input:checkbox').prop('checked', false);
storeCheckboxStatus(this, context);
checks.each(function() {
showSelectedClient(this);
storeCheckboxStatus(this, context);
});
});
}
const roomBranch = findParentCheckboxes(this).add(childrenCheckboxes)
.filter('[name="scope-room"]')
.parent().find('input:checkbox[form="scopesForm"]');
checkboxes.not(roomBranch).each(function () {
this.checked = false;
this.indeterminate = false;
});
}
children.each(function () {
childrenCheckboxes.each(function () {
this.checked = checked;
storeCheckboxStatus(this, context);
$(this).trigger('show-client');
});
checkParentsCheckboxes();
setParentStatus(checkboxes);
checkboxes.each(function() {
showSelectedClient(this);
storeCheckboxStatus(this, context);
});
});
}

View File

@ -108,7 +108,7 @@
<!-- ChartJS -->
<script src="{{ url_for('static', filename='AdminLTE/plugins/chart.js/Chart.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/ogcp.js') }}?v=11"></script>
<script src="{{ url_for('static', filename='js/ogcp.js') }}?v=12"></script>
<script>
// error messages

View File

@ -13,8 +13,7 @@
keepScopesTreeState();
let context = {{ selection_mode | tojson | safe }};
{% if selection_mode == 'commands' %}
checkChildrenCheckboxes(context);
checkParentsCheckboxes();
configureCommandCheckboxes(context);
{% elif selection_mode == 'scopes' %}
limitCheckboxes(context);
checkFolderParent(context);
@ -41,7 +40,6 @@
value="{{ scope["id"] }}"
{% if state %}style="filter: grayscale(100%);" onclick="return false;"{% endif %}
{% if scope.get("selected", False) %}checked{% endif %}
{% if selection_mode == "commands" %}disabled="disabled"{% endif %}
name="scope-center" />
{% elif scope["type"] == "room" %}
{% set parent_room = scope.name + "-" + scope.id|string %}