From f3bddf24ac193485890dc93b12897405f44d3881 Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Fri, 8 Oct 2021 15:31:46 +0000 Subject: [PATCH] Bug 28694: Check alert in cataloguing should be a static message This patch modifies the basic cataloging interface so that form validation errors are collected in a static "dialog" at the top of the page instead of showing in a transient JavaScript alert. The text of the message is roughly the same as it was in the alert, and links have been added so that the user can click to jump directly to the field referenced. If the user scrolls down away from the static error message, a button appears in the floating toolbar to jump back to the message. To test, apply the patch and rebuild the staff interface CSS (https://wiki.koha-community.org/wiki/Working_with_SCSS_in_the_OPAC_and_staff_client). - Go to Cataloging and create a new record using the basic cataloging editor and a framework which has multiple mandatory fields defined (e.g. an unmodified default framework) - Without entering anything in mandatory fields, click the "Save" button. - You should see a message box appear at the top of the page. - It should list each missing mandatory subfield and tag, each with a "Go to field" link next to it. - Clicking the "Go to field" link should switch you to the correct tab and scroll the mandatory field into view. - When you have scrolled down far enough for the error messages to be offscreen, an "Errors" button should appear in the floating toolbar. Clicking it should scroll the box back into view. - The JS function for scrolling to a particular element on the screen has been modified, so test that the links in the toolbar for individual tags still work correctly. --- .../intranet-tmpl/prog/css/addbiblio.css | 12 ++ .../prog/css/src/staff-global.scss | 12 ++ .../prog/en/modules/cataloguing/addbiblio.tt | 114 ++++++++++++++---- 3 files changed, 115 insertions(+), 23 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/css/addbiblio.css b/koha-tmpl/intranet-tmpl/prog/css/addbiblio.css index 3c6974fb5c..634f2b2af6 100644 --- a/koha-tmpl/intranet-tmpl/prog/css/addbiblio.css +++ b/koha-tmpl/intranet-tmpl/prog/css/addbiblio.css @@ -368,6 +368,18 @@ tbody tr.active td { background-color: #FFAAAA !important; } + .show-errors { + background: #FFEC8C none; + border-color: #E0C726; + color: #000; + display: none; + text-shadow: none; +} + +.floating .show-errors { + display: inline-block; +} + @media (min-width: 768px) { li.subfield_line label { width: 20em; diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss index 5889f41d71..85c64461f7 100644 --- a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss +++ b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss @@ -1774,6 +1774,7 @@ i { padding: .5em; text-align: center; width: 65%; + max-width: 600px; a { &.approve { @@ -1860,6 +1861,17 @@ i { strong { color: #900; } + + &.list { + text-align: left; + + h2, + h3, + h4 { + margin: 1em 0; + text-align: left; + } + } } } 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 2d158edac2..16067c5feb 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt @@ -155,14 +155,24 @@ $(".tag_anchor").on("click", function(e){ e.preventDefault(); - var toolbar_height = $("#toolbar").outerHeight(); $(".tag_anchor").removeClass("selected"); $(this).addClass("selected"); var link = this.href; var linkid = link.substring( link.indexOf("#") + 1 ); - var dest = $("#" + linkid ); - var yoffset = dest.offset(); - window.scrollTo( 0, yoffset.top - toolbar_height - 20 ); + window.scrollTo( 0, getScrollto( linkid, "toolbar" ) ); + }); + + $("body").on("click", ".linkfield", function(e){ + e.preventDefault(); + var tab = $(this).data("tab"); + var field = $(this).data("field"); + var tablink = $("a[data-tabid='" + tab + "']" ); + selectTab( tablink ); + window.scrollTo( 0, getScrollto( field, "toolbar" ) ); + }); + + $("body").on("click", ".show-errors", function(e){ + document.getElementById("form-errors").scrollIntoView(); }); }); @@ -176,6 +186,26 @@ $(".tag_anchors_" + tabid ).addClass("tab_selected").show(); } + /** + * Returns a roughly ideal position to scroll an element into view + * @param {string} target - The HTML id of the element to scroll into view + * @param {string} elemid - The HTML id of the element which might obscure + * the view of the target element e.g. a floating toolbar + * @return {number} - The y-coordinate to pass to window.scrollTo() + */ + function getScrollto( target, elemid ){ + var dest = $("#" + target ); + var yoffset = dest.offset(); + + if( elemid != "" ){ + var element = $("#" + elemid ); + var elem_height = element.outerHeight(); + } else { + elem_height = 0; + } + return yoffset.top - elem_height - 20; + } + function redirect(dest){ $("#redirect").attr("value",dest); return Check(); @@ -185,7 +215,7 @@ var onOption = function () { return Check(); } -[% END %] + [% END %] /** * this function append button for create new authority if not found @@ -512,14 +542,14 @@ function PopupMARCFieldDoc(field) { var label = new Array(); var flag=0; var tabflag= new Array(); - var StrAlert = ""; + var StrAlert = "
"; var notFilledClass = "subfield_not_filled"; if (mandatory) { [% FOREACH BIG_LOO IN BIG_LOOP %] [% FOREACH innerloo IN BIG_LOO.innerloop %] [% IF ( innerloo.mandatory ) %] - fields.push(new Array("[% innerloo.tag | html %]","[% innerloo.index | html %][% innerloo.random | html %]","[% innerloo.index | html %]")); + fields.push(new Array("[% innerloo.tag | html %]","[% innerloo.index | html %][% innerloo.random | html %]","[% innerloo.index | html %]", "[% BIG_LOO.number | html %]")); [% END %] [% FOREACH subfield_loo IN innerloo.subfield_loop %] [% IF ( subfield_loo.mandatory ) %]subfields.push("[% subfield_loo.id | html %]"); @@ -529,12 +559,12 @@ function PopupMARCFieldDoc(field) { [% END %] [% END %] [% END %] - StrAlert = _("Can't save this record because the following field aren't filled:"); + StrAlert += "

" + _("The following subfields aren't filled:") + "

"; } else { [% FOREACH BIG_LOO IN BIG_LOOP %] [% FOREACH innerloo IN BIG_LOO.innerloop %] [% IF ( innerloo.important ) %] - fields.push(new Array("[% innerloo.tag | html %]","[% innerloo.index | html %][% innerloo.random | html %]","[% innerloo.index | html %]")); + fields.push(new Array("[% innerloo.tag | html %]","[% innerloo.index | html %][% innerloo.random | html %]","[% innerloo.index | html %]", "[% BIG_LOO.number | html %]")); [% END %] [% FOREACH subfield_loo IN innerloo.subfield_loop %] [% IF ( subfield_loo.important ) %]subfields.push("[% subfield_loo.id | html %]"); @@ -544,11 +574,10 @@ function PopupMARCFieldDoc(field) { [% END %] [% END %] [% END %] - StrAlert = _("A few important fields are not filled:"); + StrAlert += "

" + _("A few important fields are not filled:") + "

"; notFilledClass = "important_subfield_not_filled"; } - - StrAlert += "\n\n"; + StrAlert += ""; /* Check for mandatories/importants field(not subfields) */ + /* Loop over array of fields identified as mandatory or + important to see if at least one subfield is filled */ + mandatoryFields = new Object(); + for(var i=0,len=fields.length; i 0 ){ + StrAlert += "

" + _("The following fields aren't filled:") + "

"; + StrAlert += "
    "; + for( var prop in mandatoryFields ){ + if( mandatoryFields[prop]["importance"] == "mandatory" ){ + StrAlert += "
  • " + _("Field %s is mandatory, at least one of its subfields must be filled.").format( prop ) + ' Go to field
  • '; + } else { + StrAlert += "
  • " + _("Field %s is important, at least one of its subfields must be filled.").format(arr[0]) + ' Go to field
  • '; + } + } + StrAlert += "
"; + } + StrAlert += "
"; if(flag){ + $("#show-errors").html('