var pickmeup;
var activePickmeup = null;
$(document).ready(InitDateTimePickers);
//Заглушка для совместимости
function InitDateTimePickers() {
DateTimePickerInitializer.init();
}
class DateTimePickerInitializer {
public static readonly defaultDateFormat = "d.m.Y";
public static readonly attrStartItem = "data-start-item-selector";
public static readonly attrEndItem = "data-end-item-selector";
public static readonly attrIsPaired = "data-date-is-paired";
static readonly CalendarLocales = {
days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
daysShort: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
daysMin: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
monthsShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек']
};
static initPickMeUpFlag = "pick-me-up-inited";
public static init() {
$('.custom-date-time input').each((i, item) => {
DateTimePickerInitializer.initElement(item);
});
}
public static initElement(dateTimeElement: HTMLElement) {
DateTimePickerInitializer.InitInput(dateTimeElement);
let label = $(dateTimeElement).closest(".custom-date-time").find("label").get(0);
DateTimePickerInitializer.initLabel(label);
}
public static InitInput(dateTimeInput: HTMLElement) {
var $this = $(dateTimeInput);
if ($this.attr("disabled") === "disabled") {
// return;
}
var dateFormat = $this.data("pmu-format");
let ageLimit: number = $this.data("age-limit");
let maxDate = $this.data("pmu-max");
let minDate = $this.data("pmu-min");
//инициализация обёртки
DateTimePickerInitializer.initPickMeUp($this, dateFormat);
// валидация и синхронность ограничений мин-макс для 2 связанных инпутов(начало события и конец).
if ($this.attr(DateTimePickerInitializer.attrStartItem) &&
$this.attr(DateTimePickerInitializer.attrStartItem).indexOf("$index") > 0 ||
$this.attr(DateTimePickerInitializer.attrEndItem) &&
$this.attr(DateTimePickerInitializer.attrEndItem).indexOf("$index") > 0 ||
$this.attr(DateTimePickerInitializer.attrIsPaired)) {
//задержка для отработки ангуляра
setTimeout(() => { DateInputValidation.initValidation($this, dateFormat); }, 1100);
} else {
DateInputValidation.initValidation($this, dateFormat);
}
// для ограничения выбора дат в календаре
setTimeout(() => DateTimePickerInitializer.initMinMaxDates($this), 900);
if (ageLimit) {
DateTimePickerInitializer.initByAgeLimit($this, ageLimit);
}
}
public static initByAgeLimit(input, ageLimit) {
let limitDate = new Date();
limitDate.setFullYear(limitDate.getFullYear() - ageLimit);
$(input).attr("data-pmu-max", limitDate.toLocaleDateString());
input[0].__pickmeup.options.max = limitDate;
pickmeup(input[0]).update();
pickmeup(input[0]).hide();
}
public static initMinMaxDates(input) {
let max = ConvertStringToDate($(input).attr("data-pmu-max"));
let min = ConvertStringToDate($(input).attr("data-pmu-min"));
let domInput = input[0];
$(input).attr("data-pmu-min", $(input).attr("data-pmu-min"));
domInput.__pickmeup.options.min = min;
$(input).attr("data-pmu-max", $(input).attr("data-pmu-max"));
domInput.__pickmeup.options.max = max;
pickmeup(domInput).update();
pickmeup(domInput).hide();
}
/**
* Инициализирует обёртку PickMeUp для инпута
* @param element
*/
public static initPickMeUp(element: JQuery, dateFormat?: string) {
if (element.data(this.initPickMeUpFlag)) {
return;
}
// пометить инициализированным, чтобы не проинициализировать повторно
element.data(this.initPickMeUpFlag, "true");
pickmeup.defaults.locales['ru'] = this.CalendarLocales;
var selectDay = element.data("pmu-select-day");
var selectMonth = element.data("pmu-select-month");
// конвертирование в boolean
selectDay = (selectDay.toLowerCase() == "true");
selectMonth = (selectMonth.toLowerCase() == "true");
if (!dateFormat) {
dateFormat = this.defaultDateFormat;
}
// получение DOM-элемента для pickmeup
var input = element[0];
pickmeup(input,
{
locale: 'ru',
default_date: false,
format: dateFormat,
select_day: selectDay,
select_month: selectMonth,
hide_on_select: true,
prev: '',
next: '',
});
input.addEventListener('pickmeup-show', function (e) {
if (activePickmeup) {
activePickmeup.hide();
}
activePickmeup = pickmeup(e.target);
});
input.addEventListener('pickmeup-hide', function (e) {
activePickmeup = null;
});
input.addEventListener('pickmeup-change', function (e) {
// триггер события изменения значения инпута
var element = e.target;
var event = new Event("change");
element.dispatchEvent(event);
});
input.addEventListener('focusout', function (e) {
var element = e.target;
var event = new Event("change");
element.dispatchEvent(event);
});
}
public static initLabel(label: HTMLElement) {
$(label).click(event => {
let datePicker = $(event.target).closest(".custom-date-time").find("input");
datePicker.show();
});
}
};
class DateInputValidation {
static initValidationFlag = "validation-inited";
private dateMinAbsolute: Date;
private dateMaxAbsolute: Date;
private constructor(public itemStart: JQuery, public itemEnd?: JQuery, public dateFormat = DateTimePickerInitializer.defaultDateFormat) {
//Если уже была инициализация - выход
if (itemStart && itemStart.data(DateInputValidation.initValidationFlag) ||
itemEnd && itemEnd.data(DateInputValidation.initValidationFlag)) {
return;
}
this.dateMinAbsolute = ConvertStringToDate(itemStart.attr("data-pmu-min")) || new Date(1940, 1, 1);
this.dateMaxAbsolute = ConvertStringToDate(itemStart.attr("data-pmu-max")) || new Date(2040, 1, 1);
this.initStartItem();
if (this.itemEnd) {
//Максимальное значение абсолютной даты, из начального инпута и второго.
let dateEndItem = ConvertStringToDate(itemEnd.attr("data-pmu-max"));
if (dateEndItem) {
this.dateMaxAbsolute = new Date(Math.max(dateEndItem.getTime(), this.dateMaxAbsolute.getTime()));
}
this.initEndItem();
}
}
/**
* Инициализирует маску ввода дат. Т.е только символы в формате маски
* @param input
*/
public static initInputMask(input: JQuery, dateFormat: string) {
let mask = dateFormat == DateTimePickerInitializer.defaultDateFormat ? "99.99.9999" : "9999";
let placeholder = dateFormat == DateTimePickerInitializer.defaultDateFormat ? "дд.мм.гггг" : "гггг";
(input as any).inputmask({
"alias": "date",
"mask": mask,
"placeholder": placeholder,
"autoGroup": "true"
});
}
/**
* Инициализирует валидацию инпутов(инпута) даты.
* @param input
*/
public static initValidation(input: JQuery, dateFormat: string) {
if (input.data(this.initValidationFlag)) {
return;
}
//Обнуляем начало и конец, т.к не знаем он начало или конец
var itemStart = input;
var itemEnd = null;
let startDateSelector = input.attr(DateTimePickerInitializer.attrStartItem);
let endDateSelector = input.attr(DateTimePickerInitializer.attrEndItem);
//А здесь нужный (начало или конец) записывает по селектору, а его брат - текущий
if (startDateSelector) {
itemStart = $(startDateSelector);
itemEnd = input;
}
if (endDateSelector) {
itemEnd = $(endDateSelector);
itemStart = input;
}
//Поиск спаренного инпута в кастомной части
//Там нельзя использовать startDateSelector, endDateSelector.
//Возможно стоит избавится от startDateSelector, endDateSelector.
//Дляэ того нужен одинаковый контейнер для датных инпутов
if (input.attr(DateTimePickerInitializer.attrIsPaired) == "True") {
let parent = input.parents(".row-group");
let inputs = parent.find(".date-time-input.custom[" + DateTimePickerInitializer.attrIsPaired + "=True]");
if (inputs && inputs.length == 2 && inputs.is(input)) {
itemStart = $(inputs[0]) as any;
itemEnd = $(inputs[1]);
}
}
if (itemEnd) {
//инициализация обёртки
DateTimePickerInitializer.initPickMeUp(itemEnd);
}
new DateInputValidation(itemStart, itemEnd, dateFormat);
}
//Инит стартовый инпут, либо единственный, если нет пары
private initStartItem() {
this.itemStart.data(DateInputValidation.initValidationFlag, "true");
DateInputValidation.initInputMask(this.itemStart, this.dateFormat);
this.itemStart.on("change", (event) => {
var newStartDateVal = this.itemStart.val() as string;
var newStartDate = ConvertStringToDate(newStartDateVal);
//Дата из спаренного инпута макс даты
var endDate = this.itemEnd ? ConvertStringToDate(this.itemEnd.val() as string) : null;
//Введено значение, но оно не Дата
if (newStartDate == null && newStartDateVal) {
this.itemStart.val(this.dateToStringFormat(new Date()));
event.stopImmediatePropagation();
}
//Раньше, чем глобальный минимум(обычно даты конкурсов)
if (newStartDate < this.dateMinAbsolute && this.dateMinAbsolute) {
let dateStr = this.dateToStringFormat(this.dateMinAbsolute);
this.itemStart.val(dateStr);
MessageShower.showError("Нельзя установить дату, раньше чем " + dateStr + " !");
event.stopImmediatePropagation();
return false;
}
//Если больше чем дата в спаренном инпуте
if (newStartDate > endDate && endDate) {
let dateStr = this.dateToStringFormat(endDate);
this.itemStart.val(dateStr);
MessageShower.showError("Нельзя установить дату, позже чем " + dateStr + " !");
event.stopImmediatePropagation();
return;
}
//Если больше глобального максимума
if (newStartDate > this.dateMaxAbsolute && this.dateMaxAbsolute) {
let dateStr = this.dateToStringFormat(this.dateMaxAbsolute);
this.itemStart.val(dateStr);
MessageShower.showError("Нельзя установить дату, позже чем " + dateStr + " !");
event.stopImmediatePropagation();
return;
}
let element = event.currentTarget;
element.dispatchEvent(new Event('pickmeup-force-update'));
});
this.itemStart.on("set-date-limits", (event, minDate, maxDate) => {
this.dateMaxAbsolute = ConvertStringToDate(maxDate);
this.dateMinAbsolute = ConvertStringToDate(minDate);
DateInputValidation.setDateMin($(event.target), minDate);
DateInputValidation.setDateMax($(event.target), maxDate);
});
}
private validateInputChars(event) {
var theEvent = event || window.event;
// Handle paste
if (theEvent.type === 'paste') {
key = event.clipboardData.getData('text/plain');
} else {
// Handle key press
var key = theEvent.keyCode || theEvent.which;
key = String.fromCharCode(key);
}
var regex = /[0-9]|\./;
if (!regex.test(key)) {
theEvent.returnValue = false;
if (theEvent.preventDefault) theEvent.preventDefault();
}
}
//Инит парный второй макс дата инпут
private initEndItem() {
this.itemEnd.data(DateInputValidation.initValidationFlag, "true");
DateInputValidation.initInputMask(this.itemEnd, this.dateFormat);
this.itemEnd.on("change", (event) => {
var newEndDateVal = this.itemEnd.val() as string;
var newEndDate = ConvertStringToDate(newEndDateVal);
var startDate = this.itemStart ? ConvertStringToDate(this.itemStart.val() as string) : null;
//Введено значение, но оно не Дата
if (newEndDate == null && newEndDateVal) {
this.itemEnd.val(this.dateToStringFormat(new Date()));
event.stopImmediatePropagation();
}
if (newEndDate > this.dateMaxAbsolute && this.dateMaxAbsolute) {
let dateStr = this.dateToStringFormat(this.dateMaxAbsolute);
this.itemEnd.val(dateStr);
MessageShower.showError("Нельзя установить дату, позже чем " + dateStr + " !");
event.stopImmediatePropagation();
return;
}
if (newEndDate < startDate && startDate) {
let dateStr = this.dateToStringFormat(startDate);
this.itemEnd.val(dateStr);
MessageShower.showError("Нельзя установить дату, раньше чем " + dateStr + " !");
event.stopImmediatePropagation();
return;
}
if (newEndDate < this.dateMinAbsolute && this.dateMinAbsolute) {
let dateStr = this.dateToStringFormat(this.dateMinAbsolute);
this.itemEnd.val(dateStr);
MessageShower.showError("Нельзя установить дату, раньше чем " + dateStr + " !");
event.stopImmediatePropagation();
return;
}
});
this.itemEnd.on("set-date-limits", (event, minDate, maxDate) => {
this.dateMaxAbsolute = ConvertStringToDate(maxDate);
this.dateMinAbsolute = ConvertStringToDate(minDate);
DateInputValidation.setDateMin($(event.target), minDate);
DateInputValidation.setDateMax($(event.target), maxDate);
});
}
/**
* Переводит дату в нужном формате инпута (ДД.ММ.ГОД или ГОД)
* @param date
*/
private dateToStringFormat(date: Date): string {
if (this.dateFormat === DateTimePickerInitializer.defaultDateFormat) {
return (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + "." +
((date.getMonth() + 1) < 10 ? "0" + (date.getMonth() + 1) : (date.getMonth() + 1)) + "." +
date.getFullYear();
}
else {
return date.getFullYear().toString();
}
}
/**
* задать новое минимальное значение на основе даты окончания
* @param item Элемент
* @param newStartDateVal Новая дата
*/
public static setDateMin(item: JQuery, newStartDateVal: string) {
let pureItem = (item[0] as any);
item.attr("data-pmu-min", newStartDateVal);
pureItem.__pickmeup.options.min = newStartDateVal;
pickmeup(pureItem).update();
pickmeup(pureItem).hide();
}
/**
* задать новое максимальное значение на основе даты окончания
* @param item Элемент
* @param newEndDateVal Новая дата
*/
public static setDateMax(item: JQuery, newEndDateVal: string) {
let pureItem = (item[0] as any);
item.attr("data-pmu-max", newEndDateVal);
pureItem.__pickmeup.options.max = newEndDateVal;
pickmeup(pureItem).update();
pickmeup(pureItem).hide();
}
}