From 5ebcbb67b7ed77c1c3dfbf3342584520c387d87f Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 27 Feb 2026 18:33:05 +0000 Subject: [PATCH] Bug 35104: Show nonxml_stripped errors in edit form with quick-links to fields Two related changes: 1. Metadata::store() no longer auto-clears nonxml_stripped errors on a clean re-save. Errors are review flags that require deliberate human resolution; they are only replaced when fresh stripping occurs on the same record. 2. addbiblio.pl loads any existing nonxml_stripped errors for a biblio being edited and passes them to the template. The template renders them in an alert banner above the editor with "Go to field" quick-links that navigate to the correct tab and scroll to the first occurrence of the affected subfield. A custom .nonxml-linkfield JS handler resolves the tab and element at click time using the tag/subfield data attributes, avoiding the need to know the random element-ID suffix server-side. --- Koha/Biblio/Metadata.pm | 7 ++-- cataloguing/addbiblio.pl | 29 ++++++++++++++++ .../prog/en/modules/cataloguing/addbiblio.tt | 34 +++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Koha/Biblio/Metadata.pm b/Koha/Biblio/Metadata.pm index 6cb83e2a6af..d673004617d 100644 --- a/Koha/Biblio/Metadata.pm +++ b/Koha/Biblio/Metadata.pm @@ -117,9 +117,12 @@ sub store { $self->SUPER::store; - # Sync nonxml_stripped error rows: clear any existing, then re-add if needed - $self->metadata_errors->search( { error_type => 'nonxml_stripped' } )->delete; + # If this save triggered fresh stripping, replace all existing nonxml_stripped + # errors with the new set. If the save was clean (no stripping needed), leave + # any existing errors alone – they are review flags requiring explicit human + # resolution and should not be silently cleared by a routine re-save. if ($nonxml_error_message) { + $self->metadata_errors->search( { error_type => 'nonxml_stripped' } )->delete; my @occurrences = ref $nonxml_error_message eq 'ARRAY' ? @{$nonxml_error_message} diff --git a/cataloguing/addbiblio.pl b/cataloguing/addbiblio.pl index 4bb600a029a..144095b30c2 100755 --- a/cataloguing/addbiblio.pl +++ b/cataloguing/addbiblio.pl @@ -681,6 +681,35 @@ if ($biblionumber) { } } +# Load any existing nonxml_stripped errors so they can be shown in the edit form +# with quick-links to the affected fields. +if ( $biblio && $is_a_modif ) { + my @existing_errors = $biblio->metadata->metadata_errors->search( { error_type => 'nonxml_stripped' } )->as_list; + if (@existing_errors) { + $template->param( + existing_nonxml_errors => [ + map { + my $msg = $_->message; + + # First line is "TAG$sub: invalid char ..." – extract tag/subfield + my ($field_ref) = $msg =~ /^(\S+?):/; + my ( $tag, $subfield ) = + $field_ref && $field_ref =~ /^(\w+)\$(\w)$/ ? ( $1, $2 ) + : $field_ref ? ( $field_ref, undef ) + : ( undef, undef ); + { + id => $_->id, + message => $msg, + field_ref => $field_ref // '', + tag => $tag // '', + subfield => $subfield // '', + } + } @existing_errors + ] + ); + } +} + #------------------------------------------------------------------------------------- if ( $op eq "cud-addbiblio" ) { diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt index 46d4827e9a8..dea2d4911ad 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt @@ -193,6 +193,21 @@ document.getElementById("form-errors").scrollIntoView(); }); + $("body").on("click", ".nonxml-linkfield", function(e){ + e.preventDefault(); + var tag = $(this).data("tag"); + var sub = $(this).data("subfield") || "@"; + // Find the first subfield_line for this tag+subfield (random suffix unknown) + var $li = $('li[id^="subfield' + tag + sub + '"]').first(); + if ( !$li.length ) return; + // Determine which tab contains the field + var $tabpane = $li.closest(".tab-pane"); + if ( $tabpane.length ) { + selectTab("#" + $tabpane.attr("id")); + } + window.scrollTo(0, getScrollto($li.attr("id"), "toolbar")); + }); + }); function selectTab( tablink ){ @@ -798,6 +813,25 @@ [% END #/ WRAPPER sub-header.inc %] [% WRAPPER 'main-container.inc' wide_centered => 1 %] + [% IF existing_nonxml_errors %] +
+

Data quality warnings

+

Non-XML characters were automatically stripped from this record when it was last saved. Please review the affected fields and correct or confirm the data.

+ +
+ [% END %] [% IF ( INVALID_METADATA ) %]

Errors found

-- 2.53.0