Telegram Web K with changes to work inside I2P https://web.telegram.i2p/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
10 KiB

import PopupElement, { PopupOptions } from ".";
import { getFullDate, months } from "../../helpers/date";
import InputField from "../inputField";
export default class PopupDatePicker extends PopupElement {
protected controlsDiv: HTMLElement;
protected monthTitle: HTMLElement;
protected prevBtn: HTMLElement;
protected nextBtn: HTMLElement;
protected monthsContainer: HTMLElement;
protected month: HTMLElement;
protected minMonth: Date;
protected maxMonth: Date;
protected minDate: Date;
protected maxDate: Date;
protected selectedDate: Date;
protected selectedMonth: Date;
protected selectedEl: HTMLElement;
protected timeDiv: HTMLDivElement;
protected hoursInputField: InputField;
protected minutesInputField: InputField;
constructor(initDate: Date, public onPick: (timestamp: number) => void, protected options: Partial<{
noButtons: true,
noTitle: true,
minDate: Date,
maxDate: Date
withTime: true,
showOverflowMonths: true
}> & PopupOptions = {}) {
super('popup-date-picker', options.noButtons ? [] : [{
text: 'CANCEL',
isCancel: true
}, {
text: 'JUMP TO DATE',
callback: () => {
if(this.onPick) {
this.onPick(this.selectedDate.getTime() / 1000 | 0);
}
}
}], {body: true, ...options});
this.minDate = options.minDate || new Date('2013-08-01T00:00:00');
// Controls
this.controlsDiv = document.createElement('div');
this.controlsDiv.classList.add('date-picker-controls');
this.prevBtn = document.createElement('button');
this.prevBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-prev');
this.prevBtn.addEventListener('click', this.onPrevClick);
this.nextBtn = document.createElement('button');
this.nextBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-next');
this.nextBtn.addEventListener('click', this.onNextClick);
this.monthTitle = document.createElement('div');
this.monthTitle.classList.add('date-picker-month-title');
this.controlsDiv.append(this.prevBtn, this.monthTitle, this.nextBtn);
// Month
this.monthsContainer = document.createElement('div');
this.monthsContainer.classList.add('date-picker-months');
this.monthsContainer.addEventListener('click', this.onDateClick);
this.body.append(this.controlsDiv, this.monthsContainer);
// Time inputs
if(options.withTime) {
this.timeDiv = document.createElement('div');
this.timeDiv.classList.add('date-picker-time');
const delimiter = document.createElement('div');
delimiter.classList.add('date-picker-time-delimiter');
delimiter.append(':');
const handleTimeInput = (max: number, inputField: InputField, onInput: (length: number) => void, onOverflow?: (number: number) => void) => {
const maxString = '' + max;
inputField.input.addEventListener('input', (e) => {
let value = inputField.value.replace(/\D/g, '');
if(value.length > 2) {
value = value.slice(0, 2);
} else {
if((value.length === 1 && +value[0] > +maxString[0]) || (value.length === 2 && +value > max)) {
if(value.length === 2 && onOverflow) {
onOverflow(+value[1]);
}
value = '0' + value[0];
}
}
inputField.setValueSilently(value);
onInput(value.length);
});
};
this.hoursInputField = new InputField({plainText: true});
this.minutesInputField = new InputField({plainText: true});
handleTimeInput(23, this.hoursInputField, (length) => {
if(length === 2) {
this.minutesInputField.input.focus();
}
this.setTimeTitle();
}, (number) => {
this.minutesInputField.value = (number + this.minutesInputField.value).slice(0, 2);
});
handleTimeInput(59, this.minutesInputField, (length) => {
if(!length) {
this.hoursInputField.input.focus();
}
this.setTimeTitle();
});
this.selectedDate = initDate;
initDate.setMinutes(initDate.getMinutes() + 10);
this.hoursInputField.setValueSilently(('0' + initDate.getHours()).slice(-2));
this.minutesInputField.setValueSilently(('0' + initDate.getMinutes()).slice(-2));
initDate.setHours(0, 0, 0, 0);
this.timeDiv.append(this.hoursInputField.container, delimiter, this.minutesInputField.container);
this.btnConfirm.addEventListener('click', () => {
if(this.onPick) {
this.selectedDate.setHours(+this.hoursInputField.value || 0, +this.minutesInputField.value || 0, 0, 0);
this.onPick(this.selectedDate.getTime() / 1000 | 0);
}
this.destroy();
}, {once: true});
this.body.append(this.timeDiv);
}
const popupCenterer = document.createElement('div');
popupCenterer.classList.add('popup-centerer');
popupCenterer.append(this.container);
this.element.append(popupCenterer);
//const passed = (initDate.getTime() - (initDate.getTimezoneOffset() * 60000)) % 86400000;
//this.selectedDate = this.maxDate = new Date(initDate.getTime() - passed);
initDate.setHours(0, 0, 0, 0);
this.selectedDate = initDate;
this.maxDate = options.maxDate || new Date();
this.maxDate.setHours(0, 0, 0, 0);
this.selectedMonth = new Date(this.selectedDate);
this.selectedMonth.setDate(1);
this.maxMonth = new Date(this.maxDate);
this.maxMonth.setDate(1);
this.minMonth = new Date(this.minDate);
this.minMonth.setHours(0, 0, 0, 0);
this.minMonth.setDate(1);
if(this.selectedMonth.getTime() == this.minMonth.getTime()) {
this.prevBtn.setAttribute('disabled', 'true');
}
if(this.selectedMonth.getTime() == this.maxMonth.getTime()) {
this.nextBtn.setAttribute('disabled', 'true');
}
if(options.noTitle) {
this.setTitle = () => {};
}
this.setTimeTitle();
this.setTitle();
this.setMonth();
}
onPrevClick = (e: MouseEvent) => {
this.selectedMonth.setMonth(this.selectedMonth.getMonth() - 1);
this.setMonth();
if(this.selectedMonth.getTime() == this.minMonth.getTime()) {
this.prevBtn.setAttribute('disabled', 'true');
}
this.nextBtn.removeAttribute('disabled');
};
onNextClick = (e: MouseEvent) => {
this.selectedMonth.setMonth(this.selectedMonth.getMonth() + 1);
this.setMonth();
if(this.selectedMonth.getTime() == this.maxMonth.getTime()) {
this.nextBtn.setAttribute('disabled', 'true');
}
this.prevBtn.removeAttribute('disabled');
};
onDateClick = (e: MouseEvent) => {
//cancelEvent(e);
const target = e.target as HTMLElement;
if(!target.dataset.timestamp) return;
if(this.selectedEl) {
if(this.selectedEl == target) return;
this.selectedEl.classList.remove('active');
}
target.classList.add('active');
const timestamp = +target.dataset.timestamp;
this.selectedDate = new Date(timestamp);
this.setTitle();
this.setMonth();
this.setTimeTitle();
};
public setTimeTitle() {
if(this.btnConfirm && this.selectedDate) {
let dayStr = '';
const date = new Date();
date.setHours(0, 0, 0, 0);
if(this.selectedDate.getTime() === date.getTime()) {
dayStr = 'Today';
} else if(this.selectedDate.getTime() === (date.getTime() + 86400e3)) {
dayStr = 'Tomorrow';
} else {
dayStr = 'on ' + getFullDate(this.selectedDate, {
noTime: true,
monthAsNumber: true,
leadingZero: true
});
}
this.btnConfirm.firstChild.nodeValue = 'Send ' + dayStr + ' at ' + ('00' + this.hoursInputField.value).slice(-2) + ':' + ('00' + this.minutesInputField.value).slice(-2);
}
}
public setTitle() {
const splitted = this.selectedDate.toString().split(' ', 3);
this.title.innerText = splitted[0] + ', ' + splitted[1] + ' ' + splitted[2];
}
private renderElement(disabled: boolean, innerText = '') {
const el = document.createElement('button');
el.classList.add('btn-icon', 'date-picker-month-date');
if(disabled) {
el.setAttribute('disabled', 'true');
}
if(innerText) {
el.innerText = innerText;
}
return el;
}
public setMonth() {
this.monthTitle.innerText = months[this.selectedMonth.getMonth()] + ' ' + this.selectedMonth.getFullYear();
if(this.month) {
this.month.remove();
}
this.month = document.createElement('div');
this.month.classList.add('date-picker-month');
const days = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
this.month.append(...days.map(s => {
const el = this.renderElement(true, s);
el.classList.remove('date-picker-month-date');
el.classList.add('date-picker-month-day');
return el;
}));
const firstDate = new Date(this.selectedMonth);
// 0 - sunday
let dayIndex = firstDate.getDay() - 1;
if(dayIndex == -1) dayIndex = days.length - 1;
const clonedDate = new Date(firstDate.getTime());
clonedDate.setDate(clonedDate.getDate() - dayIndex - 1);
// Padding first week
for(let i = 0; i < dayIndex; ++i) {
if(this.options.showOverflowMonths) {
clonedDate.setDate(clonedDate.getDate() + 1);
this.month.append(this.renderElement(true, '' + clonedDate.getDate()));
} else {
this.month.append(this.renderElement(true));
}
}
do {
const date = firstDate.getDate();
const el = this.renderElement(firstDate > this.maxDate || firstDate < this.minDate, '' + date);
el.dataset.timestamp = '' + firstDate.getTime();
if(firstDate.getTime() === this.selectedDate.getTime()) {
this.selectedEl = el;
el.classList.add('active');
}
this.month.append(el);
firstDate.setDate(date + 1);
} while(firstDate.getDate() !== 1);
const remainder = this.month.childElementCount % 7;
if(this.options.showOverflowMonths && remainder) {
for(let i = remainder; i < 7; ++i) {
this.month.append(this.renderElement(true, '' + firstDate.getDate()));
firstDate.setDate(firstDate.getDate() + 1);
}
}
this.container.classList.toggle('is-max-lines', (this.month.childElementCount / 7) > 6);
this.monthsContainer.append(this.month);
}
}