From 0e786803ee6232bf13d1ff2e277a4599db623dc1 Mon Sep 17 00:00:00 2001 From: Inga Kirschnick Date: Mon, 5 Jun 2023 15:49:11 +0200 Subject: [PATCH] List Selection expansion & select all fix --- app/static/js/ResourceLists/CorpusFileList.js | 31 ++-- app/static/js/ResourceLists/CorpusList.js | 165 +++++++++++++++++- app/static/js/ResourceLists/JobList.js | 142 ++++++++++++++- 3 files changed, 315 insertions(+), 23 deletions(-) diff --git a/app/static/js/ResourceLists/CorpusFileList.js b/app/static/js/ResourceLists/CorpusFileList.js index 66bf3970..6e4c035e 100644 --- a/app/static/js/ResourceLists/CorpusFileList.js +++ b/app/static/js/ResourceLists/CorpusFileList.js @@ -81,7 +81,7 @@ class CorpusFileList extends ResourceList { Filename @@ -89,8 +89,8 @@ class CorpusFileList extends ResourceList { Title Publishing year - delete - file_download + delete + file_download @@ -199,15 +199,16 @@ class CorpusFileList extends ResourceList { case 'select-all': { let selectedIds = new Set(Array.from(items) .map(item => item.values().id)) - if (event.target.checked) { - selectableItems.forEach(selectableItem => selectableItem.checked = true); - this.selectedItemIds = selectedIds; - } else { - selectableItems.forEach(checkbox => checkbox.checked = false); - this.selectedItemIds = new Set([...this.selectedItemIds].filter(id => !selectedIds.has(id))); - + if (event.target.checked !== undefined) { + if (event.target.checked) { + selectableItems.forEach(selectableItem => selectableItem.checked = true); + this.selectedItemIds = selectedIds; + } else { + selectableItems.forEach(checkbox => checkbox.checked = false); + this.selectedItemIds = new Set([...this.selectedItemIds].filter(id => !selectedIds.has(id))); + } + this.renderingItemSelection(); } - this.renderingItemSelection(); break; } case 'delete': { @@ -326,6 +327,14 @@ class CorpusFileList extends ResourceList { actionButton.classList.remove('hide'); }); } + + // Check select all checkbox if all items are selected + let selectAllCheckbox = document.querySelector('.select-all-checkbox[type="checkbox"]'); + if (selectableItems.length === this.selectedItemIds.size && selectAllCheckbox.checked === false) { + selectAllCheckbox.checked = true; + } else if (selectableItems.length !== this.selectedItemIds.size && selectAllCheckbox.checked === true) { + selectAllCheckbox.checked = false; + } } onPatch(patch) { diff --git a/app/static/js/ResourceLists/CorpusList.js b/app/static/js/ResourceLists/CorpusList.js index d2184bf6..a95533fe 100644 --- a/app/static/js/ResourceLists/CorpusList.js +++ b/app/static/js/ResourceLists/CorpusList.js @@ -8,7 +8,11 @@ class CorpusList extends ResourceList { constructor(listContainerElement, options = {}) { super(listContainerElement, options); this.listjs.list.addEventListener('click', (event) => {this.onClick(event)}); + document.querySelectorAll('.corpus-list-selection-action-trigger[data-selection-action]').forEach((element) => { + element.addEventListener('click', (event) => {this.onSelectionAction(event)}); + }); this.isInitialized = false + this.selectedItemIds = new Set(); this.userId = listContainerElement.dataset.userId; if (this.userId === undefined) {return;} app.subscribeUser(this.userId).then((response) => { @@ -22,13 +26,18 @@ class CorpusList extends ResourceList { get item() { return (values) => { return ` - - book + + + +
- delete + delete send @@ -61,11 +70,18 @@ class CorpusList extends ResourceList { - + - + @@ -95,7 +111,7 @@ class CorpusList extends ResourceList { if (listItemElement === null) {return;} let itemId = listItemElement.dataset.id; let listActionElement = event.target.closest('.list-action-trigger[data-list-action]'); - let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction; + let listAction = listActionElement === null ? '' : listActionElement.dataset.listAction; switch (listAction) { case 'delete-request': { let values = this.listjs.get('id', itemId)[0].values(); @@ -135,12 +151,149 @@ class CorpusList extends ResourceList { window.location.href = `/corpora/${itemId}`; break; } + case 'select': { + + if (event.target.checked) { + this.selectedItemIds.add(itemId); + } else { + this.selectedItemIds.delete(itemId); + } + this.renderingItemSelection(); + } default: { break; } } } + onSelectionAction(event) { + let selectionActionElement = event.target.closest('.corpus-list-selection-action-trigger[data-selection-action]'); + let selectionAction = selectionActionElement.dataset.selectionAction; + let items = Array.from(this.listjs.items).filter(item => item._values["is-owner"] === true); + let selectableItems = Array.from(items) + .filter(item => item.elm) + .map(item => item.elm.querySelector('.select-checkbox[type="checkbox"]')); + + switch (selectionAction) { + case 'select-all': { + let selectedIds = new Set(Array.from(items) + .map(item => item.values().id)) + if (event.target.checked !== undefined) { + if (event.target.checked) { + selectableItems.forEach(selectableItem => selectableItem.checked = true); + this.selectedItemIds = selectedIds; + } else { + selectableItems.forEach(checkbox => checkbox.checked = false); + this.selectedItemIds = new Set([...this.selectedItemIds].filter(id => !selectedIds.has(id))); + } + this.renderingItemSelection(); + } + break; + } + case 'delete': { + let modalElement = Utils.HTMLToElement( + ` + + ` + ); + document.querySelector('#modals').appendChild(modalElement); + let itemList = document.querySelector('#selected-items-list'); + this.selectedItemIds.forEach(selectedItemId => { + let listItem = this.listjs.get('id', selectedItemId)[0].elm; + let values = this.listjs.get('id', listItem.dataset.id)[0].values(); + let itemElement = Utils.HTMLToElement(`
  • - ${values.title}
  • `); + itemList.appendChild(itemElement); + }); + let modal = M.Modal.init( + modalElement, + { + dismissible: false, + onCloseEnd: () => { + modal.destroy(); + modalElement.remove(); + } + } + ); + let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); + confirmElement.addEventListener('click', (event) => { + this.selectedItemIds.forEach(selectedItemId => { + Requests.corpora.entity.delete(selectedItemId); + }); + this.selectedItemIds.clear(); + this.renderingItemSelection(); + }); + modal.open(); + break; + } + default: { + break; + } + } + } + + renderingItemSelection() { + let selectionActionButtons = document.querySelectorAll('.corpus-list-selection-action-trigger:not([data-selection-action="select-all"])'); + let selectableItems = this.listjs.items; + let actionButtons = []; + + Object.values(selectableItems).forEach(selectableItem => { + if (selectableItem._values["is-owner"] === false && this.selectedItemIds.size > 0) { + selectableItem.elm.classList.add('hide'); + } else if (selectableItem._values["is-owner"] === false && this.selectedItemIds.size === 0) { + selectableItem.elm.classList.remove('hide'); + } else { + if (selectableItem.elm) { + let checkbox = selectableItem.elm.querySelector('.select-checkbox[type="checkbox"]'); + if (checkbox.checked) { + selectableItem.elm.classList.add('grey', 'lighten-3'); + } else { + selectableItem.elm.classList.remove('grey', 'lighten-3'); + } + let itemActionButtons = selectableItem.elm.querySelectorAll('.list-action-trigger:not([data-list-action="select"])'); + itemActionButtons.forEach(itemActionButton => { + actionButtons.push(itemActionButton); + }); + } + } + }); + // Hide item action buttons if > 0 item is selected and show selection action buttons + if (this.selectedItemIds.size > 0) { + selectionActionButtons.forEach(selectionActionButton => { + selectionActionButton.classList.remove('hide'); + }); + actionButtons.forEach(actionButton => { + actionButton.classList.add('hide'); + }); + } else { + selectionActionButtons.forEach(selectionActionButton => { + selectionActionButton.classList.add('hide'); + }); + actionButtons.forEach(actionButton => { + actionButton.classList.remove('hide'); + }); + } + + // Check select all checkbox if all items are selected + let filteredItems = Object.values(selectableItems).filter(item => item._values["is-owner"] === true) + let selectAllCheckbox = document.querySelector('.corpus-list-select-all-checkbox[type="checkbox"]'); + if (filteredItems.length === this.selectedItemIds.size && selectAllCheckbox.checked === false) { + selectAllCheckbox.checked = true; + } else if (filteredItems.length !== this.selectedItemIds.size && selectAllCheckbox.checked === true) { + selectAllCheckbox.checked = false; + } + } + onPatch(patch) { let re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)`); let filteredPatch = patch.filter(operation => re.test(operation.path)); diff --git a/app/static/js/ResourceLists/JobList.js b/app/static/js/ResourceLists/JobList.js index f8ccc058..a568c646 100644 --- a/app/static/js/ResourceLists/JobList.js +++ b/app/static/js/ResourceLists/JobList.js @@ -7,7 +7,11 @@ class JobList extends ResourceList { constructor(listContainerElement, options = {}) { super(listContainerElement, options); + this.documentJobArea = document.querySelector('#jobs'); this.listjs.list.addEventListener('click', (event) => {this.onClick(event)}); + document.querySelectorAll('.job-list-selection-action-trigger[data-selection-action]').forEach((element) => { + element.addEventListener('click', (event) => {this.onSelectionAction(event)}); + }); this.isInitialized = false; this.selectedItemIds = new Set(); this.userId = listContainerElement.dataset.userId; @@ -25,7 +29,7 @@ class JobList extends ResourceList { get item() { return ` - + - + @@ -106,7 +112,7 @@ class JobList extends ResourceList { if (listItemElement === null) {return;} let itemId = listItemElement.dataset.id; let listActionElement = event.target.closest('.list-action-trigger[data-list-action]'); - let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction; + let listAction = listActionElement === null ? '' : listActionElement.dataset.listAction; switch (listAction) { case 'delete-request': { let values = this.listjs.get('id', itemId)[0].values(); @@ -161,6 +167,130 @@ class JobList extends ResourceList { } } + onSelectionAction(event) { + let selectionActionElement = event.target.closest('.job-list-selection-action-trigger[data-selection-action]'); + let selectionAction = selectionActionElement.dataset.selectionAction; + let items = this.listjs.items; + let selectableItems = Array.from(items) + .filter(item => item.elm) + .map(item => item.elm.querySelector('.select-checkbox[type="checkbox"]')); + switch (selectionAction) { + case 'select-all': { + let selectedIds = new Set(Array.from(items) + .map(item => item.values().id)) + if (event.target.checked !== undefined) { + if (event.target.checked) { + selectableItems.forEach(selectableItem => selectableItem.checked = true); + this.selectedItemIds = selectedIds; + } else { + selectableItems.forEach(checkbox => checkbox.checked = false); + this.selectedItemIds = new Set([...this.selectedItemIds].filter(id => !selectedIds.has(id))); + } + this.renderingItemSelection(); + } + break; + } + case 'delete': { + let modalElement = Utils.HTMLToElement( + ` + + ` + ); + document.querySelector('#modals').appendChild(modalElement); + let itemList = document.querySelector('#selected-items-list'); + this.selectedItemIds.forEach(selectedItemId => { + let listItem = this.listjs.get('id', selectedItemId)[0].elm; + let values = this.listjs.get('id', listItem.dataset.id)[0].values(); + let itemElement = Utils.HTMLToElement(`
  • - ${values.title}
  • `); + itemList.appendChild(itemElement); + }); + let modal = M.Modal.init( + modalElement, + { + dismissible: false, + onCloseEnd: () => { + modal.destroy(); + modalElement.remove(); + } + } + ); + let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); + confirmElement.addEventListener('click', (event) => { + this.selectedItemIds.forEach(selectedItemId => { + Requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId); + }); + this.selectedItemIds.clear(); + this.renderingItemSelection(); + }); + modal.open(); + break; + } + default: { + break; + } + } + } + + renderingItemSelection() { + let selectionActionButtons = document.querySelectorAll('.job-list-selection-action-trigger:not([data-selection-action="select-all"])'); + let selectableItems = this.listjs.items; + let actionButtons = []; + + Object.values(selectableItems).forEach(selectableItem => { + if (selectableItem.elm) { + let checkbox = selectableItem.elm.querySelector('.select-checkbox[type="checkbox"]'); + if (checkbox.checked) { + selectableItem.elm.classList.add('grey', 'lighten-3'); + } else { + selectableItem.elm.classList.remove('grey', 'lighten-3'); + } + let itemActionButtons = selectableItem.elm.querySelectorAll('.list-action-trigger:not([data-list-action="select"])'); + itemActionButtons.forEach(itemActionButton => { + actionButtons.push(itemActionButton); + }); + } + }); + + + + // Hide item action buttons if > 0 item is selected and show selection action buttons + if (this.selectedItemIds.size > 0) { + selectionActionButtons.forEach(selectionActionButton => { + selectionActionButton.classList.remove('hide'); + }); + actionButtons.forEach(actionButton => { + actionButton.classList.add('hide'); + }); + } else { + selectionActionButtons.forEach(selectionActionButton => { + selectionActionButton.classList.add('hide'); + }); + actionButtons.forEach(actionButton => { + actionButton.classList.remove('hide'); + }); + } + + // Check select all checkbox if all items are selected + let selectAllCheckbox = document.querySelector('.job-list-select-all-checkbox[type="checkbox"]'); + if (selectableItems.length === this.selectedItemIds.size && selectAllCheckbox.checked === false) { + selectAllCheckbox.checked = true; + } else if (selectableItems.length !== this.selectedItemIds.size && selectAllCheckbox.checked === true) { + selectAllCheckbox.checked = false; + } + + } + onPatch(patch) { let re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)`); let filteredPatch = patch.filter(operation => re.test(operation.path));
    + + Title and Description Owner Status + delete +
    - Service Title and Description Status + delete +