From 0111632f1e5edd4f7d23a1888e2e2e576d757c43 Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Mon, 4 Oct 2021 16:33:25 +0000 Subject: [PATCH] Bug 28963: Use Flatpickr on calendar page This patch replaces the use of jQueryUI's datepicker widget on the Calendar page. In order to ease customization of the static calendar which shows the current calendar, I've converted the calendar.css file to SCSS. This allows us to define new SCSS variables to pass to the Flatpickr SCSS. Also changed: Removed some unecessary comments in the template. 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 Tools -> Calendar. - Confirm that entering holidays works correctly for all types: Single, weekly, yearly, ranges, repeated ranges. - Confirm that holidays are deleted as expected. - Confirm that the colors of each type of holiday is correct. Signed-off-by: David Nind Signed-off-by: Katrin Fischer Signed-off-by: Jonathan Druart --- .../prog/css/src/_flatpickr.scss | 3 +- .../src/{_vars.scss => _flatpickr_vars.scss} | 4 +- .../intranet-tmpl/prog/css/src/calendar.scss | 149 ++++++++++++++++++ .../prog/en/modules/tools/holidays.tt | 139 ++++++++-------- 4 files changed, 223 insertions(+), 72 deletions(-) rename koha-tmpl/intranet-tmpl/prog/css/src/{_vars.scss => _flatpickr_vars.scss} (94%) create mode 100644 koha-tmpl/intranet-tmpl/prog/css/src/calendar.scss diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr.scss b/koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr.scss index 19462121b3..59886c9e83 100644 --- a/koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr.scss +++ b/koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr.scss @@ -1,4 +1,4 @@ -@import "vars"; +@import "flatpickr_vars"; @-webkit-keyframes fpFadeInDown { from { @@ -69,6 +69,7 @@ direction: ltr; display: none; font-size: 14px; + gap: 2px; line-height: 24px; opacity: 0; padding: 0; diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/_vars.scss b/koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr_vars.scss similarity index 94% rename from koha-tmpl/intranet-tmpl/prog/css/src/_vars.scss rename to koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr_vars.scss index 98bbac315e..0c0eaffab3 100644 --- a/koha-tmpl/intranet-tmpl/prog/css/src/_vars.scss +++ b/koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr_vars.scss @@ -2,9 +2,9 @@ $bezier: cubic-bezier(0.23, 1, 0.32, 1); $slideTime: 400ms; -$daySize: 39px; +$daySize: 39px !default; $padding: $daySize / 16; -$dayMargin: 2px; +$dayMargin: 2px !default; $daysWidth: $daySize * 7 + $dayMargin * 14 + $padding * 2 + 2; $calendarWidth: $daysWidth; diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/calendar.scss b/koha-tmpl/intranet-tmpl/prog/css/src/calendar.scss new file mode 100644 index 0000000000..fdf972ea51 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/css/src/calendar.scss @@ -0,0 +1,149 @@ +$daySize: 45px; +$exception_bg: #B3D4FF; +$holiday_bg: #FFAEAE; +$repeatableweekly_bg: #FFFF99; +$repeatableyearly_bg: #FFCC66; +$selected: #B9DB88; + +@import "flatpickr"; + +.controls { + display: block; + padding: 3px 0; +} + +.key { + line-height: 230%; + padding: 3px; + white-space: nowrap; + + &.exception { + background-color: $exception_bg; + } + + &.holiday { + background-color: $holiday_bg; + } + + &.repeatableweekly { + background-color: $repeatableweekly_bg; + } + + &.repeatableyearly { + background-color: $repeatableyearly_bg; + } +} + +.flatpickr-day { + &.selected { + background-color: $selected; + border: 0; + } + + &.exception { + background-color: $exception_bg; + + &.selected { + border: 3px solid $selected; + } + } + + &.holiday { + background-color: $holiday_bg; + + &.selected { + border: 3px solid $selected; + } + } + + &.repeatableweekly { + background-color: $repeatableweekly_bg; + + &.selected { + border: 3px solid $selected; + } + } + + &.repeatableyearly { + background-color: $repeatableyearly_bg; + + &.selected { + border: 3px solid $selected; + } + } +} + +#holidayexceptions th.exception { + background-color: $exception_bg; +} + +#holidaysunique th.holiday { + background-color: $holiday_bg; + + &.selected { + border: 2px solid #fff4c6; + } +} + +#holidayweeklyrepeatable th.repeatableweekly { + background-color: $repeatableweekly_bg; +} + +#holidaysyearlyrepeatable th.repeatableyearly { + background-color: $repeatableyearly_bg; +} + +.panel { + border: 1px solid #B9D8D9; + border-radius: 4px; + box-shadow: none; + padding: 0; + display: none; + margin: 1em 0; + z-index: 1; +} + +fieldset.brief { + border: 0; + border-radius: 4px; + margin: 0; +} + +#showHoliday { + margin: .5em 0; +} + +fieldset.brief ol { + font-size: 100%; +} + +fieldset.brief li, +fieldset.brief li.radio { + padding: 0.2em 0; +} + +#holidayweeklyrepeatable, +#holidaysyearlyrepeatable, +#holidaysunique, +#holidayexceptions { + font-size: 90%; + margin-bottom: 1em; +} + +#calendar-container { + margin: 1em 0; +} + +#calendar-anchor { + display: none; +} + +.flatpickr-calendar { + border-radius: 0; + border: 1px solid #B9D8D9; + box-shadow: none; +} + +.dayContainer { + gap: 3px; +} diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt index 5d20e5a938..ac728fe74d 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt @@ -41,11 +41,6 @@ [% PROCESS options_for_libraries libraries => Branches.all( selected => branch ) %] - - - - -
@@ -76,7 +71,7 @@
  • To date: - +
  • @@ -141,7 +136,7 @@
  • - +
    @@ -174,7 +169,7 @@
  • To date: - +
  • @@ -228,15 +223,10 @@
  • - - - - - - - -

    Calendar information

    -
    +
    +

    Calendar information

    + +
    @@ -497,35 +487,48 @@ location.href='/cgi-bin/koha/tools/holidays.pl?branch=' + branch + '&calendardate=' + "[% calendardate | html %]"; } - function Help() { - newin=window.open("/cgi-bin/koha/help.pl","KohaHelp",'width=600,height=600,toolbar=false,scrollbars=yes'); - } - - /* This function gives css clases to each kind of day */ - function dateStatusHandler(date) { - date = new Date(date); - var day = date.getDate(); - var month = date.getMonth() + 1; - var year = date.getFullYear(); - var weekDay = date.getDay(); + /** + * Build settings to be passed to the formatDay function for each day in the calendar + * @param {object} dayElem - HTML node passed from Flatpickr + * @return {void} + */ + function dateStatusHandler( dayElem ) { + var day = dayElem.dateObj.getDate(); + var month = dayElem.dateObj.getMonth() + 1; + var year = dayElem.dateObj.getFullYear(); + var weekDay = dayElem.dateObj.getDay(); var dayMonth = month + '/' + day; var dateString = year + '/' + month + '/' + day; if (exception_holidays[dateString] != null) { - return [true, "exception", _("Exception: %s").format(exception_holidays[dateString].title)]; + formatDay( [ "exception", _("Exception: %s").format(exception_holidays[dateString].title)], dayElem ); } else if ( week_days[weekDay] != null ){ - return [true, "repeatableweekly", _("Weekly holiday: %s").format(week_days[weekDay].title)]; + formatDay( [ "repeatableweekly", _("Weekly holiday: %s").format(week_days[weekDay].title)], dayElem ); } else if ( day_month_holidays[dayMonth] != null ) { - return [true, "repeatableyearly", _("Yearly holiday: %s").format(day_month_holidays[dayMonth].title)]; + formatDay( [ "repeatableyearly", _("Yearly holiday: %s").format(day_month_holidays[dayMonth].title)], dayElem ); } else if (holidays[dateString] != null) { - return [true, "holiday", _("Single holiday: %s").format(holidays[dateString].title)]; + formatDay( [ "holiday", _("Single holiday: %s").format(holidays[dateString].title)], dayElem ); } else { - return [true, "normalday", _("Normal day")]; + formatDay( [ "normalday", _("Normal day")], dayElem ); } } - /* This function is in charge of showing the correct panel considering the kind of holiday */ - function dateChanged(calendar) { - calendar = new Date(calendar); + /** + * Adds style and title attribute to a day on the calendar + * @param {object} settings - span class attribute ([0]) and title attribute ([1]) + * @param {node} dayElem - HTML node passed from Flatpickr + * @return {void} + */ + function formatDay( settings, dayElem ){ + $(dayElem).attr("title", settings[1]).addClass( settings[0]); + } + + /** + * Triggers an action based on a click on a calendar day: If a holiday exists on + * that day it loads an edit form. If there is no existing holiday one can be created + * @param {object} calendar - a Date object corresponding to the clicked day + * @return {void} + */ + function dateChanged( calendar ) { var day = calendar.getDate(); var month = calendar.getMonth() + 1; var year = calendar.getFullYear(); @@ -579,7 +582,7 @@ "sDom": 't', "bPaginate": false })); - var tables = $("#holidayexceptions,#holidaysyearlyrepeatable,#holidaysunique").DataTable($.extend(true, {}, dataTablesDefaults, { + var tables = $("#holidayexceptions, #holidaysyearlyrepeatable, #holidaysunique").DataTable($.extend(true, {}, dataTablesDefaults, { "sDom": 't', "bPaginate": false, "createdRow": function( row, data, dataIndex ) { @@ -597,46 +600,44 @@ $("a.helptext").click(function(){ $(this).parent().find(".hint").toggle(); return false; }); - $("#dateofrange").datepicker({ - beforeShow: function() { - var startdate = $("#jcalendar-container").datepicker("getDate"); - if (startdate !== null) { - var sd = new Date(startdate); - var ed = new Date($(this).datepicker("getDate")); - if (ed < sd) { - $(this).datepicker("setDate", startdate); - $(this).datepicker("option", "defaultDate", startdate); - } - } - } - }); - $("#datecancelrange").datepicker(); + + var dateofrange = $("#dateofrange").flatpickr(); + + var datecancelrange = $("#datecancelrange").flatpickr(); + $("#dateofrange").each(function () { this.value = "" }); $("#datecancelrange").each(function () { this.value = "" }); - $("#jcalendar-container").datepicker({ - beforeShowDay: function(thedate) { - var day = thedate.getDate(); - var month = thedate.getMonth() + 1; - var year = thedate.getFullYear(); - var dateString = year + '/' + month + '/' + day; - return dateStatusHandler(dateString); + + var maincalendar = $("#calendar-anchor").flatpickr({ + inline: true, + onReady: function(){ + return; + }, + onDayCreate: function( dObj, dStr, fp, dayElem ){ + /* for each day on the calendar, get the + correct status information for the date */ + dateStatusHandler( dayElem ); }, - onSelect: function(dateText, inst) { - dateChanged($(this).datepicker("getDate")); - var enddate = $("#dateofrange").datepicker("getDate"); - $("#dateofrange").datepicker("option", "defaultDate", $(this).datepicker("getDate")); - $("#dateofrange").datepicker( "option", "minDate", $(this).datepicker("getDate")); //ensure end date can't be before start date - if (enddate !== null) { - var ed = new Date(enddate); - var sd = new Date($(this).datepicker("getDate")); - if (ed < sd) { - $("#dateofrange").datepicker("setDate", $(this).datepicker("getDate")); - $("#dateofrange").datepicker("option", "defaultDate", enddate); + onChange: function( selectedDates, dateStr, instance ){ + var fromdate = selectedDates[0]; + var enddate = dateofrange.selectedDates[0]; + + dateChanged( fromdate ); + + dateofrange.set( 'defaultDate', fromdate ); + dateofrange.set( 'minDate', fromdate ); + + if ( enddate != undefined ) { + if ( enddate < fromdate ) { + dateofrange.set("defaultDate", fromdate); + dateofrange.setDate(fromdate); } } + }, defaultDate: new Date("[% keydate | html %]") }); + $(".hidePanel").on("click",function(){ if( $(this).hasClass("showHoliday") ){ hidePanel("showHoliday"); -- 2.39.5