Skip to content

Commit

Permalink
Merge pull request kitodo#6293 from thomaslow/detail-view-forward-bac…
Browse files Browse the repository at this point in the history
…kward-navigation-fixes-5930

Add navigation buttons to detail view of the metadata editor
  • Loading branch information
solth authored Nov 22, 2024
2 parents 2e36e3f + 4d96c98 commit 256951c
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1048,4 +1048,52 @@ public boolean hasMediaViewMimeTypePrefix(String mimeTypePrefix) {
public MediaPartialsPanel getMediaPartialsPanel() {
return mediaPartialsPanel;
}

/**
* Return true if the currently selected media (that is shown in the detail view) is the
* first media of all available media.
* @return boolean true if selected media is first media
*/
public boolean isSelectedMediaFirst() {
Pair<PhysicalDivision, LogicalDivision> lastSelection = getLastSelection();
if (Objects.isNull(lastSelection)) {
return false;
}

List<GalleryMediaContent> medias = getMedias();
if (medias.isEmpty()) {
return false;
}

PhysicalDivision firstPhysicalDivision = medias.get(0).getView().getPhysicalDivision();
if (Objects.isNull(firstPhysicalDivision)) {
return false;
}

return firstPhysicalDivision.equals(lastSelection.getKey());
}

/**
* Return true if the currently selected media (that is shown in the detail view) is the
* last media of all available media.
* @return boolean true if selected media is last media
*/
public boolean isSelectedMediaLast() {
Pair<PhysicalDivision, LogicalDivision> lastSelection = getLastSelection();
if (Objects.isNull(lastSelection)) {
return false;
}

List<GalleryMediaContent> medias = getMedias();
if (medias.isEmpty()) {
return false;
}

PhysicalDivision lastPhysicalDivision = medias.get(medias.size() - 1).getView().getPhysicalDivision();
if (Objects.isNull(lastPhysicalDivision)) {
return false;
}

return lastPhysicalDivision.equals(lastSelection.getKey());
}
}
4 changes: 4 additions & 0 deletions Kitodo/src/main/resources/messages/messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ dataEditor.layoutMenuSaveForTaskText=Spaltenaufteilung für Aufgabentyp speicher
dataEditor.layoutSavedSuccessfullyTitle=Aktuelle Spaltenaufteilung erfolgreich gespeichert
dataEditor.layoutSavedSuccessfullyDefaultText=Ihre Einstellungen wurden erfolgreich als Standard-Einstellungen gespeichert! Beim n\u00E4chsten \u00D6ffnen des Matadaten-Editors wird die Breite der drei Spalten (Strukturdaten, Metadaten und Galerie) entsprechend ihrer aktuellen Einstellung geladen.
dataEditor.layoutSavedSuccessfullyForTaskText=Ihre Einstellungen wurden erfolgreich f\u00FCr alle zuk\u00FCnftigen Aufgaben des Typs "{0}" gespeichert! Beim n\u00E4chsten \u00D6ffnen des Matadaten-Editors f\u00FCr eine Aufgabe des gleichen Typs wird die Breite der drei Spalten (Strukturdaten, Metadaten und Galerie) entsprechend ihrer aktuellen Einstellung geladen.
dataEditor.navigateToPreviousElementMany=mehrere Elemente zur\u00FCckspringen
dataEditor.navigateToPreviousElementOne=zum vorherigen Element
dataEditor.navigateToNextElementMany=mehrere Elemente vorspringen
dataEditor.navigateToNextElementOne=zum n\u00E4chsten Element
dataEditor.renamingMediaComplete=Das Umbenennen der Medien ist abgeschlossen
dataEditor.renamingMediaError=Beim Umbenennen der Medien ist ein Fehler aufgetreten
dataEditor.renamingMediaText={0} Mediendateien in {1} Ordnern wurden umbenannt. Bitte speichern Sie den Vorgang. Andernfalls werden die Dateiumbennungen beim Schlie\u00DFen des Metadateneditors verworfen.
Expand Down
4 changes: 4 additions & 0 deletions Kitodo/src/main/resources/messages/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ dataEditor.layoutMenuSaveForTaskText=Save task-specific layout
dataEditor.layoutSavedSuccessfullyTitle=Current layout successfully saved
dataEditor.layoutSavedSuccessfullyDefaultText=Your current editor column configuration has been successfully saved as default configuration. The next time you open the editor, the width of all three columns (structure data, metadata, gallery) will be loaded according to your current configuration.
dataEditor.layoutSavedSuccessfullyForTaskText=Your current editor column configuration has been successfully saved as default configuration for the task type "{0}". The next time you open the editor for the same task type, the width of all three columns (structure data, metadata, gallery) will be loaded according to your current configuration.
dataEditor.navigateToPreviousElementMany=jump multiple elements back
dataEditor.navigateToPreviousElementOne=show previous element
dataEditor.navigateToNextElementMany=jump multiple elements forward
dataEditor.navigateToNextElementOne=show next element
dataEditor.renamingMediaComplete=Finished renaming media
dataEditor.renamingMediaError=An error occurred while renaming media files
dataEditor.renamingMediaText={0} media files in {1} folders have been renamed. Please click the 'Save' button to persist changes to the filenames. Otherwise the renaming will be reverted upon closing the editor.
Expand Down
8 changes: 8 additions & 0 deletions Kitodo/src/main/resources/messages/messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,14 @@ dataEditor.layoutSavedSuccessfullyTitle=La plantilla actual se guardó correctam
dataEditor.layoutSavedSuccessfullyDefaultText=La configuración actual de la columna del editor se ha guardado correctamente como predeterminada. La próxima vez que abra el editor, el ancho de las tres columnas (datos de estructura, metadatos, galería) se cargará de acuerdo con su configuración actual.
# please check google translation below and remove comment if translation is acceptable
dataEditor.layoutSavedSuccessfullyForTaskText=La configuración actual de la columna del editor se ha guardado correctamente como predeterminada para el tipo de tarea "{0}". La próxima vez que abra el editor para el mismo tipo de tarea, el ancho de las tres columnas (datos de estructura, metadatos, galería) se cargará de acuerdo con su configuración actual.
# please check google translation below and remove comment if translation is acceptable
dataEditor.navigateToPreviousElementMany=saltar múltiples elementos hacia atrás
# please check google translation below and remove comment if translation is acceptable
dataEditor.navigateToPreviousElementOne=mostrar elemento anterior
# please check google translation below and remove comment if translation is acceptable
dataEditor.navigateToNextElementMany=saltar múltiples elementos hacia adelante
# please check google translation below and remove comment if translation is acceptable
dataEditor.navigateToNextElementOne=mostrar el siguiente elemento
dataEditor.renamingMediaComplete=El cambio de nombre de los archivos multimedia ha finalizado
dataEditor.renamingMediaError=Se produjo un error al cambiar el nombre de los archivos multimedia
dataEditor.renamingMediaText=Se ha cambiado el nombre de {0} archivos multimedia en {1} carpeta. Por favor, haga clic en el botón 'Guardar' para mantener los cambios en los nombres de archivo. De lo contrario, el cambio de nombre se revertirá al cerrar el editor.
Expand Down
24 changes: 24 additions & 0 deletions Kitodo/src/main/webapp/WEB-INF/resources/css/kitodo.css
Original file line number Diff line number Diff line change
Expand Up @@ -3280,6 +3280,7 @@ div[id$='metadataTable'].ui-treetable tr.focusedRow {
width: calc(100% - 100px);
align-items: center;
justify-content: left;
position: relative;
}

#imagePreviewForm\:mediaDetailMediaContainer {
Expand Down Expand Up @@ -3441,6 +3442,29 @@ div[id$='metadataTable'].ui-treetable tr.focusedRow {
background-color: var(--blue);
}

#imagePreviewForm\:mediaDetailNavigationPanel {
position: absolute;
width: 100%;
bottom: 0;
text-align: center;
pointer-events: none;
}

#imagePreviewForm\:mediaDetailNavigationPanel button {
margin: var(--default-full-size) var(--default-half-size);
pointer-events: all;
opacity: 0.0;
transition: opacity 0.1s linear;
}

#imagePreviewForm:hover #imagePreviewForm\:mediaDetailNavigationPanel button {
opacity: 1.0;
}

#imagePreviewForm\:mediaDetailNavigationPanel button:enabled:hover {
background: var(--blue);
}

#galleryWrapperPanel,
#galleryWrapperPanel_content {
height: 100%;
Expand Down
30 changes: 30 additions & 0 deletions Kitodo/src/main/webapp/WEB-INF/resources/js/metadata_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,36 @@ metadataEditor.pagination = {
}
};

metadataEditor.detailView = {

/**
* Select the previous or following media when clicking on the navigation buttons of the detail view.
* @param {int} delta position delta with respect to currently selected media
*/
navigate(delta) {
// find media currently shown in detail view
let currentTreeNodeId = $("#imagePreviewForm\\:mediaDetail").data("logicaltreenodeid");
if (!currentTreeNodeId) {
return;
}
// find current media in list of thumbnails
let thumbnails = $("#imagePreviewForm .thumbnail-container");
let currentThumbnail = $("#imagePreviewForm .thumbnail-container[data-logicaltreenodeid='" + currentTreeNodeId + "']");
let index = thumbnails.index(currentThumbnail);
if (index < 0) {
return;
}
// add delta to find previous or next thumbnail
index = Math.min(thumbnails.length - 1, Math.max(0, index + delta));
let nextThumbnail = thumbnails.eq(index);
let nextTreeNodeId = nextThumbnail.data("logicaltreenodeid");
// update selection and trigger reload of detail view
metadataEditor.gallery.pages.handleSingleSelect(null, nextThumbnail, nextTreeNodeId);
metadataEditor.gallery.pages.handleSelectionUpdates(nextTreeNodeId);
scrollToPreviewThumbnail(nextThumbnail, $("#thumbnailStripeScrollableContent"));
}
};

metadataEditor.contextMenu = {
listen() {
document.oncontextmenu = function(event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:a="http://xmlns.jcp.org/jsf/passthrough">

<h:panelGroup id="mediaDetail" layout="block">
<ui:param name="selectedGalleryMediaContent"
value="#{DataEditorForm.galleryPanel.getGalleryMediaContent(DataEditorForm.galleryPanel.lastSelection.key)}"/>
<ui:param name="selectedGalleryMediaContent"
value="#{DataEditorForm.galleryPanel.getGalleryMediaContent(DataEditorForm.galleryPanel.lastSelection.key)}"/>

<h:panelGroup id="mediaDetail"
layout="block"
a:data-logicaltreenodeid="#{selectedGalleryMediaContent.getLogicalTreeNodeId()}">

<ui:fragment
rendered="#{mediaProvider.hasMediaViewVariant(selectedGalleryMediaContent) and (fn:startsWith(selectedGalleryMediaContent.mediaViewMimeType, 'video') or fn:startsWith(selectedGalleryMediaContent.mediaViewMimeType, 'audio'))}">
Expand Down Expand Up @@ -91,6 +94,29 @@
</p:outputPanel>
</ui:fragment>

<p:outputPanel id="mediaDetailNavigationPanel">
<p:commandButton id="navigateToPreviousElementMany"
title="#{msgs['dataEditor.navigateToPreviousElementMany']}"
disabled="#{DataEditorForm.galleryPanel.isSelectedMediaFirst()}"
icon="fa fa-angle-double-left fa-lg"
onclick="metadataEditor.detailView.navigate(-20);" />
<p:commandButton id="navigateToPreviousElementOne"
title="#{msgs['dataEditor.navigateToPreviousElementOne']}"
disabled="#{DataEditorForm.galleryPanel.isSelectedMediaFirst()}"
icon="fa fa-angle-left fa-lg"
onclick="metadataEditor.detailView.navigate(-1);" />
<p:commandButton id="navigateToNextElementOne"
title="#{msgs['dataEditor.navigateToNextElementOne']}"
disabled="#{DataEditorForm.galleryPanel.isSelectedMediaLast()}"
icon="fa fa-angle-right fa-lg"
onclick="metadataEditor.detailView.navigate(+1);" />
<p:commandButton id="navigateToNextElementMany"
title="#{msgs['dataEditor.navigateToNextElementMany']}"
disabled="#{DataEditorForm.galleryPanel.isSelectedMediaLast()}"
icon="fa fa-angle-double-right fa-lg"
onclick="metadataEditor.detailView.navigate(+20);" />
</p:outputPanel>

</h:panelGroup>

</ui:composition>
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
Expand All @@ -37,6 +38,7 @@
import org.kitodo.test.utils.ProcessTestUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

/**
* Tests the image preview panel (OpenLayers map) in the metadata editor.
Expand Down Expand Up @@ -209,6 +211,77 @@ public void viewPersistsImageChange() throws Exception {
assertTrue(Math.abs(getOpenLayersRotation() - changedRotation) < EPSILON);
}

/**
* Test that navigation buttons select previous or following image, are disabled in case there is
* no previous or next image, and are hidden if the mouse is not inside the image preview panel.
*/
@Test
public void navigationButtonTest() throws Exception {
login("kowal");

// open metadata editor and detail view
Pages.getProcessesPage().goTo().editMetadata(PROCESS_TITLE);
Pages.getMetadataEditorPage().openDetailView();
pollAssertTrue(() -> findElementsByCSS(OPEN_LAYERS_CANVAS_SELECTOR).get(0).isDisplayed());

// image is thumbnail 2, which is the very first image, such that left buttons are disabled
assertEquals("Bild 2, Seite -", findElementsByCSS(GALLERY_HEADING_WRAPPER_SELECTOR).get(0).getText().strip());
WebElement leftMany = findElementsByCSS("#imagePreviewForm\\:navigateToPreviousElementMany").get(0);
WebElement rightMany = findElementsByCSS("#imagePreviewForm\\:navigateToNextElementMany").get(0);

// check left buttons are disabled and right buttons are enabled
assertFalse(leftMany.isEnabled());
assertTrue(rightMany.isEnabled());

// click on right-many button, which selects last image
rightMany.click();

// wait for image 3 to be shown
pollAssertTrue(
() -> "Bild 3, Seite -".equals(
findElementsByCSS(GALLERY_HEADING_WRAPPER_SELECTOR).get(0).getText().strip()
)
);

// find buttons again because image preview is re-rendered
WebElement leftOne = findElementsByCSS("#imagePreviewForm\\:navigateToPreviousElementOne").get(0);
WebElement rightOne = findElementsByCSS("#imagePreviewForm\\:navigateToNextElementOne").get(0);

// check left buttons are enabled and right buttons are disabled
assertTrue(leftOne.isEnabled());
assertFalse(rightOne.isEnabled());

// click on left-one button, selecting image 1 (middle image of all 3 images)
leftOne.click();

// wait for image 1 to be shown
pollAssertTrue(
() -> "Bild 1, Seite -".equals(
findElementsByCSS(GALLERY_HEADING_WRAPPER_SELECTOR).get(0).getText().strip()
)
);

// find buttons again because image preview is re-rendered
leftOne = findElementsByCSS("#imagePreviewForm\\:navigateToPreviousElementOne").get(0);
rightOne = findElementsByCSS("#imagePreviewForm\\:navigateToNextElementOne").get(0);

// both left and right buttons are enabled
assertTrue(leftOne.isEnabled());
assertTrue(rightOne.isEnabled());

// check that buttons are displayed (since mouse in hovering buttons due to prior click)
assertTrue(leftOne.isDisplayed());
assertTrue(rightOne.isDisplayed());

// move mouse to main header menu
new Actions(Browser.getDriver()).moveToElement(findElementsByCSS("#menu").get(0)).perform();

// check buttons are hidden now
pollAssertTrue(
() -> !findElementsByCSS("#imagePreviewForm\\:navigateToPreviousElementOne").get(0).isDisplayed()
);
}

/**
* Close metadata editor and logout after every test.
* @throws Exception when page navigation fails
Expand Down

0 comments on commit 256951c

Please sign in to comment.