ion-datepicker-2
Version:
A date picker for ionic
837 lines (783 loc) • 27.4 kB
text/typescript
import { Component, EventEmitter, ViewEncapsulation, ElementRef } from "@angular/core";
import { NavParams, ViewController } from 'ionic-angular';
import { DatePickerData, DatePickerView } from './datepicker.interface';
import { DateService } from '../services/datepicker.service';
export class DatePickerComponent {
/**
*
* @type {DatePickerData}
* @description - represents the configuration of the datepicker
* @memberof DatePickerComponent
*/
public config: DatePickerData;
/**
*
* @type {Date}
* @description - The currently selected date when opening the datepicker
* @memberof DatePickerComponent
*/
public selectedDate: Date = new Date();
/**
*
* @type {Date[]}
* @description - The whole list of dates in a month
* @memberof DatePickerComponent
*/
public dateList: Date[];
/**
*
* @type {number[]}
* @description - The columns of a month
* @memberof DatePickerComponent
*/
public cols: number[];
/**
*
* @type {number[]}
* @description - The rows in a month
* @memberof DatePickerComponent
*/
public rows: number[];
/**
*
* @type {string[]}
* @description - An array of the weekday names
* @memberof DatePickerComponent
*/
public weekdays: string[];
/**
*
* @type {string[]}
* @description - An array of month names
* @memberof DatePickerComponent
*/
public months: string[];
/**
*
* @type {number[]}
* @description - An array of the years
* @memberof DatePickerComponent
*/
public years: number[];
/**
*
* @type {DatePickerView}
* @description - Current view of picker
* @memberof DatePickerComponent
*/
public view: DatePickerView = DatePickerView.Calendar;
/**
*
* @type {tyepof DatePickerView}
* @description - List of view types
* @memberof DatePickerComponent
*/
public views: typeof DatePickerView = DatePickerView;
/**
*
* @private
* @type {Date}
* @description - The selected date after opening the datepicker
* @memberof DatePickerComponent
*/
private tempDate: Date;
/**
*
* @private
* @type {Date}
* @description - Today's date
* @memberof DatePickerComponent
*/
private today: Date = new Date();
/**
*
* Creates an instance of DatePickerComponent.
* @param {ViewController} viewCtrl - dismissing the modal
* @param {NavParams} navParams - carrying the navigation parameters
* @param {DateService} DatepickerService - services for various things
* @memberof DatePickerComponent
*/
constructor(
public viewCtrl: ViewController,
public navParams: NavParams,
public DatepickerService: DateService) {
this.config = this.navParams.data;
if (!this.config.calendar)
this.view = this.views.Day;
this.selectedDate = this.navParams.data.date;
this.initialize();
}
/**
*
* @function initialize - Initializes date variables
*/
public initialize(): void {
if (this.config.min)
this.config.min.setHours(0, 0, 0, 0);
if (this.config.max)
this.config.max.setHours(0, 0, 0, 0);
this.tempDate = this.selectedDate;
this.createDateList(this.selectedDate);
this.weekdays = this.DatepickerService.getDaysOfWeek();
this.months = this.DatepickerService.getMonths();
this.years = this.DatepickerService.getYears();
}
/**
*
* @function createDateList - creates the list of dates
* @param selectedDate - creates the list based on the currently selected date
*/
public createDateList(selectedDate: Date): void {
this.dateList = this.DatepickerService.createDateList(selectedDate);
this.cols = new Array(7);
this.rows = new Array(Math.ceil(this.dateList.length / this.cols.length));
}
/**
* @function getDate - gets the actual date of date from the list of dates
* @param row - the row of the date in a month. For instance 14 date would be 3rd or 2nd row
* @param col - the column of the date in a month. For instance 1 would be on the column of the weekday.
*/
public getDate(row: number, col: number): Date {
/**
* @description The locale en-US is noted for the sake of starting with monday if its in usa
*/
return this.dateList[(row * 7 + col)];
}
/**
*
* @function getDate - gets the actual number of date from the list of dates
* @param row - the row of the date in a month. For instance 14 date would be 3rd or 2nd row
* @param col - the column of the date in a month. For instance 1 would be on the column of the weekday.
*/
public getDateAsDay(row: number, col: number): number {
let date = this.getDate(row, col);
if (date) return date.getDate();
}
/**
*
* @function isDisabled - Checks whether the date should be disabled or not
* @param date - the date to test against
*/
public isDisabled(date: Date): boolean {
if (!date) return true;
if (this.config.min) {
this.config.min.setHours(0, 0, 0, 0);
if (date < this.config.min) return true;
}
if (this.config.max) {
this.config.max.setHours(0, 0, 0, 0);
if (date > this.config.max) return true;
}
if (this.config.disabledDates) {
return this.config.disabledDates.some(disabledDate =>
this.areEqualDates(new Date(disabledDate), date));
}
return false;
}
/**
*
* @function testYear - Checks whether the year should be disabled or not
* @param year - the year to test against
*/
public testYear(year: number): boolean {
if (year === undefined) return false;
let testDate = new Date(year, this.tempDate.getMonth(), this.tempDate.getDate());
return !this.isDisabled(testDate);
}
/**
*
* @function testMonth - Checks whether the year should be disabled or not
* @param month - the month to test against
*/
public testMonth(month: number): boolean {
if (month === undefined) return false;
let testDate = new Date(this.tempDate.getFullYear(), month, this.tempDate.getDate());
return !this.isDisabled(testDate);
}
/**
*
* @function testMonth - Checks whether the year should be disabled or not
* @param month - the month to test against
*/
public testDay(day: number): boolean {
if (day === undefined) return false;
let testDate = new Date(this.tempDate.getFullYear(), this.tempDate.getMonth(), day);
return !this.isDisabled(testDate);
}
/**
*
* @function isMark - Checks whether the date should be marked
* @param {Date} date - date to check
* @returns {boolean}
* @memberof DatePickerComponent
*/
public isMark(date: Date): boolean {
if (!date) return false;
if (this.config.markDates) {
return this.config.markDates.some(markDate =>
this.areEqualDates(new Date(markDate), date));
}
return false
}
/**
*
* @function isActualDate - Checks whether the date is today's date.
* @param {Date} date - date to check
* @returns {boolean}
* @memberof DatePickerComponent
*/
public isActualDate(date: Date): boolean {
if (!date) return false;
return this.areEqualDates(date, this.today);
}
/**
*
* @function isSelectedDate - Checks whether the date is the selected date.
* @param {Date} date - date to check
* @returns {boolean}
* @memberof DatePickerComponent
*/
public isSelectedDate(date: Date): boolean {
if (!date) return false;
return this.areEqualDates(date, this.selectedDate);
}
/**
*
* @function isTempDate - Checks whether the date is the selected date.
* @param {Date} date - date to check
* @returns {boolean}
* @memberof DatePickerComponent
*/
public isTempDate(date: Date): boolean {
if (!date) return false;
return this.areEqualDates(date, this.tempDate);
}
/**
*
* @function selectDate - selects a date and emits back the date
* @param {Date} date - date to select
* @returns {void}
* @memberof DatePickerComponent
*/
public selectDate(date: Date): void {
if (this.isDisabled(date)) return;
this.tempDate = date;
this.tempDate.setHours(0, 0, 0, 0);
this.config.ionSelected.emit(this.tempDate);
}
/**
*
* @function getSelectedWeekday - Gets the selected date's weekday
* @returns {string}
* @memberof DatePickerComponent
*/
public getSelectedWeekday(): string {
let day = this.tempDate.getDay();
let dayAdjust = 0;
// go back to sunday which is 6
// TODO: FIND BETTER WAY TO DO THIS. LIKE A ROTATE ARRAY
if (this.DatepickerService.doesStartFromMonday() && day === 0) dayAdjust = 6;
// go back one day
else if (this.DatepickerService.doesStartFromMonday()) dayAdjust = -1;
return this.weekdays[day + dayAdjust];
}
/**
*
* @function getSelectedMonth - Gets the selected date's name of month
* @returns {string}
* @memberof DatePickerComponent
*/
public getSelectedMonth(): string {
return this.months[this.tempDate.getMonth()];
}
/**
*
* @function getDayList - Gets the list of days
* @returns {string[]}
* @memberof DatePickerComponent
*/
public getDayList(): string[] {
var date = new Date(this.tempDate.getFullYear(), this.tempDate.getMonth(), 1);
var days = [];
while (date.getMonth() === this.tempDate.getMonth()) {
days.push(new Date(date).getDate());
date.setDate(date.getDate() + 1);
}
return days;
}
/**
*
* @function getTempMonth - Gets the temporary selected date's name of month
* @returns {string}
* @memberof DatePickerComponent
*/
public getTempMonth(): string {
return this.months[this.tempDate.getMonth()];
}
/**
*
* @function getTempYear - Gets the temporary selected date's year
* @returns {number}
* @memberof DatePickerComponent
*/
public getTempYear(): number {
return (this.tempDate || this.selectedDate).getFullYear();
}
/**
*
* @function getTempDate - Gets the temporary selected date's day
* @returns {number}
* @memberof DatePickerComponent
*/
public getTempDate(): number {
return (this.tempDate || this.selectedDate).getDate();
}
/**
*
* @function getSelectedDate - Gets selected date's date
* @returns {number}
* @memberof DatePickerComponent
*/
public getSelectedDate(): number {
return (this.selectedDate || new Date()).getDate();
}
/**
*
* @function getSelectedYear - Gets selected date's year
* @returns {number}
* @memberof DatePickerComponent
*/
public getSelectedYear(): number {
return (this.selectedDate || new Date()).getFullYear();
}
/**
*
* @function setSelectedMonth - Sets the selected month
* @memberof DatePickerComponent
*/
public setSelectedMonth(month: number): void {
this.tempDate = new Date(this.tempDate.getFullYear(), month, this.tempDate.getDate());
this.createDateList(this.tempDate);
if (this.config.calendar)
this.view = this.views.Calendar;
}
/**
*
* @function setSelectedMonth - Sets the selected month
* @memberof DatePickerComponent
*/
public setSelectedDay(day: number): void {
this.tempDate = new Date(this.tempDate.getFullYear(), this.tempDate.getMonth(), day);
if (this.config.calendar)
this.view = this.views.Calendar;
}
/**
*
* @function setSelectedYear - Sets the selected year
* @memberof DatePickerComponent
*/
public setSelectedYear(year: number): void {
this.tempDate = new Date(year, this.tempDate.getMonth(), this.tempDate.getDate());
this.createDateList(this.tempDate);
if (this.config.calendar)
this.view = this.views.Calendar;
}
/**
*
* @function setView - Sets the view and scrolls to the relevant row
* @param {DatePickerView} view - the view to set
* @param {number} index - index of date/month/year
* @param {number} total - total amount of items
* @param {HTMLElement} scrolledElement - element to scroll upon
* @memberof DatePickerComponent
*/
public setView(view: DatePickerView, index: number | string, total: number | string, scrolledElement: HTMLElement): void {
this.view = view;
setTimeout(() => {
scrolledElement.scrollTop = (scrolledElement.scrollHeight / +total) * (+index - 1);
}, 10);
}
/**
*
* @function onCancel - activates on cancel and emits a cancel event
* @memberof DatePickerComponent
*/
public onCancel(): void {
if (this.config.date)
this.selectedDate = this.config.date || new Date();
this.config.ionCanceled.emit();
this.viewCtrl.dismiss();
};
/**
*
* @function onDone - activates on done and emits date
* @memberof DatePickerComponent
*/
public onDone(): void {
this.config.date = this.tempDate;
this.config.ionChanged.emit(this.config.date);
this.viewCtrl.dismiss();
};
/**
*
* @function limitTo - removes part of the string depending on a language and its needs
* @param {(Array<string> | string)} arr - the array of strings to limit
* @param {number} limit - amount to limit
* @returns {(Array<string> | string)}
* @memberof DatePickerComponent
*/
public limitTo(arr: Array<string> | string, limit: number): Array<string> | string {
if (this.DatepickerService.locale === 'custom') return arr;
if (Array.isArray(arr))
return arr.splice(0, limit);
if (this.DatepickerService.locale === 'zh-CN' || this.DatepickerService.locale === 'zh-TW')
arr = arr.replace("星期", "")
return (<string>arr).slice(0, limit);
}
/**
*
* @function monthShort - returns the abbreviated month name
* @param {(Array<string> | string)} arr - the array of strings to limit
* @returns {(Array<string> | string)}
* @memberof DatePickerComponent
*/
public monthShort(arr: Array<string> | string): Array<string> | string {
return this.limitTo(arr, 3);
}
/**
*
* @function dayOfWeekShort - returns the abbreviated day of week
* @param {(Array<string> | string)} arr - the array of strings to limit
* @returns {(Array<string> | string)}
* @memberof DatePickerComponent
*/
public dayOfWeekShort(arr: Array<string> | string): Array<string> | string {
let limit = 3;
if (this.DatepickerService.locale === 'de') limit = 2;
return this.limitTo(arr, limit);
}
/**
*
* @function nextMonth - moves the calendar to the next month
* @memberof DatePickerComponent
*/
public nextMonth() {
//if (this.max.getMonth() < this.tempDate.getMonth() + 1 && this.min.getFullYear() === this.tempDate.getFullYear()) return;
let testDate: Date = new Date(this.tempDate.getTime());
if (testDate.getMonth() === 11) {
testDate.setFullYear(testDate.getFullYear() + 1);
testDate.setMonth(0);
}
else {
testDate.setMonth(testDate.getMonth() + 1);
}
if (testDate.getDate() !== this.tempDate.getDate()) {
// something went wrong with the dates, oh oh.
testDate = new Date(testDate.getFullYear(), testDate.getMonth(), 0);
}
let maxTestDate: Date;
if (this.config.max) {
maxTestDate = new Date(this.config.max.getFullYear(), this.config.max.getMonth() + 1, 0);
}
if (!maxTestDate || maxTestDate >= testDate) {
if (maxTestDate && maxTestDate.getMonth() === testDate.getMonth()) {
if (this.config.max.getDate() < testDate.getDate()) {
testDate.setDate(this.today.getDate());
}
}
this.tempDate = testDate;
let availableDates = this.DatepickerService.getMonthAvailableDays(testDate, this.config.disabledDates);
if (availableDates.length === 0) {
this.tempDate = testDate;
this.nextMonth();
return;
}
// if the current day is a disabled one, just take the first available day
if (-1 === availableDates.findIndex(date => date.getDate() === this.tempDate.getDate())) {
this.tempDate = availableDates[0];
}
this.createDateList(this.tempDate);
}
}
/**
*
* @function prevMonth - moves the calendar to the previous month
* @memberof DatePickerComponent
*/
public prevMonth() {
let testDate: Date = new Date(this.tempDate.getTime());
testDate.setMonth(testDate.getMonth() - 1);
// testDate.setDate(this.tempDate.getDate());
if (testDate.getDate() !== this.tempDate.getDate()) {
// something went wrong with the dates, oh oh.
testDate = new Date(testDate.getFullYear(), testDate.getMonth(), 0);
}
let minTestDate: Date;
if (this.config.min) {
minTestDate = new Date(this.config.min);
minTestDate.setDate(1);
}
if (!minTestDate || minTestDate <= testDate) {
if (minTestDate && minTestDate.getMonth() === testDate.getMonth()) {
if (this.config.min.getDate() > testDate.getDate()) {
testDate.setDate(this.config.min.getDate());
}
}
this.tempDate = testDate;
let availableDates = this.DatepickerService.getMonthAvailableDays(testDate, this.config.disabledDates);
if (availableDates.length === 0) {
this.tempDate = testDate;
this.prevMonth();
return;
}
// if the current day is a disabled one, just take the last available day
if (-1 === availableDates.findIndex(date => date.getDate() === this.tempDate.getDate())) {
this.tempDate = availableDates[availableDates.length - 1];
}
this.createDateList(this.tempDate);
}
}
/**
*
* @function areEqualDates - compares 2 dates only by their month,date & year
* @private
* @param {Date} dateA - first date to compare
* @param {Date} dateB - second date to compare
* @returns
* @memberof DatePickerComponent
*/
private areEqualDates(dateA: Date, dateB: Date): boolean {
return dateA.getDate() === dateB.getDate() &&
dateA.getMonth() === dateB.getMonth() &&
dateA.getFullYear() === dateB.getFullYear();
}
}