Skip to content

Commit

Permalink
Merge pull request kitodo#6285 from thomaslow/focus-new-metadata-fiel…
Browse files Browse the repository at this point in the history
…ds-in-metadata-editor-fixes-5929

Scroll to recently added metadata row
  • Loading branch information
solth authored Nov 15, 2024
2 parents 2911ef0 + 90aa906 commit 1c6a99a
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 8 deletions.
5 changes: 5 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 @@ -3165,6 +3165,11 @@ Column content
overflow: hidden;
}

#metadataAccordion\:metadata\:metadataTable_data tr.focusedRow,
div[id$='metadataTable'].ui-treetable tr.focusedRow {
background-color: var(--trans-blue-highlight);
}

#imagePreviewForm {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
--medium-gray: #999;
--orange: #f94a15;
--trans-blue: #f2fbff;
--trans-blue-highlight: #dbecf6;
--pure-white: #fff;
--error-background: #f2dede;

Expand Down
85 changes: 85 additions & 0 deletions Kitodo/src/main/webapp/WEB-INF/resources/js/metadata_table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* (c) Kitodo. Key to digital objects e. V. <[email protected]>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/

/**
* This class allows to focus the most recently added metadata row of a metadata table.
*
* It requires each row to be annotated with a data attribute containing its metadata type.
* When adding a new metadata row, the last row of the same metadata type is focused.
*/
class FocusMetadataRow {

/**
* Contains the row key (rk data attribute) of the metadata group whose add button (+)
* was last clicked by the user.
*/
#lastSelectedRowKey;

constructor() {
this.#lastSelectedRowKey = "root";
}

/**
* Retrieves the recently added metadata type (e.g. TitleDocMain or LABEL) from the
* "addMetadata" dialog. Requires "widgetVar" declaration on PrimeFaces element.
*/
#getSelectedMetadataType() {
return PF('metadataTypeSelection').getSelectedValue();
}

/**
* Remove all highlights.
*/
#removeHighlights() {
$("div[id$='metadataTable'] tr.focusedRow").removeClass("focusedRow");
}

/**
* Remembers the metadata group whose add button (+) was clicked by the user.
* Is used to determine which metadata row needs to be focused if there are multiple
* groups with the same metadata type (e.g. ContributingPerson).
*
* @param {String} rowId the id of the metadata row whose add button (+) was clicked by the user
*/
remember(rowId) {
this.#removeHighlights();
// extract data attribute "rk" (row key?), which references the current row (tree node)
let rowKey = $(document.getElementById(rowId)).closest("tr").data("rk");
// remember the current row key if available
this.#lastSelectedRowKey = typeof rowKey !== 'undefined' ? rowKey : "root";
}

/**
* Focus the row that was added by a user.
*/
focus() {
this.#removeHighlights();

// find last metadata row matching currently selected metadata type
let row = $(
"div[id$='metadataTable'] " + // metadata table selector
"tr[data-prk='" + this.#lastSelectedRowKey + "'] " + // remembered metadata group
"label[data-metadataid='" + this.#getSelectedMetadataType() + "']" // selected metadata type
).last().closest("tr");

// if found, focus row
if (row.length === 1) {
row.addClass("focusedRow");
row.get(0).scrollIntoView();
row.find("input:enabled:visible,textarea:enabled:visible").first().focus();
}
}

}

// register class with global metadataTable namespace
var metadataTable = metadataTable || {};
metadataTable.focusMetadataRow = new FocusMetadataRow();
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
styleClass="dialogFieldWrapper">
<div>
<p:selectOneMenu id="metadataTypeSelection"
widgetVar="metadataTypeSelection"
value="#{DataEditorForm.addMetadataDialog.selectedMetadata}">
<f:selectItems value="#{DataEditorForm.addMetadataDialog.addableMetadata}"/>
</p:selectOneMenu>
Expand All @@ -42,7 +43,7 @@
<p:commandButton id="apply"
action="#{DataEditorForm.metadataPanel.addMetadataEntry}"
update="metadataAccordion:metadata:metadataTable metadataAccordion:addMetadataButtonWrapper"
oncomplete="PF('addMetadataDialog').hide();"
oncomplete="PF('addMetadataDialog').hide();metadataTable.focusMetadataRow.focus();"
value="#{msgs.apply}"
styleClass="primary right"/>
<p:commandButton id="cancel"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
update="addMetadataForm"
disabled="#{DataEditorForm.structurePanel.selectedLogicalNode.data.linked or not DataEditorForm.metadataPanel.metadataAddableToStructureElement()}"
action="#{DataEditorForm.addMetadataDialog.prepareAddableMetadataForStructure(DataEditorForm.metadataPanel.logicalMetadataRows.getChildren())}"
oncomplete="PF('addMetadataDialog').show();">
oncomplete="PF('addMetadataDialog').show();metadataTable.focusMetadataRow.remember(this.source);">
<f:setPropertyActionListener target="#{DataEditorForm.metadataPanel.selectedMetadataTreeNode}" value="#{null}"/>
</p:commandButton>
</h:panelGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
xmlns:p="http://primefaces.org/ui"
xmlns:a="http://xmlns.jcp.org/jsf/passthrough">

<!-- parameters:
* root: table data tree (org.primefaces.model.TreeNode)
Expand Down Expand Up @@ -51,8 +52,10 @@

<p:outputLabel for="#{item.input eq 'dataTable' ? '' : item.input}"
value="#{item.label}: #{item.required ? ' *' :''}"
a:data-metadataid="#{item.metadataID}"
rendered="#{not item.undefined}"/>
<p:outputLabel value="#{item.label}: ⚠️"
a:data-metadataid="#{item.metadataID}"
style="background-color: gold;"
title="#{msgs['dataEditor.undefinedKey']}"
rendered="#{item.undefined}"/>
Expand Down Expand Up @@ -198,7 +201,7 @@
icon="fa fa-plus"
styleClass="secondary"
update="addMetadataDialog"
oncomplete="PF('addMetadataDialog').show()"/>
oncomplete="PF('addMetadataDialog').show();metadataTable.focusMetadataRow.remember(this.source);"/>
</h:panelGroup>

<!-- button to delete -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@
update="addMetadataDialog"
disabled="#{not CreateProcessForm.addMetadataDialog.metadataAddableToStructureElement()}"
action="#{CreateProcessForm.addMetadataDialog.prepareAddableMetadataForStructure()}"
oncomplete="PF('addMetadataDialog').show();">
oncomplete="PF('addMetadataDialog').show();metadataTable.focusMetadataRow.remember(this.source);">
</p:commandButton>
</h:panelGroup>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
styleClass="dialogFieldWrapper">
<div>
<p:selectOneMenu id="metadataTypeSelection"
widgetVar="metadataTypeSelection"
value="#{CreateProcessForm.addMetadataDialog.selectedMetadata}">
<f:selectItems value="#{CreateProcessForm.addMetadataDialog.addableMetadata}"/>
</p:selectOneMenu>
Expand All @@ -43,7 +44,7 @@
action="#{CreateProcessForm.processMetadata.addMetadataEntry}"
process="addMetadataDialog"
update="editForm:processFromTemplateTabView:metadataTable editForm:processFromTemplateTabView:addMetadataButtonWrapper"
oncomplete="PF('addMetadataDialog').hide();"
oncomplete="PF('addMetadataDialog').hide();metadataTable.focusMetadataRow.focus();"
value="#{msgs.apply}"
styleClass="primary right"/>
<p:commandButton id="cancel"
Expand Down
1 change: 1 addition & 0 deletions Kitodo/src/main/webapp/pages/metadataEditor.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@
<h:outputScript name="js/metadata_editor_unsaved_changes.js" target="head"/>
<h:outputScript name="js/metadataeditor_jquery-ui_fix.js" />
<h:outputScript name="js/pf_contextMenu_custom.js" target="body"/>
<h:outputScript name="js/metadata_table.js" target="body"/>
<h:outputScript>
PrimeFaces.widget.VerticalTree.prototype.bindKeyEvents = function () {
// Prevent PrimeFaces' default keyboard event handling for VerticalTrees.
Expand Down
1 change: 1 addition & 0 deletions Kitodo/src/main/webapp/pages/processFromTemplate.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
<ui:define name="page-scripts">
<h:outputScript name="js/defaultScript.js" target="body"/>
<h:outputScript name="js/metadata_editor.js" target="body"/>
<h:outputScript name="js/metadata_table.js" target="body"/>
</ui:define>

</ui:composition>
68 changes: 67 additions & 1 deletion Kitodo/src/test/java/org/kitodo/selenium/MetadataST.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,14 @@ public void showPaginationByDefaultTest() throws Exception {
Pages.getProcessesPage().goTo().editMetadata(MockDatabase.MEDIA_RENAMING_TEST_PROCESS_TITLE);
assertFalse(Pages.getMetadataEditorPage().isPaginationPanelVisible());
Pages.getMetadataEditorPage().closeEditor();
Pages.getUserEditPage().setPaginationToShowByDefault();
Pages.getUserEditPage().togglePaginationToShowByDefault();
Pages.getProcessesPage().goTo().editMetadata(MockDatabase.MEDIA_RENAMING_TEST_PROCESS_TITLE);
assertTrue(Pages.getMetadataEditorPage().isPaginationPanelVisible());
// disable pagination again to prevent conflicts with other tests (when interacting with metadata table)
Pages.getMetadataEditorPage().closeEditor();
Pages.getUserEditPage().togglePaginationToShowByDefault();
Pages.getProcessesPage().goTo().editMetadata(MockDatabase.MEDIA_RENAMING_TEST_PROCESS_TITLE);
assertFalse(Pages.getMetadataEditorPage().isPaginationPanelVisible());
}

/**
Expand Down Expand Up @@ -496,6 +501,67 @@ public void linkPageToNextDivision() throws Exception {
}

/**
* Tests that a metadata row of the metadata table is highlighted as soon as a user adds a new
* row via the add metadata dialog.
*/
@Test
public void focusRecentlyAddedMetadataRowTest() throws Exception {
login("kowal");

// open the metadata editor
Pages.getProcessesPage().goTo().editMetadata(MockDatabase.MEDIA_RENAMING_TEST_PROCESS_TITLE);

// wait until metadata table is shown
await().ignoreExceptions().pollDelay(100, TimeUnit.MILLISECONDS).atMost(5, TimeUnit.SECONDS).until(
() -> Browser.getDriver().findElement(By.id("metadataAccordion:metadata:metadataTable")).isDisplayed()
);

// verify no metadata row is focused yet
assertTrue(Browser.getDriver().findElements(
By.cssSelector("#metadataAccordion\\:metadata\\:metadataTable tr.focusedRow")).isEmpty()
);

// click on add metadata button
Browser.getDriver().findElement(By.id("metadataAccordion:addMetadataButton")).click();

// wait until dialog is visible
await().ignoreExceptions().pollDelay(100, TimeUnit.MILLISECONDS).atMost(5, TimeUnit.SECONDS).until(
() -> Browser.getDriver().findElement(By.id("addMetadataDialog")).isDisplayed()
);

// open select menu
Browser.getDriver().findElement(By.id("addMetadataForm:metadataTypeSelection")).click();

// wait until selection menu list is visible
await().ignoreExceptions().pollDelay(100, TimeUnit.MILLISECONDS).atMost(5, TimeUnit.SECONDS).until(
() -> Browser.getDriver().findElement(By.id("addMetadataForm:metadataTypeSelection_items")).isDisplayed()
);

// select Person as new metadata row
Browser.getDriver().findElement(By.cssSelector(
"#addMetadataForm\\:metadataTypeSelection_items li[data-label='Person'].ui-selectonemenu-item"
)).click();

// confirm dialog
Browser.getDriver().findElement(By.id("addMetadataForm:apply")).click();

// wait until dialog disappears
await().ignoreExceptions().pollDelay(100, TimeUnit.MILLISECONDS).atMost(5, TimeUnit.SECONDS).until(
() -> !Browser.getDriver().findElement(By.id("addMetadataDialog")).isDisplayed()
);

// verify metadata row with name "Person" is selected
assertEquals("Person:", Browser.getDriver().findElement(
By.cssSelector("#metadataAccordion\\:metadata\\:metadataTable tr.focusedRow label")
).getText());

// verify accordion was scrolled down
assertTrue(0 < (Long)Browser.getDriver().executeScript(
"return document.getElementById('metadataAccordion:metadata:metadataTable').scrollTop;"
));
}

/*
* Verifies that an image can be openend in a separate window by clicking on the corresponding
* context menu item of the first logical tree node.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public void changeUserSettings() throws Exception {
/**
* Set pagination panel to show by default in metadata editor.
*/
public void setPaginationToShowByDefault() throws Exception {
public void togglePaginationToShowByDefault() throws Exception {
openUserConfig();
switchToTabByIndex(TabIndex.USER_METADATA_EDITOR_SETTINGS.getIndex());
WebElement switchCheckBox = showPaginationByDefaultSwitch.findElement(By.className("ui-chkbox-box"));
Expand Down

0 comments on commit 1c6a99a

Please sign in to comment.