From b06ac3f1e1e896fc4e0cd604b7f246dcb26fb34a Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Tue, 3 May 2022 15:31:32 +0000 Subject: [PATCH] Bug 30673: Improve is_valid_date function for validating date strings This patch corrects a couple of issues with our date validation in both the staff interface and the OPAC. The "is_valid_date" function needs to be able to accept a custom date format when one has been defined to override the default Flatpickr configuration. The function also needs to do better checking of the date itself following the transition to Flatpickr. jQueryUI's parse method had better built-in error handling, whereas Flatpickr's simply tries its best to convert a string into a date. We can use the existing Date_from_syspref function to check that the date string can be converted to a valid JavaScript Date object. To test, apply the patch and test date input fields in a few places in the staff interface, e.g. the patron edit form, the circulation statistics wizard, or the overdues page. Also check these specific pages: - With the dateformat system preference set to something other than "yyyy-mm-dd" open an item for editing. The "Date acquired" date picker should work correctly and fill the date in "yyyy-mm-dd" format (overriding the Flatpickr default). - Check Serial -> Claims to confirm that the "To" and "From" filters work correctly. - Test that various dateformat preference settings work in all cases. In the OPAC, test that date picker inputs work correctly on pages like the "Place hold" page, the "Your personal details" page, and "Your summary" -> "Holds" -> "Suspend." --- koha-tmpl/intranet-tmpl/prog/js/calendar.js | 59 +++++++-------- .../bootstrap/en/includes/calendar.inc | 75 ++++++++++++++----- 2 files changed, 84 insertions(+), 50 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/js/calendar.js b/koha-tmpl/intranet-tmpl/prog/js/calendar.js index 81561cc42d..17c68d8d33 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/calendar.js +++ b/koha-tmpl/intranet-tmpl/prog/js/calendar.js @@ -1,74 +1,73 @@ -/* global debug sentmsg __ dateformat_pref flatpickr_dateformat_string bidi calendarFirstDayOfWeek */ -/* exported DateTime_from_syspref flatpickr_weekdays flatpickr_months */ +/* global debug sentmsg __ dateformat_pref flatpickr_dateformat_string */ +/* exported DateTime_from_syspref flatpickr_weekdays flatpickr_months validate_date */ var MSG_PLEASE_ENTER_A_VALID_DATE = ( __("Please enter a valid date (should match %s).") ); if (debug > 1) { alert("dateformat: " + dateformat_pref + "\ndebug is on (level " + debug + ")"); } -function is_valid_date(date) { +function is_valid_date( date, dateformat_string ) { // An empty string is considered as a valid date for convenient reasons. if (date === '') return 1; - var dateformat = flatpickr_dateformat_string; - if (dateformat == 'us') { + let dateformat; + const ourformat = dateformat_string === undefined ? flatpickr_dateformat_string : dateformat_string; + /* Check that the date string matches the general date format rules */ + if (ourformat == 'm/d/Y') { + dateformat = "us"; if (date.search(/^\d{2}\/\d{2}\/\d{4}($|\s)/) == -1) return 0; - dateformat = 'm/d/Y'; - } else if (dateformat == 'metric') { + } else if (ourformat == 'd/m/Y') { + dateformat = "metric"; if (date.search(/^\d{2}\/\d{2}\/\d{4}($|\s)/) == -1) return 0; - dateformat = 'd/m/Y'; - } else if (dateformat == 'iso') { - if (date.search(/^\d{4}-\d{2}-\d{2}($|\s)/) == -1) return 0; - dateformat = 'Y-m-d'; - } else if (dateformat == 'dmydot') { + } else if (ourformat == 'd.m.Y') { + dateformat = "dmydot"; if (date.search(/^\d{2}\.\d{2}\.\d{4}($|\s)/) == -1) return 0; - dateformat = 'd.m.Y'; - } - try { - flatpickr.parseDate(date, dateformat); - } catch (e) { - return 0; + } else if (ourformat == 'Y-m-d') { + dateformat = "iso"; + if (date.search(/^\d{4}-\d{2}-\d{2}($|\s)/) == -1) return 0; } - return 1; + /* Check that the date is a valid date */ + const dateobj = Date_from_syspref(date, dateformat); + return ( dateobj instanceof Date && !isNaN( dateobj ) ) ? 1 : 0; } function get_dateformat_str(dateformat) { var dateformat_str; if (dateformat == 'us') { - dateformat_str = 'mm/dd/yyyy'; + dateformat_str = __("mm/dd/yyyy"); } else if (dateformat == 'metric') { - dateformat_str = 'dd/mm/yyyy'; + dateformat_str = __("dd/mm/yyyy"); } else if (dateformat == 'iso') { - dateformat_str = 'yyyy-mm-dd'; + dateformat_str = __("yyyy-mm-dd"); } else if (dateformat == 'dmydot') { - dateformat_str = 'dd.mm.yyyy'; + dateformat_str = __("dd.mm.yyyy"); } return dateformat_str; } function validate_date(dateText, inst) { - if (!is_valid_date(dateText)) { + if (!is_valid_date( dateText, inst.config.dateFormat )) { var dateformat_str = get_dateformat_str( dateformat_pref ); alert(MSG_PLEASE_ENTER_A_VALID_DATE.format(dateformat_str)); inst.clear(); } } -function Date_from_syspref(dstring) { +function Date_from_syspref( dstring, dateformat = dateformat_pref ) { var dateX = dstring.split(/[-/.]/); if (debug > 1 && sentmsg < 1) { sentmsg++; alert("Date_from_syspref(" + dstring + ") splits to:\n" + dateX.join("\n")); } - if (dateformat_pref === "iso") { + if (dateformat === "iso") { return new Date(dateX[0], (dateX[1] - 1), dateX[2]); // YYYY-MM-DD to (YYYY,m(0-11),d) - } else if (dateformat_pref === "us") { + } else if (dateformat === "us") { return new Date(dateX[2], (dateX[0] - 1), dateX[1]); // MM/DD/YYYY to (YYYY,m(0-11),d) - } else if (dateformat_pref === "metric") { + } else if (dateformat === "metric") { return new Date(dateX[2], (dateX[1] - 1), dateX[0]); // DD/MM/YYYY to (YYYY,m(0-11),d) - } else if (dateformat_pref === "dmydot") { + } else if (dateformat === "dmydot") { return new Date(dateX[2], (dateX[1] - 1), dateX[0]); // DD.MM.YYYY to (YYYY,m(0-11),d) } else { if (debug > 0) { - alert("KOHA ERROR - Unrecognized date format: " + dateformat_pref); + alert("KOHA ERROR - Unrecognized date format: " + dateformat); } return 0; } diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/calendar.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/calendar.inc index 8a4877f9f4..c204f47882 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/calendar.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/calendar.inc @@ -84,31 +84,44 @@ }, }); - var MSG_PLEASE_ENTER_A_VALID_DATE = ( __("Please enter a valid date (should match %s).") ); + var MSG_PLEASE_ENTER_A_VALID_DATE = ( _("Please enter a valid date (should match %s).") ); - function is_valid_date(date) { + function is_valid_date( date, dateformat_string ) { // An empty string is considered as a valid date for convenient reasons. if (date === '') return 1; - var dateformat = flatpickr_dateformat_string; - switch ( dateformat_pref ){ - case "us": - flatpickr_dateformat_string = "m/d/Y"; - break; - case "metric": - flatpickr_dateformat_string = "d/m/Y"; - break; - case "dmydot": - flatpickr_dateformat_string = "d.m.Y"; - break; - default: - flatpickr_dateformat_string = "Y-m-d"; + let dateformat; + const ourformat = dateformat_string === undefined ? flatpickr_dateformat_string : dateformat_string; + /* Check that the date string matches the general date format rules */ + if (ourformat == 'm/d/Y') { + dateformat = "us"; + if (date.search(/^\d{2}\/\d{2}\/\d{4}($|\s)/) == -1) return 0; + } else if (ourformat == 'd/m/Y') { + dateformat = "metric"; + if (date.search(/^\d{2}\/\d{2}\/\d{4}($|\s)/) == -1) return 0; + } else if (ourformat == 'd.m.Y') { + dateformat = "dmydot"; + if (date.search(/^\d{2}\.\d{2}\.\d{4}($|\s)/) == -1) return 0; + } else if (ourformat == 'Y-m-d') { + dateformat = "iso"; + if (date.search(/^\d{4}-\d{2}-\d{2}($|\s)/) == -1) return 0; } - try { - flatpickr.parseDate(date, dateformat); - } catch (e) { - return 0; + /* Check that the date is a valid date */ + const dateobj = Date_from_syspref(date, dateformat); + return ( dateobj instanceof Date && !isNaN( dateobj ) ) ? 1 : 0; + } + + function get_dateformat_str(dateformat) { + var dateformat_str; + if (dateformat == 'us') { + dateformat_str = _("mm/dd/yyyy"); + } else if (dateformat == 'metric') { + dateformat_str = _("dd/mm/yyyy"); + } else if (dateformat == 'iso') { + dateformat_str = _("yyyy-mm-dd"); + } else if (dateformat == 'dmydot') { + dateformat_str = _("dd.mm.yyyy"); } - return 1; + return dateformat_str; } function validate_date(dateText, inst) { @@ -119,6 +132,28 @@ } } + function Date_from_syspref( dstring, dateformat = dateformat_pref ) { + var dateX = dstring.split(/[-/.]/); + if (debug > 1 && sentmsg < 1) { + sentmsg++; + alert("Date_from_syspref(" + dstring + ") splits to:\n" + dateX.join("\n")); + } + if (dateformat === "iso") { + return new Date(dateX[0], (dateX[1] - 1), dateX[2]); // YYYY-MM-DD to (YYYY,m(0-11),d) + } else if (dateformat === "us") { + return new Date(dateX[2], (dateX[0] - 1), dateX[1]); // MM/DD/YYYY to (YYYY,m(0-11),d) + } else if (dateformat === "metric") { + return new Date(dateX[2], (dateX[1] - 1), dateX[0]); // DD/MM/YYYY to (YYYY,m(0-11),d) + } else if (dateformat === "dmydot") { + return new Date(dateX[2], (dateX[1] - 1), dateX[0]); // DD.MM.YYYY to (YYYY,m(0-11),d) + } else { + if (debug > 0) { + alert("KOHA ERROR - Unrecognized date format: " + dateformat); + } + return 0; + } + } + $(document).ready(function(){ $(".flatpickr").flatpickr(); -- 2.20.1