Browse Source

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 <david@davidnind.com>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
21.11.x
Owen Leonard 3 years ago
committed by Jonathan Druart
parent
commit
0111632f1e
  1. 3
      koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr.scss
  2. 4
      koha-tmpl/intranet-tmpl/prog/css/src/_flatpickr_vars.scss
  3. 149
      koha-tmpl/intranet-tmpl/prog/css/src/calendar.scss
  4. 139
      koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt

3
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;

4
koha-tmpl/intranet-tmpl/prog/css/src/_vars.scss → 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;

149
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;
}

139
koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt

@ -41,11 +41,6 @@
[% PROCESS options_for_libraries libraries => Branches.all( selected => branch ) %]
</select>
<!-- ******************************** FLAT PANELS ******************************************* -->
<!-- ***** Makes all the flat panel to deal with holidays ***** -->
<!-- **************************************************************************************** -->
<!-- ********************** Panel for showing already loaded holidays *********************** -->
<div class="panel" id="showHoliday">
<form action="/cgi-bin/koha/tools/exceptionHolidays.pl" method="post">
<input type="hidden" id="showHolidayType" name="showHolidayType" value="" />
@ -76,7 +71,7 @@
</li>
<li class="dateinsert">
<strong>To date: </strong>
<input type="text" id="datecancelrange" name="datecancelrange" size="20" value="[% datecancelrange | html %]" class="datepicker"/>
<input type="text" id="datecancelrange" name="datecancelrange" size="20" value="[% datecancelrange | html %]" />
</li>
<li>
<label for="showTitle">Title: </label><input type="text" name="showTitle" id="showTitle" size="35" />
@ -141,7 +136,7 @@
</form>
</div> <!-- /#showHoliday -->
<!-- ***************************** Panel to deal with new holidays ********************** -->
<!-- Panel to deal with new holidays -->
<div class="panel" id="newHoliday">
<form action="/cgi-bin/koha/tools/newHolidays.pl" method="post">
<fieldset class="brief">
@ -174,7 +169,7 @@
</li>
<li class="dateinsert">
<strong>To date: </strong>
<input type="text" id="dateofrange" name="dateofrange" size="20" value="[% dateofrange | html %]" class="datepicker" />
<input type="text" id="dateofrange" name="dateofrange" size="20" value="[% dateofrange | html %]" />
</li>
<li>
<label for="title">Title: </label>
@ -228,15 +223,10 @@
</form>
</div> <!-- /#newHoliday -->
<!-- *************************************************************************************** -->
<!-- ****** END OF FLAT PANELS ****** -->
<!-- *************************************************************************************** -->
<!-- ************************************************************************************** -->
<!-- ****** MAIN SCREEN CODE ****** -->
<!-- ************************************************************************************** -->
<h3>Calendar information</h3>
<div id="jcalendar-container"></div>
<div id="calendar-container">
<h3>Calendar information</h3>
<span id="calendar-anchor"></span>
</div>
<div style="margin-top: 2em;">
<form action="copy-holidays.pl" method="post">
<input type="hidden" name="from_branchcode" value="[% branch | html %]" />
@ -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");

Loading…
Cancel
Save