mirror of
https://github.com/grocy/grocy.git
synced 2026-04-05 12:26:15 +02:00
335 lines
8.8 KiB
JavaScript
335 lines
8.8 KiB
JavaScript
import { EmptyElementWhenMatches } from '../helpers/extensions'
|
|
import { RefreshContextualTimeago } from '../configs/timeago'
|
|
|
|
class datetimepicker
|
|
{
|
|
constructor(Grocy, scopeSelector = null, basename = "datetimepicker")
|
|
{
|
|
this.Grocy = Grocy;
|
|
|
|
this.scopeSelector = scopeSelector;
|
|
this.scope = scopeSelector != null ? $(scopeSelector) : $(document);
|
|
var jScope = this.scope;
|
|
this.$ = scopeSelector != null ? (selector) => jScope.find(selector) : $;
|
|
|
|
this.basename = basename;
|
|
|
|
var inputElement = this.GetInputElement();
|
|
var self = this;
|
|
|
|
|
|
this.startDate = null;
|
|
if (inputElement.data('init-with-now') === true)
|
|
{
|
|
this.startDate = moment().format(inputElement.data('format'));
|
|
}
|
|
if (inputElement.data('init-value').length > 0)
|
|
{
|
|
this.startDate = moment(inputElement.data('init-value')).format(inputElement.data('format'));
|
|
}
|
|
|
|
this.limitDate = moment('2999-12-31 23:59:59');
|
|
if (inputElement.data('limit-end-to-now') === true)
|
|
{
|
|
this.limitDate = moment();
|
|
}
|
|
|
|
// set some event handlers
|
|
inputElement.on('keyup', (e) => self.keyupHandler(this, e));
|
|
inputElement.on('input', (e) => self.inputHandler(this, e));
|
|
|
|
this.$('.' + this.basename).on('update.datetimepicker', () => self.stateTrigger());
|
|
this.$('.' + this.basename).on('hide.datetimepicker', () => self.stateTrigger());
|
|
|
|
this.$("#" + this.basename + "-shortcut").on("click", () => self.handleShortcut(this));
|
|
|
|
this.Init()
|
|
}
|
|
|
|
GetInputElement()
|
|
{
|
|
return this.$('.' + this.basename).find('input').not(".form-check-input");
|
|
}
|
|
|
|
GetValue()
|
|
{
|
|
return this.GetInputElement().val();
|
|
}
|
|
|
|
SetValue(value, triggerEvents = true)
|
|
{
|
|
// "Click" the shortcut checkbox when the desired value is
|
|
// not the shortcut value and it is currently set
|
|
var shortcutValue = this.$("#" + this.basename + "-shortcut").data(this.basename + "-shortcut-value");
|
|
if (value != shortcutValue && this.$("#" + this.basename + "-shortcut").is(":checked"))
|
|
{
|
|
this.$("#" + this.basename + "-shortcut").click();
|
|
}
|
|
|
|
var inputElement = this.GetInputElement();
|
|
inputElement.val(value);
|
|
if (triggerEvents)
|
|
{
|
|
inputElement.trigger('change');
|
|
|
|
inputElement.keyup();
|
|
}
|
|
}
|
|
|
|
Clear()
|
|
{
|
|
this.$("." + this.basename).datetimepicker("destroy");
|
|
this.Init();
|
|
this.SetValue("", false);
|
|
|
|
this.$('#' + this.basename + '-timeago').text('');
|
|
}
|
|
|
|
ChangeFormat(format)
|
|
{
|
|
this.$("." + this.basename).datetimepicker("destroy");
|
|
var elem = this.GetInputElement();
|
|
elem.data("format", format);
|
|
this.Init();
|
|
|
|
if (format == "YYYY-MM-DD")
|
|
{
|
|
elem.addClass("date-only-datetimepicker");
|
|
}
|
|
else
|
|
{
|
|
elem.removeClass("date-only-datetimepicker");
|
|
}
|
|
}
|
|
|
|
Init()
|
|
{
|
|
this.$('.' + this.basename).datetimepicker(
|
|
{
|
|
format: this.GetInputElement().data('format'),
|
|
buttons: {
|
|
showToday: true,
|
|
showClose: true
|
|
},
|
|
calendarWeeks: this.Grocy.CalendarShowWeekNumbers,
|
|
maxDate: this.limitDate,
|
|
locale: moment.locale(),
|
|
defaultDate: this.startDate,
|
|
useCurrent: false,
|
|
icons: {
|
|
time: 'far fa-clock',
|
|
date: 'far fa-calendar',
|
|
up: 'fas fa-arrow-up',
|
|
down: 'fas fa-arrow-down',
|
|
previous: 'fas fa-chevron-left',
|
|
next: 'fas fa-chevron-right',
|
|
today: 'fas fa-calendar-check',
|
|
clear: 'far fa-trash-alt',
|
|
close: 'far fa-times-circle'
|
|
},
|
|
sideBySide: true,
|
|
keyBinds: {
|
|
up: function(widget) { },
|
|
down: function(widget) { },
|
|
'control up': function(widget) { },
|
|
'control down': function(widget) { },
|
|
left: function(widget) { },
|
|
right: function(widget) { },
|
|
pageUp: function(widget) { },
|
|
pageDown: function(widget) { },
|
|
enter: function(widget) { },
|
|
escape: function(widget) { },
|
|
'control space': function(widget) { },
|
|
t: function(widget) { },
|
|
'delete': function(widget) { }
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
keyupHandler(_this, e)
|
|
{
|
|
this.$('.' + this.basename).datetimepicker('hide');
|
|
|
|
var inputElement = this.GetInputElement();
|
|
|
|
var value = this.GetValue();
|
|
var now = new Date();
|
|
var centuryStart = Number.parseInt(now.getFullYear().toString().substring(0, 2) + '00');
|
|
var centuryEnd = Number.parseInt(now.getFullYear().toString().substring(0, 2) + '99');
|
|
var format = inputElement.data('format');
|
|
var nextInputElement = this.$(inputElement.data('next-input-selector'));
|
|
|
|
//If input is empty and any arrow key is pressed, set date to today
|
|
if (value.length === 0 && (e.keyCode === 38 || e.keyCode === 40 || e.keyCode === 37 || e.keyCode === 39))
|
|
{
|
|
this.SetValue(moment(new Date(), format, true).format(format));
|
|
nextInputElement.focus();
|
|
}
|
|
else if (value === 'x' || value === 'X')
|
|
{
|
|
this.SetValue(moment('2999-12-31 23:59:59').format(format));
|
|
nextInputElement.focus();
|
|
}
|
|
else if (value.length === 4 && !(Number.parseInt(value) > centuryStart && Number.parseInt(value) < centuryEnd))
|
|
{
|
|
var date = moment((new Date()).getFullYear().toString() + value);
|
|
if (date.isBefore(moment()))
|
|
{
|
|
date.add(1, "year");
|
|
}
|
|
this.SetValue(date.format(format));
|
|
nextInputElement.focus();
|
|
}
|
|
else if (value.length === 8 && $.isNumeric(value))
|
|
{
|
|
this.SetValue(value.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3'));
|
|
nextInputElement.focus();
|
|
}
|
|
else if (value.length === 7 && $.isNumeric(value.substring(0, 6)) && (value.substring(6, 7).toLowerCase() === "e" || value.substring(6, 7).toLowerCase() === "+"))
|
|
{
|
|
var endOfMonth = moment(value.substring(0, 4) + "-" + value.substring(4, 6) + "-01").endOf("month");
|
|
this.SetValue(endOfMonth.format(format));
|
|
nextInputElement.focus();
|
|
}
|
|
else
|
|
{
|
|
var dateObj = moment(value, format, true);
|
|
if (dateObj.isValid())
|
|
{
|
|
if (e.shiftKey)
|
|
{
|
|
// WITH shift modifier key
|
|
|
|
if (e.keyCode === 38) // Up
|
|
{
|
|
this.SetValue(dateObj.add(-1, 'months').format(format));
|
|
}
|
|
else if (e.keyCode === 40) // Down
|
|
{
|
|
this.SetValue(dateObj.add(1, 'months').format(format));
|
|
}
|
|
else if (e.keyCode === 37) // Left
|
|
{
|
|
this.SetValue(dateObj.add(-1, 'years').format(format));
|
|
}
|
|
else if (e.keyCode === 39) // Right
|
|
{
|
|
this.SetValue(dateObj.add(1, 'years').format(format));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// WITHOUT shift modifier key
|
|
|
|
if (e.keyCode === 38) // Up
|
|
{
|
|
this.SetValue(dateObj.add(-1, 'days').format(format));
|
|
}
|
|
else if (e.keyCode === 40) // Down
|
|
{
|
|
this.SetValue(dateObj.add(1, 'days').format(format));
|
|
}
|
|
else if (e.keyCode === 37) // Left
|
|
{
|
|
this.SetValue(dateObj.add(-1, 'weeks').format(format));
|
|
}
|
|
else if (e.keyCode === 39) // Right
|
|
{
|
|
this.SetValue(dateObj.add(1, 'weeks').format(format));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Custom validation
|
|
value = this.GetValue();
|
|
dateObj = moment(value, format, true);
|
|
var element = inputElement[0];
|
|
if (!dateObj.isValid())
|
|
{
|
|
if (inputElement.hasAttr("required"))
|
|
{
|
|
element.setCustomValidity("error");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (inputElement.data('limit-end-to-now') === true && dateObj.isAfter(moment()))
|
|
{
|
|
element.setCustomValidity("error");
|
|
}
|
|
else if (inputElement.data('limit-start-to-now') === true && dateObj.isBefore(moment()))
|
|
{
|
|
element.setCustomValidity("error");
|
|
}
|
|
else
|
|
{
|
|
element.setCustomValidity("");
|
|
}
|
|
|
|
var earlierThanLimit = inputElement.data("earlier-than-limit");
|
|
if (!earlierThanLimit.isEmpty())
|
|
{
|
|
if (moment(value).isBefore(moment(earlierThanLimit)))
|
|
{
|
|
this.$("#" + this.basename + "-earlier-than-info").removeClass("d-none");
|
|
}
|
|
else
|
|
{
|
|
this.$("#" + this.basename + "-earlier-than-info").addClass("d-none");
|
|
}
|
|
}
|
|
}
|
|
|
|
// "Click" the shortcut checkbox when the shortcut value was
|
|
// entered manually and it is currently not set
|
|
var shortcutValue = this.$("#" + this.basename + "-shortcut").data(this.basename + "-shortcut-value");
|
|
if (value == shortcutValue && !this.$("#" + this.basename + "-shortcut").is(":checked"))
|
|
{
|
|
this.$("#" + this.basename + "-shortcut").click();
|
|
}
|
|
}
|
|
|
|
inputHandler(_this, e)
|
|
{
|
|
this.$('#' + this.basename + '-timeago').attr("datetime", this.GetValue());
|
|
EmptyElementWhenMatches(this.$('#' + this.basename + '-timeago'), this.Grocy.translate('timeago_nan'));
|
|
|
|
// TODO: scoping
|
|
RefreshContextualTimeago("#" + this.basename + "-wrapper");
|
|
}
|
|
|
|
stateTrigger()
|
|
{
|
|
var linputElement = this.GetInputElement();
|
|
linputElement.trigger('input')
|
|
.trigger('change')
|
|
.trigger('keypress')
|
|
.trigger('keyup');
|
|
}
|
|
|
|
handleShortcut(_this)
|
|
{
|
|
{
|
|
var linputElement = this.GetInputElement();
|
|
if (_this.checked)
|
|
{
|
|
var value = this.$("#" + this.basename + "-shortcut").data(this.basename + "-shortcut-value");
|
|
this.SetValue(value);
|
|
this.GetInputElement().attr("readonly", "");
|
|
this.$(linputElement.data('next-input-selector')).focus();
|
|
}
|
|
else
|
|
{
|
|
this.SetValue("");
|
|
linputElement.removeAttr("readonly");
|
|
linputElement.focus();
|
|
}
|
|
|
|
this.stateTrigger();
|
|
}
|
|
}
|
|
}
|
|
|
|
export { datetimepicker } |