Enhance datepicker UX: position above input with proper styling

- Added CSS positioning to display inline datepicker above input field
- Enhanced datepicker styling with background, border and shadow
- Improved template with datepicker-above class for better positioning
- Maintains Bootstrap 5 compatibility and inline mode functionality

This provides a better user experience by preventing the datepicker
from appearing below and potentially being cut off by page boundaries.
This commit is contained in:
Micha
2025-07-26 15:33:02 +02:00
parent f4dc8a3dd0
commit 3eacb7c438
20 changed files with 531 additions and 67 deletions

View File

@@ -151,3 +151,17 @@
.editable-pre-wrapped {
white-space: pre-wrap;
}
/* Position datepicker above input for datepicker-above class */
.datepicker-above .datepicker-inline {
position: absolute;
bottom: 100%;
left: 0;
right: 0;
z-index: 1000;
margin-bottom: 5px;
background: white;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}

View File

@@ -14,18 +14,37 @@ Automatically shown in inline mode.
var DateField = function (options) {
this.init('datefield', options, DateField.defaults);
this.initPicker(options, DateField.defaults);
// Ensure type is set correctly
this.type = 'datefield';
};
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
$.extend(DateField.prototype, {
render: function () {
console.log("DateField.render() called");
this.$input = this.$tpl.find('input');
this.setClass();
this.setAttr('placeholder');
//bootstrap-datepicker is set `bdateicker` to exclude conflict with jQuery UI one. (in date.js)
this.$tpl.bdatepicker(this.options.datepicker);
console.log("DateField initializing datepicker on container:", this.$tpl[0]);
console.log("DateField datepicker options:", this.options.datepicker);
//use datepicker instead of bdatepicker
this.$tpl.datepicker(this.options.datepicker);
console.log("DateField datepicker initialized, data:", this.$tpl.data('datepicker'));
// Add event listeners to track date changes
this.$tpl.on('changeDate', $.proxy(function(e) {
console.log("DateField changeDate event triggered:", e.date);
}, this));
this.$tpl.on('hide', $.proxy(function(e) {
console.log("DateField datepicker hide event triggered");
console.log("DateField datepicker data on hide:", this.$tpl.data('datepicker'));
}, this));
//need to disable original event handlers
this.$input.off('focus keydown');
@@ -33,17 +52,60 @@ Automatically shown in inline mode.
//update value of datepicker
this.$input.keyup($.proxy(function(){
this.$tpl.removeData('date');
this.$tpl.bdatepicker('update');
this.$tpl.datepicker('update');
}, this));
},
value2input: function(value) {
this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '');
this.$tpl.bdatepicker('update');
console.log("DateField.value2input() called with value:", value);
var formattedValue = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
console.log("DateField formatted value for input:", formattedValue);
this.$input.val(formattedValue);
this.$tpl.datepicker('update');
console.log("DateField after update, datepicker data:", this.$tpl.data('datepicker'));
},
input2value: function() {
console.log("DateField.input2value() called");
// First try the container datepicker (ideal case)
var containerDatepicker = this.$tpl.data('datepicker');
console.log("DateField container datepicker object:", containerDatepicker);
if (containerDatepicker && containerDatepicker.dates && containerDatepicker.dates.length > 0) {
console.log("DateField returning from container dates array:", containerDatepicker.dates[0]);
return containerDatepicker.dates[0];
}
// Fallback: try the input datepicker (in case manual init worked)
var inputDatepicker = this.$input.data('datepicker');
console.log("DateField input datepicker object:", inputDatepicker);
if (inputDatepicker && inputDatepicker.dates && inputDatepicker.dates.length > 0) {
console.log("DateField returning from input dates array:", inputDatepicker.dates[0]);
return inputDatepicker.dates[0];
}
// Try getDate methods
if (containerDatepicker && typeof containerDatepicker.getDate === 'function') {
var containerDate = containerDatepicker.getDate();
if (containerDate) {
console.log("DateField returning from container getDate():", containerDate);
return containerDate;
}
}
if (inputDatepicker && typeof inputDatepicker.getDate === 'function') {
var inputDate = inputDatepicker.getDate();
if (inputDate) {
console.log("DateField returning from input getDate():", inputDate);
return inputDate;
}
}
// Final fallback to text parsing
console.log("DateField fallback to text input value:", this.$input.val());
return this.html2value(this.$input.val());
},
@@ -60,19 +122,21 @@ Automatically shown in inline mode.
/**
@property tpl
**/
tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
tpl:'<div class="input-group input-group-sm date datepicker-above" style="width: 200px; border: 1px solid #dee2e6; border-radius: 0.375rem; position: relative;"><input type="text" class="form-control form-control-sm" style="border: none;"/><span class="input-group-text" style="border: none; background: transparent;"><i class="bi bi-calendar"></i></span></div>',
/**
@property inputclass
@default 'input-small'
@default 'form-control form-control-sm'
**/
inputclass: 'input-small',
inputclass: 'form-control form-control-sm',
/* datepicker config */
datepicker: {
weekStart: 0,
startView: 0,
minViewMode: 0,
autoclose: true
autoclose: true,
orientation: 'top',
container: 'body'
}
});