Bug 29212: Use Flatpickr on OPAC pages

This patch adds Flatpickr assets to the OPAC (JS and SCSS). A few pages
are updated to use Flatpickr instead of jQueryUI datepickers.

jQueryUI CSS files are updated because they contain some font family
definitions which are simple to remove but overly complicated to
override. Without this change some Font Awesome icons are broken when
they appear inside jQueryUI widgets like tabs.

We don't run the risk of having this change overwritten by a future
jQueryUI upgrade because there won't be any more.

To test, apply the patch and rebuild the OPAC CSS
(https://wiki.koha-community.org/wiki/Working_with_SCSS_in_the_OPAC_and_staff_client).

- Log into the OPAC and check that date pickers on the following pages
  work correctly, including month selection, year selection, forward
  and back arrows, and "Clear date" controls:
- Go to the "Your personal details" page.
- Check the "Date of birth" field.
- With SuspendHoldsOpac enabled, view the "Your summary" page for a
  patron with pending holds.
- Click "Suspend" to confirm that the "Suspend until" datepicker
  works correctly for more than one hold.
- From the catalog search results page, select multiple results and
  click the "Place hold" link.
- On the hold confirmation page, click "Show more options" to test
  the "Hold starts on date" (with OPACAllowHoldDateInFuture enabled)
  and the "Hold not needed after" fields.

Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
This commit is contained in:
Owen Leonard 2021-10-13 17:51:08 +00:00 committed by Fridolin Somers
parent 56ea40359a
commit 5f4e4708a2
15 changed files with 1155 additions and 185 deletions

View file

@ -78,6 +78,8 @@ $high-contrast-grey: #666666;
@import "../../../../../node_modules/bootstrap/scss/type";
@import "../../../../../node_modules/bootstrap/scss/utilities";
@import "flatpickr";
/* Koha imports */
@import "fonts";
@ -621,7 +623,6 @@ div.dt-button-collection button.dt-button.buttons-print:not(.disabled):before {
.ui-widget select,
.ui-widget textarea,
.ui-widget button {
font-family: 'NotoSans';
font-size: inherit;
}
@ -799,35 +800,6 @@ ul {
/* End jQueryUI tab styles */
/* jQuery UI Datepicker */
.ui-datepicker {
@include shadowed;
table {
border: 0;
border-collapse: collapse;
font-size: .9em;
margin: 0 0 .4em;
width: 100%;
}
th {
background: transparent none;
border: 0;
font-weight: bold;
padding: .7em .3em;
text-align: center;
}
}
.ui-datepicker-trigger {
margin: 0 3px;
vertical-align: middle;
}
/* End jQueryUI datepicker styles */
/* jQueryUI Core */
.ui-widget-content {

View file

@ -0,0 +1,965 @@
@import "flatpickr_vars";
@-webkit-keyframes fpFadeInDown {
from {
opacity: 0;
transform: translate3d(0, -20px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
@-moz-keyframes fpFadeInDown {
from {
opacity: 0;
transform: translate3d(0, -20px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
@-ms-keyframes fpFadeInDown {
from {
opacity: 0;
transform: translate3d(0, -20px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
@-o-keyframes fpFadeInDown {
from {
opacity: 0;
transform: translate3d(0, -20px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
@keyframes fpFadeInDown {
from {
opacity: 0;
transform: translate3d(0, -20px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.flatpickr-calendar {
animation: none;
background: transparent;
border-radius: 5px;
border: 0;
box-sizing: border-box;
direction: ltr;
display: none;
font-size: 14px;
gap: 2px;
line-height: 24px;
opacity: 0;
padding: 0;
position: absolute;
text-align: center;
touch-action: manipulation;
visibility: hidden;
width: $calendarWidth;
@if variable-exists( "noCalendarBorder" ) {
box-shadow: 0 3px 13px rgba(black, 0.08);
}
@else {
background: $calendarBackground;
box-shadow: 1px 1px 3px 0 #666;
}
&.open,
&.inline {
opacity: 1;
max-height: 640px;
visibility: visible;
}
&.open {
display: inline-block;
z-index: 99999;
}
&.animate.open {
animation: fpFadeInDown 300ms $bezier;
}
&.inline {
display: block;
position: relative;
top: 2px;
}
&.static {
position: absolute;
top: calc(100% + 2px);
&.open {
z-index: 999;
display: block;
}
}
&.multiMonth {
.flatpickr-days .dayContainer:nth-child(n+1) {
& .flatpickr-day.inRange:nth-child(7n+7) {
box-shadow: none !important;
}
}
.flatpickr-days .dayContainer:nth-child(n+2) {
& .flatpickr-day.inRange:nth-child(7n+1) {
box-shadow: -2px 0 0 #e6e6e6, 5px 0 0 #e6e6e6;
}
}
}
.hasWeeks,
.hasTime {
.dayContainer {
border-bottom: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
}
@if variable-exists( "noCalendarBorder" ) {
.hasWeeks .dayContainer {
border-left: 0;
}
}
&.hasTime {
.flatpickr-time {
height: $timeHeight;
border-top: 1px solid $calendarBorderColor;
}
@if variable-exists( "noCalendarBorder" ) {
.flatpickr-innerContainer {
border-bottom: 0;
}
.flatpickr-time {
border: 1px solid $calendarBorderColor;
}
}
}
&.noCalendar.hasTime {
.flatpickr-time {
height: auto;
}
}
&:before,
&:after {
position: absolute;
display: block;
pointer-events: none;
border: solid transparent;
content: '';
height: 0;
width: 0;
left: 22px;
}
&.rightMost,
&.arrowRight {
&:before,
&:after {
left: auto;
right: 22px;
}
}
&.arrowCenter {
&:before,
&:after {
left: 50%;
right: 50%;
}
}
&:before {
border-width: 5px;
margin: 0 -5px;
}
&:after {
border-width: 4px;
margin: 0 -4px;
}
&.arrowTop {
&:before,
&:after {
bottom: 100%;
}
&:before {
border-bottom-color: $calendarBorderColor;
}
&:after {
@if variable-exists( "noCalendarBorder" ) {
border-bottom-color: $monthBackground;
}
@else {
border-bottom-color: $calendarBackground;
}
}
}
&.arrowBottom {
&:before,
&:after {
top: 100%;
}
&:before {
border-top-color: $calendarBorderColor;
}
&:after {
@if variable-exists( "noCalendarBorder" ) {
border-top-color: $monthBackground;
}
@else {
border-top-color: $calendarBackground;
}
}
}
&:focus {
outline: 0;
}
}
.flatpickr-wrapper {
position: relative;
display: inline-block;
}
.flatpickr-months {
display: flex;
.flatpickr-month {
@if variable-exists( "noCalendarBorder" ) {
border-radius: 5px 5px 0 0;
}
background: $monthBackground;
color: $monthForeground;
fill: $monthForeground;
height: $monthNavHeight;
line-height: 1;
text-align: center;
position: relative;
user-select: none;
overflow: hidden;
flex: 1;
}
.flatpickr-prev-month,
.flatpickr-next-month {
text-decoration: none;
cursor: pointer;
position: absolute;
top: 0;
height: $monthNavHeight;
padding: 10px;
z-index: 3;
color: $monthForeground;
fill: $monthForeground;
&.flatpickr-disabled {
display: none;
}
i {
position: relative;
}
&.flatpickr-prev-month {
/*!
/*rtl:begin:ignore*/
/*
*/
left: 0;
/*!
/*rtl:end:ignore*/
/*
*/
}
&.flatpickr-next-month {
/*!
/*rtl:begin:ignore*/
/*
*/
right: 0;
/*!
/*rtl:end:ignore*/
/*
*/
}
&:hover {
color: $todayColor;
svg {
@if variable-exists( "arrow_hover_color" ){
fill: $arrow_hover_color;
}
@else {
fill: $todayColor;
}
}
}
svg {
width: 14px;
height: 14px;
path {
transition: fill 0.1s;
fill: inherit;
}
}
}
}
.numInputWrapper {
position: relative;
height: auto;
input,
span {
display: inline-block;
}
input {
width: 100%;
&::-ms-clear {
display: none;
}
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
margin: 0;
-webkit-appearance: none;
}
}
span {
position: absolute;
right: 0;
width: $timecontrols;
padding: 0 4px 0 2px;
height: 50%;
line-height: 50%;
opacity: 0;
cursor: pointer;
border: 1px solid rgba($dayForeground, 0.15);
box-sizing: border-box;
&:hover {
background: rgba($invertedBg, 0.1);
}
&:active {
background: rgba($invertedBg, 0.2);
}
&:after {
display: block;
content: "";
position: absolute;
}
&.arrowUp {
top: 0;
border-bottom: 0;
&:after {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid rgba($dayForeground, 0.6);
top: 26%;
}
}
&.arrowDown {
top: 50%;
&:after {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid rgba($dayForeground, 0.6);
top: 40%;
}
}
svg {
width: inherit;
height: auto;
path {
fill: rgba($monthForeground, 0.5);
}
}
}
&:hover {
background: rgba($invertedBg, 0.05);
span {
opacity: 1;
}
}
}
.flatpickr-current-month {
font-size: 135%;
line-height: inherit;
font-weight: 300;
color: inherit;
position: absolute;
width: 75%;
left: 12.5%;
padding: 0.22 * $monthNavHeight 0 0 0;
line-height: 1;
height: $monthNavHeight;
display: inline-block;
text-align: center;
transform: translate3d(0px, 0px, 0px);
span.cur-month {
font-family: inherit;
font-weight: 700;
color: inherit;
display: inline-block;
margin-left: 0.5ch;
padding: 0;
&:hover {
background: rgba($invertedBg, 0.05);
}
}
.numInputWrapper {
width: 8ch;
display: inline-block;
span.arrowUp:after {
border-bottom-color: $monthForeground;
}
span.arrowDown:after {
border-top-color: $monthForeground;
}
}
input.cur-year {
background: transparent;
box-sizing: border-box;
color: inherit;
cursor: text;
padding: 0 0 0 0.5ch;
margin: 0;
display: inline-block;
font-size: inherit;
font-family: inherit;
font-weight: 300;
line-height: inherit;
height: auto;
border: 0;
border-radius: 0;
vertical-align: initial;
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
&:focus {
outline: 0;
}
&[disabled],
&[disabled]:hover {
font-size: 100%;
color: rgba($monthForeground, 0.5);
background: transparent;
pointer-events: none;
}
}
.flatpickr-monthDropdown-months {
appearance: none;
background-image: url('data:image/svg+xml;charset=utf8,%3csvg fill="%23000000" fill-opacity="0.54" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"%3e%3cpath d="M7 10l5 5 5-5z"/%3e%3cpath d="M0 0h24v24H0z" fill="none"/%3e%3c/svg%3e');
background-position: 100% 50%;
background-repeat: no-repeat;
background-size: 24px 24px;
border: none;
border-radius: 0;
box-sizing: border-box;
color: inherit;
cursor: pointer;
font-size: 90%;
font-family: inherit;
font-weight: 300;
height: auto;
line-height: 120%;
margin: -1px 0 0 0;
outline: none;
padding: 4px 28px 4px 4px;
position: relative;
vertical-align: initial;
width: auto;
&:focus,
&:active {
outline: none;
}
.flatpickr-monthDropdown-month {
background-color: $monthBackground;
outline: none;
padding: 0;
}
}
}
.flatpickr-weekdays {
background: $weekdaysBackground;
text-align: center;
overflow: hidden;
width: 100%;
display: flex;
align-items: center;
height: $weekdaysHeight;
.flatpickr-weekdaycontainer {
display: flex;
flex: 1;
}
}
span.flatpickr-weekday {
cursor: default;
font-size: 90%;
background: $monthBackground;
color: $weekdaysForeground;
line-height: 1;
margin: 0;
text-align: center;
display: block;
flex: 1;
font-weight: bolder;
}
.dayContainer,
.flatpickr-weeks {
padding: 1px 0 0 0;
}
.flatpickr-days {
position: relative;
overflow: hidden;
display: flex;
align-items: flex-start;
width: $daysWidth;
&:focus {
outline: 0;
}
@if variable-exists( "noCalendarBorder" ) {
border-left: 1px solid $calendarBorderColor;
border-right: 1px solid $calendarBorderColor;
}
}
.dayContainer {
padding: 0;
outline: 0;
text-align: left;
width: $daysWidth;
min-width: $daysWidth;
max-width: $daysWidth;
box-sizing: border-box;
display: inline-block;
display: -ms-flexbox;
display: flex;
flex-wrap: wrap;
-ms-flex-wrap: wrap;
-ms-flex-pack: justify;
justify-content: space-around;
transform: translate3d(0px, 0px, 0px);
opacity: 1;
&+.dayContainer {
box-shadow: -1px 0 0 $calendarBorderColor;
}
}
.flatpickr-day {
background: none;
border: 1px solid transparent;
border-radius: 150px;
box-sizing: border-box;
color: $dayForeground;
cursor: pointer;
font-weight: 400;
width: 14.2857143%;
flex-basis: 14.2857143%;
max-width: $daySize;
height: $daySize;
line-height: $daySize;
margin: 0;
display: inline-block;
position: relative;
justify-content: center;
text-align: center;
&,
&.prevMonthDay,
&.nextMonthDay {
&.inRange,
&.today.inRange,
&:hover,
&:focus {
cursor: pointer;
outline: 0;
background: $dayHoverBackground;
border-color: $dayHoverBackground;
}
}
&.today {
border-color: $todayColor;
&:hover,
&:focus {
border-color: $todayColor;
background: $todayColor;
@if variable-exists( "today_fg_color" ){
color: $today_fg_color;
}
@else {
color: white;
}
}
}
&.selected,
&.startRange,
&.endRange {
&,
&.inRange,
&:focus,
&:hover,
&.prevMonthDay,
&.nextMonthDay {
background: $selectedDayBackground;
box-shadow: none;
@if variable-exists( "selectedDayForeground" ){
color: $selectedDayForeground;
}
@else {
color: white;
}
border-color: $selectedDayBackground;
}
&.startRange {
border-radius: 50px 0 0 50px;
}
&.endRange {
border-radius: 0 50px 50px 0;
}
&.startRange+.endRange:not(:nth-child(7n+1)) {
box-shadow: -5 * $dayMargin 0 0 $selectedDayBackground;
}
&.startRange.endRange {
border-radius: 50px;
}
}
&.inRange {
border-radius: 0;
box-shadow: -2.5 * $dayMargin 0 0 $dayHoverBackground, 2.5 * $dayMargin 0 0 $dayHoverBackground;
}
&.flatpickr-disabled,
&.flatpickr-disabled:hover,
&.prevMonthDay,
&.nextMonthDay,
&.notAllowed,
&.notAllowed.prevMonthDay,
&.notAllowed.nextMonthDay {
color: rgba($dayForeground, 0.3);
background: transparent;
@if variable-exists( "disabled_border_color" ){
border-color: $disabled_border_color;
}
@else {
border-color: transparent;
}
cursor: default;
}
&.flatpickr-disabled,
&.flatpickr-disabled:hover {
cursor: not-allowed;
color: rgba($dayForeground, 0.1);
}
&.week.selected {
border-radius: 0;
box-shadow: -2.5 * $dayMargin 0 0 $selectedDayBackground, 2.5 * $dayMargin 0 0 $selectedDayBackground;
}
&.hidden {
visibility: hidden;
}
}
.rangeMode .flatpickr-day {
margin-top: 1px;
}
.flatpickr-weekwrapper {
float: left;
.flatpickr-weeks {
padding: 0 12px;
@if variable-exists( "noCalendarBorder" ) {
border-left: 1px solid $calendarBorderColor;
}
@else {
box-shadow: 1px 0 0 $calendarBorderColor;
}
}
.flatpickr-weekday {
float: none;
width: 100%;
line-height: $weekdaysHeight;
}
span.flatpickr-day {
&,
&:hover {
display: block;
width: 100%;
max-width: none;
color: rgba($dayForeground, 0.3);
background: transparent;
cursor: default;
border: none;
}
}
}
.flatpickr-innerContainer {
display: block;
display: flex;
box-sizing: border-box;
overflow: hidden;
@if variable-exists( "noCalendarBorder" ) {
background: $calendarBackground;
border-bottom: 1px solid $calendarBorderColor;
}
}
.flatpickr-rContainer {
display: inline-block;
padding: 0;
box-sizing: border-box;
}
.flatpickr-time {
text-align: center;
outline: 0;
display: block;
height: 0;
line-height: $timeHeight;
max-height: $timeHeight;
box-sizing: border-box;
overflow: hidden;
display: flex;
@if variable-exists( "noCalendarBorder" ) {
background: $calendarBackground;
border-radius: 0 0 5px 5px;
}
&:after {
content: "";
display: table;
clear: both;
}
.numInputWrapper {
flex: 1;
width: 40%;
height: $timeHeight;
float: left;
span.arrowUp:after {
border-bottom-color: $dayForeground;
}
span.arrowDown:after {
border-top-color: $dayForeground;
}
}
&.hasSeconds .numInputWrapper {
width: 26%;
}
&.time24hr .numInputWrapper {
width: 49%;
}
input {
background: transparent;
box-shadow: none;
border: 0;
border-radius: 0;
text-align: center;
margin: 0;
padding: 0;
height: inherit;
line-height: inherit;
color: $dayForeground;
font-size: 14px;
position: relative;
box-sizing: border-box;
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
&.flatpickr-hour {
font-weight: bold;
}
&.flatpickr-minute,
&.flatpickr-second {
font-weight: 400;
}
&:focus {
outline: 0;
border: 0;
}
}
.flatpickr-time-separator,
.flatpickr-am-pm {
height: inherit;
float: left;
line-height: inherit;
color: $dayForeground;
font-weight: bold;
width: 2%;
user-select: none;
align-self: center;
}
.flatpickr-am-pm {
outline: 0;
width: 18%;
cursor: pointer;
text-align: center;
font-weight: 400;
}
input,
.flatpickr-am-pm {
&:hover,
&:focus {
background: lighten($dayHoverBackground, 3);
}
}
}
.flatpickr-input {
background-repeat: no-repeat;
background-position: 3px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='#369' class='bi bi-calendar3'%3E%3Cg stroke-width='1.333'%3E%3Cpath d='M10.5 0h-9A1.5 1.5 0 0 0 0 1.5v9A1.5 1.5 0 0 0 1.5 12h9a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 10.5 0zM.75 2.893c0-.355.336-.643.75-.643h9c.414 0 .75.288.75.643v7.714c0 .355-.336.643-.75.643h-9c-.414 0-.75-.288-.75-.643z'/%3E%3Cpath d='M4.875 5.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm2.25 0a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm2.25 0a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zM2.625 7.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm2.25 0a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm2.25 0a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm2.25 0a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm-6.75 2.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm2.25 0a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5zm2.25 0a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5z'/%3E%3C/g%3E%3C/svg%3E");
border-style: inset;
border-width: 1px;
padding: 3px 3px 3px 20px;
&:focus {
border-radius: 0;
}
&[readonly] {
cursor: pointer;
}
}
.flatpickr-day {
border-radius: 0;
}
.flatpickr_wrapper {
white-space: nowrap;
}

View file

@ -0,0 +1,37 @@
$bezier: cubic-bezier(0.23, 1, 0.32, 1);
$slideTime: 400ms;
$daySize: 39px !default;
$padding: $daySize / 16;
$dayMargin: 2px !default;
$daysWidth: $daySize * 7 + $dayMargin * 14 + $padding * 2 + 2;
$calendarWidth: $daysWidth;
$monthNavHeight: 34px !default;
$weekdaysHeight: 28px !default;
$timeHeight: 40px;
$calendarBackground: #ffffff !default;
$calendarBorderColor: #e6e6e6 !default;
$monthForeground: rgba(black, 0.9) !default;
$arrow_hover_color: #f64747 !default;
$monthBackground: transparent !default;
$weekdaysBackground: transparent !default;
$weekdaysForeground: rgba(black, 0.54) !default;
$dayForeground: #000 !default;
$dayHoverBackground: #e6e6e6 !default;
$todayColor: #538200 !default;
$selectedDayBackground: #FFF4C6 !default;
$selectedDayForeground: #000;
$invertedBg: invert($calendarBackground);
$timecontrols: 25px;

View file

@ -77,6 +77,11 @@ a {
padding-left: 1em;
}
&.clear_date {
color: #c33;
font-size: 130%;
}
&.title {
font-size: 108%;
font-weight: bold;

View file

@ -1,98 +1,139 @@
[% USE Asset %]
[% USE Koha %]
[% USE raw %]
<script>
var debug = "[% debug | html %]";
var dformat = "[% dateformat | html %]";
var sentmsg = 0;
if (debug > 1) {alert("dateformat: " + dformat + "\ndebug is on (level " + debug + ")");}
var flatpickr_weekdays = {
shorthand: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
longhand: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]
};
function Date_from_syspref(dstring) {
var dateX = dstring.split(/[-/.]/);
if (debug > 1 && sentmsg < 1) {sentmsg++; alert("Date_from_syspref(" + dstring + ") splits to:\n" + dateX.join("\n"));}
if (dformat === "iso") {
return new Date(dateX[0], (dateX[1] - 1), dateX[2]); // YYYY-MM-DD to (YYYY,m(0-11),d)
} else if (dformat === "us") {
return new Date(dateX[2], (dateX[0] - 1), dateX[1]); // MM/DD/YYYY to (YYYY,m(0-11),d)
} else if (dformat === "metric") {
return new Date(dateX[2], (dateX[1] - 1), dateX[0]); // DD/MM/YYYY to (YYYY,m(0-11),d)
} else if (dformat === "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: " +dformat);}
return 0;
}
var flatpickr_months = {
shorthand: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
longhand: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
};
var debug = "[% debug | html %]";
var dateformat_pref = "[% Koha.Preference('dateformat ') | html %]";
var sentmsg = 0;
if (debug > 1) {alert("dateformat: " + dateformat_pref + "\ndebug is on (level " + debug + ")");}
var calendarFirstDayOfWeek = '[% Koha.Preference('CalendarFirstDayOfWeek') | html %]';
var flatpickr_timeformat_string = [% IF Koha.Preference('TimeFormat') == '12hr' %]"G:i K"[% ELSE %]"H:i"[% END %];
var flatpickr_timeformat = [% IF Koha.Preference('TimeFormat') == '12hr' %]false[% ELSE %]true[% END %];
var dateformat_string = "";
var flatpickr_dateformat_string = "";
switch ( dateformat_pref ){
case "us":
dateformat_string = "mm/dd/yy";
flatpickr_dateformat_string = "m/d/Y";
break;
case "metric":
dateformat_string = "dd/mm/yy";
flatpickr_dateformat_string = "d/m/Y";
break;
case "dmydot":
dateformat_string = "dd.mm.yy";
flatpickr_dateformat_string = "d.m.Y";
break;
default:
dateformat_string = "yy-mm-dd";
flatpickr_dateformat_string = "Y-m-d";
}
</script>
[% Asset.js("lib/flatpickr/flatpickr.min.js") | $raw %]
<script>
flatpickr.l10ns.default.weekdays = flatpickr_weekdays;
flatpickr.l10ns.default.months = flatpickr_months;
flatpickr.setDefaults({
allowInput: true,
dateFormat: flatpickr_dateformat_string,
nextArrow: '<i class="fa fa-fw fa-arrow-right" aria-hidden="true"></i>',
prevArrow: '<i class="fa fa-fw fa-arrow-left" aria-hidden="true"></i>',
time_24hr: flatpickr_timeformat,
locale: {
"firstDayOfWeek": calendarFirstDayOfWeek
},
onReady: function( selectedDates, dateStr, instance ){
/* When flatpickr instance is created, automatically append a "clear date" link */
if( $(instance.input).hasClass("futuredate") ){
instance.set("minDate", new Date().fp_incr(1));
}
if( $(instance.input).hasClass("pastdate") ){
instance.set("maxDate", new Date().fp_incr(-1));
}
$(instance.input)
/* Add a wrapper element so that we can prevent the clear button from wrapping */
.wrap("<span class='flatpickr_wrapper'></span>")
.after( $("<a/>")
.attr("href","#")
.addClass("clear_date")
.on("click", function(e){
e.preventDefault();
instance.clear();
})
.addClass("fa fa-fw fa-remove")
.attr("aria-hidden", true)
.attr("aria-label", _("Clear date") )
).keydown(function(e) {
var key = (event.keyCode ? event.keyCode : event.which);
if ( key == 40 ) {
instance.set('allowInput',false);
}
});
},
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
},
});
var MSG_PLEASE_ENTER_A_VALID_DATE = ( __("Please enter a valid date (should match %s).") );
function is_valid_date(date) {
// An empty string is considered as a valid date for convenient reasons.
if (date === '') return 1;
var dateformat = dateformat_string;
if (dateformat == 'us') {
if (date.search(/^\d{2}\/\d{2}\/\d{4}($|\s)/) == -1) return 0;
dateformat = 'mm/dd/yy';
} else if (dateformat == 'metric') {
if (date.search(/^\d{2}\/\d{2}\/\d{4}($|\s)/) == -1) return 0;
dateformat = 'dd/mm/yy';
} else if (dateformat == 'iso') {
if (date.search(/^\d{4}-\d{2}-\d{2}($|\s)/) == -1) return 0;
dateformat = 'yy-mm-dd';
} else if (dateformat == 'dmydot') {
if (date.search(/^\d{2}\.\d{2}\.\d{4}($|\s)/) == -1) return 0;
dateformat = 'dd.mm.yy';
}
try {
flatpickr.parseDate(date, dateformat);
} catch (e) {
return 0;
}
return 1;
}
/* Instead of including multiple localization files as you would normally see with
jQueryUI we expose the localization strings in the default configuration */
jQuery(function($){
$.datepicker.regional[''] = {
closeText: _("Done"),
prevText: _("Prev"),
nextText: _("Next"),
currentText: _("Today"),
monthNames: [_("January"),_("February"),_("March"),_("April"),_("May"),_("June"),
_("July"),_("August"),_("September"),_("October"),_("November"),_("December")],
monthNamesShort: [_("Jan"), _("Feb"), _("Mar"), _("Apr"), _("May"), _("Jun"),
_("Jul"), _("Aug"), _("Sep"), _("Oct"), _("Nov"), _("Dec")],
dayNames: [_("Sunday"), _("Monday"), _("Tuesday"), _("Wednesday"), _("Thursday"), _("Friday"), _("Saturday")],
dayNamesShort: [_("Sun"), _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat")],
dayNamesMin: [_("Su"),_("Mo"),_("Tu"),_("We"),_("Th"),_("Fr"),_("Sa")],
weekHeader: _("Wk"),
dateFormat: '[% IF ( dateformat == "us" ) %]mm/dd/yy[% ELSIF ( dateformat == "metric" ) %]dd/mm/yy[% ELSIF ( dateformat == "dmydot" ) %]dd.mm.yy[% ELSE %]yy-mm-dd[% END %]',
firstDay: [% Koha.Preference('CalendarFirstDayOfWeek') | html %],
isRTL: [% IF ( bidi ) %]true[% ELSE %]false[% END %],
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['']);
});
function validate_date(dateText, inst) {
if (!is_valid_date(dateText)) {
var dateformat_str = get_dateformat_str( dateformat_pref );
alert(MSG_PLEASE_ENTER_A_VALID_DATE.format(dateformat_str));
inst.clear();
}
}
$(document).ready(function(){
$.datepicker.setDefaults({
showOn: "both",
changeMonth: true,
changeYear: true,
buttonImage: '[% interface | html %]/lib/famfamfam/calendar.png',
buttonImageOnly: true,
showButtonPanel: true,
showOtherMonths: true,
yearRange: "c-100:c+10"
});
$("#borrower_dateofbirth").datepicker({
yearRange: "c-100:c"
});
$( ".datepicker" ).datepicker();
// http://jqueryui.com/demos/datepicker/#date-range
var dates = $( ".datepickerfrom, .datepickerto" ).datepicker({
changeMonth: true,
numberOfMonths: 1,
onSelect: function( selectedDate ) {
var option = this.id == "from" ? "minDate" : "maxDate",
instance = $( this ).data( "datepicker" );
date = $.datepicker.parseDate(
instance.settings.dateFormat ||
$.datepicker._defaults.dateFormat,
selectedDate, instance.settings );
dates.not( this ).datepicker( "option", option, date );
$(".flatpickr").flatpickr();
var startPicker = $(".flatpickrfrom").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
endPicker.set('minDate', selectedDates[0]);
}
});
var endPicker = $(".flatpickrto").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
},
});
});
// jQuery Datepicker - a11y: Map arrow keys
var doKeyDown = $.datepicker._doKeyDown
$.extend($.datepicker, {
_doKeyDown: function(event) {
if (event.which === $.ui.keyCode.LEFT ||
event.which === $.ui.keyCode.RIGHT ||
event.which === $.ui.keyCode.UP ||
event.which === $.ui.keyCode.DOWN) {
event.ctrlKey = true;
doKeyDown(event);
} else {
doKeyDown(event);
}
}
});
</script>

View file

@ -157,7 +157,7 @@
<div class="modal-body">
<input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
<label for="suspend_until_[% HOLD.reserve_id | html %]">Suspend until:</label>
<input type="text" name="suspend_until" id="suspend_until_[% HOLD.reserve_id | html %]" class="suspend-until" size="10" />
<input type="text" name="suspend_until" id="suspend_until_[% HOLD.reserve_id | html %]" class="suspend-until flatpickr futuredate" size="10" />
[% INCLUDE 'date-format.inc' %]
<p class="js-show"><a href="#" onclick="document.getElementById('suspend_until_[% HOLD.reserve_id | html %]').value='';return false;">Clear date to suspend indefinitely</a></p>
<button class="btn btn-primary btn-sm js-hide" type="submit" name="submit">Suspend</button>

View file

@ -139,9 +139,6 @@ $.widget.bridge('uitooltip', $.ui.tooltip);
"[% Asset.url('lib/enquire.min.js') | $raw %]",
"[% Asset.url('js/script.js') | $raw %]",
]);
// Fix for datepicker in a modal
$.fn.modal.Constructor.prototype.enforceFocus = function () {};
</script>
[% IF ( OPACAmazonCoverImages || SyndeticsCoverImages ) %]
<script>

View file

@ -344,13 +344,7 @@
<li>
<label for="borrower_dateofbirth" class="[% required.dateofbirth | html %]">Date of birth:</label>
<input type="text" id="borrower_dateofbirth" name="borrower_dateofbirth" value="[% borrower.dateofbirth | $KohaDates %]" size="10" class="[% required.dateofbirth | html %]" />
[% UNLESS action == 'edit' && !OPACPatronDetails %]
[% UNLESS ( mandatory.defined('dateofbirth') ) %]
<a href="#" style="font-size:85%;text-decoration:none;" class="cleardate">Clear date</a>
[% END %]
[% END %]
<input type="text" id="borrower_dateofbirth" name="borrower_dateofbirth" value="[% borrower.dateofbirth | $KohaDates %]" size="10" class="[% required.dateofbirth | html %] flatpickr pastdate" />
<div class="required_label [% required.dateofbirth | html %]">Required</div>
</li>
@ -1161,11 +1155,6 @@
} );
});
$(".cleardate").on("click", function(){
$('#borrower_dateofbirth').val('');
return false;
});
[% IF action != 'edit' and Koha.Preference('PatronSelfRegistrationConfirmEmail') %]
$("#borrower_email").bind("cut copy paste", function(e){
e.preventDefault();

View file

@ -281,14 +281,14 @@
[% IF ( reserve_in_future ) %]
<li>
<label for="from[% bibitemloo.biblionumber | html %]">Hold starts on date:</label>
<input type="text" name="reserve_date_[% bibitemloo.biblionumber | html %]" id="from[% bibitemloo.biblionumber | html %]" size="10" class="holddatefrom"/>
<input type="text" name="reserve_date_[% bibitemloo.biblionumber | html %]" id="from[% bibitemloo.biblionumber | html %]" size="10" />
<span class="date-format from" data-biblionumber="[% bibitemloo.biblionumber | html %]">[% INCLUDE 'date-format.inc' %]</span>
</li>
[% END %]
<li>
<label for="to[% bibitemloo.biblionumber | html %]">Hold not needed after:</label>
<input type="text" name="expiration_date_[% bibitemloo.biblionumber | html %]" id="to[% bibitemloo.biblionumber | html %]" size="10" class="holddateto" />
<input type="text" name="expiration_date_[% bibitemloo.biblionumber | html %]" id="to[% bibitemloo.biblionumber | html %]" size="10" />
<span class="date-format to" data-biblionumber="[% bibitemloo.biblionumber | html %]">[% INCLUDE 'date-format.inc' %]</span>
</li>
@ -473,7 +473,6 @@
[% BLOCK jsinclude %]
[% INCLUDE 'calendar.inc' %]
<script>
// <![CDATA[
var MSG_NO_ITEM_SELECTED = _("Expecting a specific item selection.");
// Clear the contents of an input field
@ -539,20 +538,6 @@
[% END %]
[% END %]
$(".date-format").each(function(){
if($(this).hasClass("to")){ var op = "to"; }
if($(this).hasClass("from")){ var op = "from"; }
var bibNum = $(this).data("biblionumber");
$(this).html("<a href=\"#\" class=\"clear-date\" data-op=\"" + op + "\" id=\"clear" + bibNum + "\">" + _("Clear date") + "</a>");
});
$(".clear-date").on("click",function(e){
e.preventDefault();
var fieldID = this.id.replace("clear","");
var op = $(this).data("op");
$("#" + op + fieldID).val("");
});
// Replace non-JS single-selection with multi-selection capability.
$(".reserve_mode").val("multi");
$(".confirm_nonjs").remove();
@ -690,25 +675,22 @@
[% FOREACH bibitemloo IN bibitemloop %]
[% IF ( bibitemloo.holdable ) %]
// http://jqueryui.com/demos/datepicker/#date-range
var dates[% bibitemloo.biblionumber | html %] = $( "#from[% bibitemloo.biblionumber | html %], #to[% bibitemloo.biblionumber | html %]" ).datepicker({
minDate: 0,
changeMonth: true,
numberOfMonths: 1,
onSelect: function( selectedDate ) {
var option = this.id == "from[% bibitemloo.biblionumber | html %]" ? "minDate" : "maxDate",
instance = $( this ).data( "datepicker" );
date = $.datepicker.parseDate(
instance.settings.dateFormat ||
$.datepicker._defaults.dateFormat,
selectedDate, instance.settings );
dates[% bibitemloo.biblionumber | html %].not( this ).datepicker( "option", option, date );
var startPicker[% bibitemloo.biblionumber | html %] = $("#from[% bibitemloo.biblionumber | html %]").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
endPicker[% bibitemloo.biblionumber | html %].set('minDate', selectedDates[0]);
}
});
var endPicker[% bibitemloo.biblionumber | html %] = $("#to[% bibitemloo.biblionumber | html %]").flatpickr({
onClose: function( selectedDates, dateText, instance) {
validate_date( selectedDates, instance );
},
});
[% END %]
[% END %]
});
// ]]>
});
</script>
[% END %]

View file

@ -1066,22 +1066,6 @@
[% END %]
$(".suspend-until").datepicker({
beforeShow: function(input, inst) {
// https://stackoverflow.com/questions/662220/how-to-change-the-pop-up-position-of-the-jquery-datepicker-control#answer-10598178
var calendar = inst.dpDiv;
setTimeout(function() {
calendar.position({
my: 'left top',
at: 'left bottom',
collision: 'none',
of: input
});
}, 1);
},
minDate: 1
});
if ( $('#opac-user-clubs').length ) {
$('#opac-user-clubs-tab-link').on('click', function() {
$('#opac-user-clubs').text(_("Loading..."));

View file

@ -448,7 +448,6 @@ body .ui-tooltip {
/* Component containers
----------------------------------*/
.ui-widget {
font-family: Verdana,Arial,sans-serif;
font-size: 1.1em;
}
.ui-widget .ui-widget {
@ -458,7 +457,6 @@ body .ui-tooltip {
.ui-widget select,
.ui-widget textarea,
.ui-widget button {
font-family: Verdana,Arial,sans-serif;
font-size: 1em;
}
.ui-widget.ui-widget-content {

File diff suppressed because one or more lines are too long

View file

@ -448,7 +448,6 @@ body .ui-tooltip {
/* Component containers
----------------------------------*/
.ui-widget {
font-family: Verdana,Arial,sans-serif;
font-size: 1.1em;
}
.ui-widget .ui-widget {
@ -458,7 +457,6 @@ body .ui-tooltip {
.ui-widget select,
.ui-widget textarea,
.ui-widget button {
font-family: Verdana,Arial,sans-serif;
font-size: 1em;
}
.ui-widget.ui-widget-content {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long