ng-devui
Version:
DevUI components based on Angular
996 lines (992 loc) • 217 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Inject, Component, ChangeDetectionStrategy, Input, ViewChild, HostListener, EventEmitter, forwardRef, Output, ContentChild, HostBinding, NgModule } from '@angular/core';
import * as i4 from '@angular/common';
import { DOCUMENT, CommonModule } from '@angular/common';
import * as i1 from 'ng-devui/i18n';
import { I18nFormat, EN_US } from 'ng-devui/i18n';
import { Subject, fromEvent } from 'rxjs';
import { takeUntil, filter, debounceTime, map } from 'rxjs/operators';
import * as i4$1 from 'ng-devui/button';
import { ButtonModule } from 'ng-devui/button';
import * as i3 from '@angular/cdk/scrolling';
import { ScrollingModule } from '@angular/cdk/scrolling';
import * as i5 from 'ng-devui/popover';
import { PopoverModule } from 'ng-devui/popover';
import { chunk } from 'lodash-es';
import * as i5$1 from '@angular/forms';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import * as i3$1 from 'ng-devui/utils';
import { DefaultDateConverter, WithConfig } from 'ng-devui/utils';
import { __decorate, __metadata } from 'tslib';
import * as i6 from 'ng-devui/dropdown';
import { DropDownModule } from 'ng-devui/dropdown';
class DatepickerProService {
set minDate(value) {
this._minDate = new Date(value) || new Date(this.calendarRange[0], 0, 1);
this.detectedChanges.next();
}
get minDate() {
return this._minDate;
}
set maxDate(value) {
this._maxDate = new Date(value) || new Date(this.calendarRange[1], 11, 31, 23, 59, 59);
this.detectedChanges.next();
}
get maxDate() {
return this._maxDate;
}
get closeAfterSelected() {
return !this.isRange && !this.showTime;
}
get curHour() {
if (this.isRange) {
return (this.currentActiveInput === 'start' ? this.curRangeDate[0]?.getHours() : this.curRangeDate[1]?.getHours()) || 0;
}
else {
return this.curDate?.getHours() || 0;
}
}
get curMin() {
if (this.isRange) {
return (this.currentActiveInput === 'start' ? this.curRangeDate[0]?.getMinutes() : this.curRangeDate[1]?.getMinutes()) || 0;
}
else {
return this.curDate?.getMinutes() || 0;
}
}
get curSec() {
if (this.isRange) {
return (this.currentActiveInput === 'start' ? this.curRangeDate[0]?.getSeconds() : this.curRangeDate[1]?.getSeconds()) || 0;
}
else {
return this.curDate?.getSeconds() || 0;
}
}
constructor(doc) {
this.doc = doc;
this.curRangeDate = [];
this.calendarRange = [1970, 2099];
this.currentActiveInput = 'start';
this._minDate = new Date(this.calendarRange[0], 0, 1);
this._maxDate = new Date(this.calendarRange[1], 11, 31, 23, 59, 59);
this.toggleEvent = new Subject();
this.closeDropdownEvent = new Subject();
this.activeInputChange = new Subject();
this.selectedDateChange = new Subject();
this.updateDateValue = new Subject();
this.selectedTimeChange = new Subject();
this.updateTimeChange = new Subject();
this.detectedChanges = new Subject();
this.document = this.doc;
}
dateInRange(date) {
if (!date) {
return true;
}
return (date.getTime() > this.minDate.getTime() && date.getTime() < this.maxDate.getTime()) ||
date.toDateString() === this.minDate.toDateString() || date.toDateString() === this.maxDate.toDateString();
}
resetMin() {
this.minDate = new Date(this.calendarRange[0], 0, 1);
}
resetMax() {
this.maxDate = new Date(this.calendarRange[1], 11, 31);
}
// 对范围模式下一些非法的选择进行修正
fixRangeDate() {
const start = this.curRangeDate[0]?.getTime();
const end = this.curRangeDate[1]?.getTime();
if (start && end && end < start) {
if (this.currentActiveInput === 'start') {
this.curRangeDate[1] = null;
}
else if (this.currentActiveInput === 'end') {
this.curRangeDate[0] = null;
}
}
}
// 判断日期是否为起始日期
isStartDate(date) {
if (!this.isRange) {
return false;
}
if (this.currentActiveInput === 'start') {
return date.toDateString() === this.curHoverDate?.toDateString() || date.toDateString() === this.curRangeDate[0]?.toDateString();
}
return date.toDateString() === this.curRangeDate[0]?.toDateString();
}
// 判断日期是否为结束日期
isEndDate(date) {
if (!this.isRange) {
return false;
}
if (this.currentActiveInput === 'end') {
return date.toDateString() === this.curHoverDate?.toDateString() || date.toDateString() === this.curRangeDate[1]?.toDateString();
}
return date.toDateString() === this.curRangeDate[1]?.toDateString();
}
// 判断日期是否在hover范围或者选中的范围内
isDateInRange(date) {
const dateTime = date.getTime();
const dateStr = date.toDateString();
if (this.isRange) {
if (this.currentActiveInput === 'start') {
return (this.curHoverDate || this.curRangeDate[0])?.getTime() < dateTime &&
(this.curHoverDate || this.curRangeDate[0])?.toDateString() !== dateStr &&
this.curRangeDate[1]?.getTime() > dateTime &&
this.curRangeDate[1]?.toDateString() !== dateStr;
}
else {
return this.curRangeDate[0]?.getTime() < dateTime &&
this.curRangeDate[0]?.toDateString() !== dateStr &&
(this.curHoverDate || this.curRangeDate[1])?.getTime() > dateTime &&
(this.curHoverDate || this.curRangeDate[1]).toDateString() !== dateStr;
}
}
else {
return false;
}
}
// 判断日期是否在已选中的范围内,与hover做区分
isDateInSelectRange(date) {
if (!this.isRange) {
return false;
}
if (!this.curRangeDate[0] || !this.curRangeDate[1]) {
return false;
}
return this.curRangeDate[0].getTime() < date.getTime() && this.curRangeDate[1].getTime() > date.getTime() &&
this.curRangeDate[1].toDateString() !== date.toDateString() && this.curRangeDate[0].toDateString() !== date.toDateString();
}
isDateActive(date) {
const dateStr = date.toDateString();
if (this.isRange) {
return dateStr === this.curRangeDate[0]?.toDateString() || dateStr === this.curRangeDate[1]?.toDateString();
}
else {
return dateStr === this.curDate?.toDateString();
}
}
isMonthActive(yearIndex, monthIndex) {
if (this.isRange) {
return (yearIndex === this.curRangeDate[0]?.getFullYear() && monthIndex === this.curRangeDate[0]?.getMonth()) ||
(yearIndex === this.curRangeDate[1]?.getFullYear() && monthIndex === this.curRangeDate[1]?.getMonth());
}
else {
return yearIndex === this.curDate?.getFullYear() && monthIndex === this.curDate?.getMonth();
}
}
isYearActive(yearIndex) {
if (this.isRange) {
return yearIndex === this.curRangeDate[0]?.getFullYear() || yearIndex === this.curRangeDate[1]?.getFullYear();
}
else {
return yearIndex === this.curDate?.getFullYear();
}
}
// 是否为范围选中日期中对应的input激活项
isActiveInputTypeDate(date) {
if (!this.isRange) {
return false;
}
if (this.currentActiveInput === 'start') {
return date.toDateString() === this.curRangeDate[0]?.toDateString();
}
else {
return date.toDateString() === this.curRangeDate[1]?.toDateString();
}
}
// 是否为选中日期且在废弃范围逻辑内
isDateAbandon(date) {
if (!this.isRange || (!this.curRangeDate[0] || !this.curRangeDate[1])) {
return false;
}
if (!this.isDateActive(date)) {
return false;
}
if (this.currentActiveInput === 'start') {
return this.curHoverDate?.getTime() > date.getTime();
}
else {
return this.curHoverDate?.getTime() < date.getTime();
}
}
isInSuggestList(date) {
if (!this.markedRangeDateList) {
return false;
}
for (let index = 0; index < this.markedRangeDateList.length; index++) {
const range = this.markedRangeDateList[index];
if (range[0]?.getTime() < date.getTime() && range[1]?.getTime() > date.getTime()) {
return true;
}
if (range[0]?.toDateString() === date.toDateString() || range[1]?.toDateString() === date.toDateString()) {
return true;
}
}
return false;
}
isMarkedDate(date) {
for (let index = 0; index < this.markedDateList?.length; index++) {
if (this.markedDateList[index]?.toDateString() === date.toDateString()) {
return true;
}
}
return false;
}
mearsureStrWidth(str) {
const mearsureDom = this.document.createElement('span');
mearsureDom.innerText = str;
mearsureDom.style.visibility = 'hidden';
this.document.body.appendChild(mearsureDom);
const domWidth = mearsureDom.offsetWidth;
this.document.body.removeChild(mearsureDom);
return domWidth;
}
ngOnDestroy() {
this.toggleEvent.complete();
this.selectedDateChange.complete();
this.closeDropdownEvent.complete();
this.updateDateValue.complete();
this.updateTimeChange.complete();
this.selectedTimeChange.complete();
this.activeInputChange.complete();
this.detectedChanges.complete();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerProService, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerProService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerProService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [DOCUMENT]
}] }] });
class DatepickerProCommonDataService {
constructor() {
this.calendarDataCache = {};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerProCommonDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerProCommonDataService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatepickerProCommonDataService, decorators: [{
type: Injectable
}] });
class TimepickerPanelComponent {
constructor(el, pickSrv, i18n, cdr) {
this.el = el;
this.pickSrv = pickSrv;
this.i18n = i18n;
this.cdr = cdr;
this.firstList = [];
this.secondList = [];
this.thirdList = [];
this.hourIndex = 0;
this.minIndex = 0;
this.secIndex = 0;
this.typeList = ['hour', 'min', 'sec'];
this.unsubscribe$ = new Subject();
}
ngOnInit() {
this.initDateList();
this.initObservable();
this.setI18nText();
}
setI18nText() {
this.i18nText = this.i18n.getI18nText().datePickerPro;
this.i18nSubscription = this.i18n.langChange().subscribe((data) => {
this.i18nText = data.datePickerPro;
});
}
initObservable() {
this.pickSrv.toggleEvent.pipe(takeUntil(this.unsubscribe$)).subscribe((isOpen) => {
if (isOpen) {
setTimeout(() => {
this.initDateList(true);
this.cdr.detectChanges();
});
}
});
this.pickSrv.updateTimeChange.pipe(takeUntil(this.unsubscribe$)).subscribe((value) => {
if (this.hourIndex !== value.hour) {
this.chooseTime('hour', value.hour);
}
if (this.minIndex !== value.min) {
this.chooseTime('min', value.min);
}
if (this.secIndex !== value.seconds) {
this.chooseTime('sec', value.seconds);
}
this.cdr.detectChanges();
});
if (this.pickSrv.isRange) {
this.pickSrv.activeInputChange.pipe(takeUntil(this.unsubscribe$)).subscribe((type) => {
const isNull = (type === 'start' && !this.pickSrv.curRangeDate[0]) || (type === 'end' && !this.pickSrv.curRangeDate[1]);
if (this.hourIndex !== this.pickSrv.curHour || isNull) {
this.chooseTime('hour', isNull ? null : this.pickSrv.curHour);
}
if (this.minIndex !== this.pickSrv.curMin || isNull) {
this.chooseTime('min', isNull ? null : this.pickSrv.curMin);
}
if (this.secIndex !== this.pickSrv.curSec || isNull) {
this.chooseTime('sec', isNull ? null : this.pickSrv.curSec);
}
});
}
this.pickSrv.selectedDateChange.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
const isFixTime = this.fixTime();
this.cdr.detectChanges();
if (isFixTime) {
setTimeout(() => {
this.pickSrv.selectedTimeChange.next({
activeInput: this.pickSrv.currentActiveInput,
hour: this.hourIndex,
min: this.minIndex,
seconds: this.secIndex,
});
});
}
});
}
initDateList(justScroll = false) {
if (this.pickSrv.curDate) {
this.hourIndex = this.pickSrv.curDate.getHours();
this.minIndex = this.pickSrv.curDate.getMinutes();
this.secIndex = this.pickSrv.curDate.getSeconds();
}
this.typeList.forEach((type) => {
this.chooseTime(type, this[`${type}Index`], false, justScroll);
});
}
chooseTime(type, index, handle = false, justScroll = false) {
if (this.itemIsDisabled(type, index)) {
return;
}
let fixed;
switch (type) {
case 'hour':
this.hourIndex = index;
fixed = this.fixTime(justScroll);
this.firstList = new Array(24).fill(1).map((t, i) => {
return {
time: i < 10 ? `0${i}` : String(i),
type: 'hour',
active: this.hourIndex === i,
};
});
if (!fixed) {
this.setScroll('first', this.hourIndex, justScroll);
}
break;
case 'min':
this.minIndex = index;
this.fixTime(justScroll);
this.secondList = new Array(60).fill(1).map((t, i) => {
return {
time: i < 10 ? `0${i}` : String(i),
type: 'min',
active: this.minIndex === i,
};
});
if (!fixed) {
this.setScroll('second', this.minIndex, justScroll);
}
break;
case 'sec':
this.secIndex = index;
this.thirdList = new Array(60).fill(1).map((t, i) => {
return {
time: i < 10 ? `0${i}` : String(i),
type: 'sec',
active: this.secIndex === i,
};
});
this.setScroll('third', this.secIndex, justScroll);
break;
default:
}
this.cdr.detectChanges();
if (handle) {
this.pickSrv.selectedTimeChange.next({
activeInput: this.pickSrv.currentActiveInput,
hour: this.hourIndex,
min: this.minIndex,
seconds: this.secIndex,
});
}
}
fixTime(justScroll = false) {
let curTime;
if (this.pickSrv.isRange) {
const target = this.pickSrv.curRangeDate[this.pickSrv.currentActiveInput === 'start' ? 0 : 1];
if (!target) {
return;
}
curTime = new Date(target);
}
else {
if (!this.pickSrv.curDate) {
return;
}
curTime = new Date(this.pickSrv.curDate);
}
curTime.setHours(this.hourIndex);
curTime.setMinutes(this.minIndex);
curTime.setSeconds(this.secIndex);
let isFixTime = false;
if (curTime.getTime() < this.pickSrv.minDate.getTime()) {
this.pickSrv.curDate = this.pickSrv.minDate;
isFixTime = true;
}
if (curTime.getTime() > this.pickSrv.maxDate.getTime()) {
this.pickSrv.curDate = this.pickSrv.maxDate;
isFixTime = true;
}
if (isFixTime) {
this.initDateList(justScroll);
}
return isFixTime;
}
itemIsDisabled(type, index) {
let curTime;
if (this.pickSrv.isRange) {
const target = this.pickSrv.curRangeDate[this.pickSrv.currentActiveInput === 'start' ? 0 : 1];
if (!target) {
return false;
}
curTime = new Date(target);
}
else {
if (!this.pickSrv.curDate) {
return false;
}
curTime = new Date(this.pickSrv.curDate);
}
if (!curTime) {
return false;
}
let flag = false;
let time;
let isTimeBoundary = false;
const maxTime = this.pickSrv.maxDate.getTime();
const minTime = this.pickSrv.minDate.getTime();
switch (type) {
case 'hour':
curTime.setHours(index);
curTime.setMinutes(this.minIndex);
time = curTime.setSeconds(this.secIndex);
isTimeBoundary = time > maxTime ? this.pickSrv.maxDate.getHours() === index : this.pickSrv.minDate.getHours() === index;
break;
case 'min':
curTime.setHours(this.hourIndex);
curTime.setMinutes(index);
time = curTime.setSeconds(this.secIndex);
isTimeBoundary = time > maxTime ? this.pickSrv.maxDate.getMinutes() === index : this.pickSrv.minDate.getMinutes() === index;
break;
case 'sec':
curTime.setHours(this.hourIndex);
curTime.setMinutes(this.minIndex);
time = curTime.setSeconds(index);
break;
default:
}
flag = time > maxTime || time < minTime;
return flag && !isTimeBoundary;
}
setAllScroll(first, second, third, justScroll) {
this.setScroll('first', first, justScroll);
this.setScroll('second', second, justScroll);
this.setScroll('third', third, justScroll);
}
setScroll(whichList, index, justScroll) {
const scroll = (22 + 8) * index;
const duration = justScroll ? 0 : 100;
if (this.el) {
this.scrollTo(this.el.nativeElement.querySelector(`.devui-${whichList}-list`), scroll, duration);
}
}
scrollTo(element, to, duration) {
if (typeof window === undefined || !element) {
return;
}
if (duration <= 0) {
element.scrollTop = to;
return;
}
const difference = to - element.scrollTop;
const perTick = (difference / duration) * 10;
const reqAnimFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame;
reqAnimFrame(() => {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop === to) {
return;
}
this.scrollTo(element, to, duration - 10);
});
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimepickerPanelComponent, deps: [{ token: i0.ElementRef }, { token: DatepickerProService }, { token: i1.I18nService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TimepickerPanelComponent, selector: "d-timepicker-panel", ngImport: i0, template: "<div class=\"devui-timepicker-panel\">\n <div class=\"devui-time-header\">\n <span class=\"devui-time-header-item\">{{ i18nText?.hour }}</span>\n <span class=\"devui-time-header-item\">{{ i18nText?.min }}</span>\n <span class=\"devui-time-header-item\">{{ i18nText?.second }}</span>\n </div>\n <div class=\"devui-time-picker\">\n <ul *ngIf=\"firstList.length\" class=\"devui-time-list devui-first-list\">\n <li\n *ngFor=\"let item of firstList; let i = index\"\n class=\"devui-time-item devui-first-item\"\n [ngClass]=\"{\n active: item?.active,\n disabled: itemIsDisabled('hour', i)\n }\"\n (click)=\"chooseTime(item.type, i, true)\"\n >\n {{ item?.time }}\n </li>\n </ul>\n <ul *ngIf=\"secondList.length\" class=\"devui-time-list devui-second-list\">\n <li\n *ngFor=\"let item of secondList; let i = index\"\n class=\"devui-time-item devui-second-item\"\n [ngClass]=\"{\n active: item?.active,\n disabled: itemIsDisabled('min', i)\n }\"\n (click)=\"chooseTime(item.type, i, true)\"\n >\n {{ item?.time }}\n </li>\n </ul>\n <ul *ngIf=\"thirdList.length\" class=\"devui-time-list devui-third-list\">\n <li\n *ngFor=\"let item of thirdList; let i = index\"\n class=\"devui-time-item devui-third-item\"\n [ngClass]=\"{\n active: item?.active,\n disabled: itemIsDisabled('sec', i)\n }\"\n (click)=\"chooseTime(item.type, i, true)\"\n >\n {{ item?.time }}\n </li>\n </ul>\n </div>\n</div>\n", styles: [":host{display:inline-block;vertical-align:top;font-size:12px}.devui-timepicker-panel{width:115px;height:306px;text-align:center;border-left:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-timepicker-panel .devui-time-header{display:flex;height:30px;padding:0 12px}.devui-timepicker-panel .devui-time-header-item{flex:1;line-height:30px;margin-right:12px}.devui-timepicker-panel .devui-time-header-item:last-child{margin-right:0}.devui-timepicker-panel .devui-time-picker{display:flex;height:276px;width:114px;padding:0 12px;overflow:hidden;border-radius:var(--devui-border-radius, 2px) var(--devui-border-radius, 2px) 0 0}.devui-timepicker-panel .devui-time-picker .devui-time-list{flex:1;overflow:hidden;scroll-behavior:auto;padding-right:6px;scrollbar-gutter:stable}.devui-timepicker-panel .devui-time-picker .devui-time-list:last-child{padding-right:0}.devui-timepicker-panel .devui-time-picker .devui-time-list::-webkit-scrollbar{width:4px}.devui-timepicker-panel .devui-time-picker .devui-time-list:hover{overflow-y:scroll}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item{width:100%;height:22px;line-height:22px;text-align:center;cursor:pointer}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item:not(:last-child){margin-bottom:8px}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item:last-child{margin-bottom:254px}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item.disabled{cursor:not-allowed}.devui-timepicker-panel .devui-time-picker:not(.devui-disabled) .devui-time-list .devui-time-item:hover{color:var(--devui-list-item-hover-text, #000000);background-color:var(--devui-list-item-hover-bg, #f2f2f3);border-radius:var(--devui-border-radius-feedback, 4px)}.devui-timepicker-panel .devui-time-picker:not(.devui-disabled) .devui-time-list .devui-time-item.active{color:var(--devui-list-item-active-text, #000000);background-color:var(--devui-list-item-active-bg, #cedefd);border-radius:var(--devui-border-radius-feedback, 4px)}.devui-timepicker-panel .devui-time-picker:not(.devui-disabled) .devui-time-list .devui-time-item.disabled{color:var(--devui-disabled-text, #c2c2c2);background-color:var(--devui-disabled-bg, #f3f3f3);border-radius:var(--devui-border-radius-feedback, 4px)}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimepickerPanelComponent, decorators: [{
type: Component,
args: [{ selector: 'd-timepicker-panel', preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"devui-timepicker-panel\">\n <div class=\"devui-time-header\">\n <span class=\"devui-time-header-item\">{{ i18nText?.hour }}</span>\n <span class=\"devui-time-header-item\">{{ i18nText?.min }}</span>\n <span class=\"devui-time-header-item\">{{ i18nText?.second }}</span>\n </div>\n <div class=\"devui-time-picker\">\n <ul *ngIf=\"firstList.length\" class=\"devui-time-list devui-first-list\">\n <li\n *ngFor=\"let item of firstList; let i = index\"\n class=\"devui-time-item devui-first-item\"\n [ngClass]=\"{\n active: item?.active,\n disabled: itemIsDisabled('hour', i)\n }\"\n (click)=\"chooseTime(item.type, i, true)\"\n >\n {{ item?.time }}\n </li>\n </ul>\n <ul *ngIf=\"secondList.length\" class=\"devui-time-list devui-second-list\">\n <li\n *ngFor=\"let item of secondList; let i = index\"\n class=\"devui-time-item devui-second-item\"\n [ngClass]=\"{\n active: item?.active,\n disabled: itemIsDisabled('min', i)\n }\"\n (click)=\"chooseTime(item.type, i, true)\"\n >\n {{ item?.time }}\n </li>\n </ul>\n <ul *ngIf=\"thirdList.length\" class=\"devui-time-list devui-third-list\">\n <li\n *ngFor=\"let item of thirdList; let i = index\"\n class=\"devui-time-item devui-third-item\"\n [ngClass]=\"{\n active: item?.active,\n disabled: itemIsDisabled('sec', i)\n }\"\n (click)=\"chooseTime(item.type, i, true)\"\n >\n {{ item?.time }}\n </li>\n </ul>\n </div>\n</div>\n", styles: [":host{display:inline-block;vertical-align:top;font-size:12px}.devui-timepicker-panel{width:115px;height:306px;text-align:center;border-left:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-timepicker-panel .devui-time-header{display:flex;height:30px;padding:0 12px}.devui-timepicker-panel .devui-time-header-item{flex:1;line-height:30px;margin-right:12px}.devui-timepicker-panel .devui-time-header-item:last-child{margin-right:0}.devui-timepicker-panel .devui-time-picker{display:flex;height:276px;width:114px;padding:0 12px;overflow:hidden;border-radius:var(--devui-border-radius, 2px) var(--devui-border-radius, 2px) 0 0}.devui-timepicker-panel .devui-time-picker .devui-time-list{flex:1;overflow:hidden;scroll-behavior:auto;padding-right:6px;scrollbar-gutter:stable}.devui-timepicker-panel .devui-time-picker .devui-time-list:last-child{padding-right:0}.devui-timepicker-panel .devui-time-picker .devui-time-list::-webkit-scrollbar{width:4px}.devui-timepicker-panel .devui-time-picker .devui-time-list:hover{overflow-y:scroll}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item{width:100%;height:22px;line-height:22px;text-align:center;cursor:pointer}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item:not(:last-child){margin-bottom:8px}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item:last-child{margin-bottom:254px}.devui-timepicker-panel .devui-time-picker .devui-time-list .devui-time-item.disabled{cursor:not-allowed}.devui-timepicker-panel .devui-time-picker:not(.devui-disabled) .devui-time-list .devui-time-item:hover{color:var(--devui-list-item-hover-text, #000000);background-color:var(--devui-list-item-hover-bg, #f2f2f3);border-radius:var(--devui-border-radius-feedback, 4px)}.devui-timepicker-panel .devui-time-picker:not(.devui-disabled) .devui-time-list .devui-time-item.active{color:var(--devui-list-item-active-text, #000000);background-color:var(--devui-list-item-active-bg, #cedefd);border-radius:var(--devui-border-radius-feedback, 4px)}.devui-timepicker-panel .devui-time-picker:not(.devui-disabled) .devui-time-list .devui-time-item.disabled{color:var(--devui-disabled-text, #c2c2c2);background-color:var(--devui-disabled-bg, #f3f3f3);border-radius:var(--devui-border-radius-feedback, 4px)}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: DatepickerProService }, { type: i1.I18nService }, { type: i0.ChangeDetectorRef }] });
class FooterPanelComponent {
get isRange() {
return this.pickerSrv.isRange;
}
get confirmDisable() {
if (this.isRange) {
return (this.pickerSrv.currentActiveInput === 'start' && !this.pickerSrv.curRangeDate[0]) ||
(this.pickerSrv.currentActiveInput === 'end' && !this.pickerSrv.curRangeDate[1]);
}
else {
return false;
}
}
constructor(pickerSrv, i18n) {
this.pickerSrv = pickerSrv;
this.i18n = i18n;
this.setI18nText();
}
setI18nText() {
this.i18nText = this.i18n.getI18nText().common;
this.i18nSubscription = this.i18n.langChange().subscribe((data) => {
this.i18nText = data.common;
});
}
ensureDate() {
if (this.pickerSrv.isRange) {
if (this.pickerSrv.currentActiveInput === 'start') {
this.pickerSrv.currentActiveInput = 'end';
this.pickerSrv.activeInputChange.next('end');
}
else if (!this.pickerSrv.curRangeDate[0]) {
this.pickerSrv.currentActiveInput = 'start';
this.pickerSrv.activeInputChange.next('start');
}
else {
this.close(true);
}
}
else {
this.close(true);
}
}
close(isConfirm = false) {
this.pickerSrv.closeDropdownEvent.next(isConfirm);
}
ngOnDestroy() {
this.i18nSubscription.unsubscribe();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FooterPanelComponent, deps: [{ token: DatepickerProService }, { token: i1.I18nService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FooterPanelComponent, selector: "d-datepicker-footer-panel", inputs: { footerTemplate: "footerTemplate" }, ngImport: i0, template: "<div class=\"devui-datepicekr-pro-footer\">\n <ng-template [ngTemplateOutlet]=\"footerTemplate || default\"> </ng-template>\n</div>\n\n<ng-template #default>\n <d-button bsStyle=\"primary\" [disabled]=\"confirmDisable\" (click)=\"ensureDate()\"> {{ i18nText.btnOk }} </d-button>\n <d-button class=\"devui-cancel-button\" bsStyle=\"common\" *ngIf=\"isRange\" (click)=\"close()\"> {{ i18nText.btnCancel }} </d-button>\n</ng-template>\n", styles: [".devui-datepicekr-pro-footer{padding:8px;text-align:center;border-top:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-datepicekr-pro-footer .devui-cancel-button{margin-left:4px}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i4$1.ButtonComponent, selector: "d-button", inputs: ["id", "type", "bsStyle", "shape", "bsSize", "bsPosition", "bordered", "icon", "disabled", "showLoading", "width", "autofocus", "loadingTemplateRef"], outputs: ["btnClick"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FooterPanelComponent, decorators: [{
type: Component,
args: [{ selector: 'd-datepicker-footer-panel', preserveWhitespaces: false, template: "<div class=\"devui-datepicekr-pro-footer\">\n <ng-template [ngTemplateOutlet]=\"footerTemplate || default\"> </ng-template>\n</div>\n\n<ng-template #default>\n <d-button bsStyle=\"primary\" [disabled]=\"confirmDisable\" (click)=\"ensureDate()\"> {{ i18nText.btnOk }} </d-button>\n <d-button class=\"devui-cancel-button\" bsStyle=\"common\" *ngIf=\"isRange\" (click)=\"close()\"> {{ i18nText.btnCancel }} </d-button>\n</ng-template>\n", styles: [".devui-datepicekr-pro-footer{padding:8px;text-align:center;border-top:1px solid var(--devui-dividing-line, #f0f0f0)}.devui-datepicekr-pro-footer .devui-cancel-button{margin-left:4px}\n"] }]
}], ctorParameters: () => [{ type: DatepickerProService }, { type: i1.I18nService }], propDecorators: { footerTemplate: [{
type: Input
}] } });
const DAY_DURATION = 24 * 60 * 60 * 1000;
const HOUR_DURATION = 60 * 60 * 1000;
class CalendarPanelComponent {
get curHoverDate() {
return this.pickerSrv.curHoverDate;
}
set curHoverDate(value) {
this.pickerSrv.curHoverDate = value;
this.cdr.detectChanges();
}
get curDate() {
if (this.isRangeType) {
if (this.pickerSrv.currentActiveInput === 'start') {
return this.pickerSrv.curRangeDate[0];
}
else if (this.pickerSrv.currentActiveInput === 'end') {
return this.pickerSrv.curRangeDate[1];
}
}
else {
return this.pickerSrv.curDate;
}
}
set curDate(value) {
if (this.isRangeType) {
if (this.pickerSrv.currentActiveInput === 'start') {
this.pickerSrv.curRangeDate[0] = value;
}
else if (this.pickerSrv.currentActiveInput === 'end') {
if (this.pickerSrv.showTime) {
this.pickerSrv.curRangeDate[1] =
(this.pickerSrv.curRangeDate[1] && this.pickerSrv.curRangeDate[1].toDateString() === value.toDateString())
? value
: new Date(value.setHours(23, 59, 59));
}
else {
this.pickerSrv.curRangeDate[1] = new Date(value.setHours(23, 59, 59));
}
}
}
else {
this.pickerSrv.curDate = value;
}
}
get selectedRangeDate() {
return this.pickerSrv.curRangeDate;
}
set selectedRangeDate(dateList) {
this.pickerSrv.curRangeDate = dateList;
}
get markDateTemplate() {
return this.pickerSrv.markDateInfoTemplate;
}
constructor(i18n, pickerSrv, dataSrv, cdr, scrollDispatcher) {
this.i18n = i18n;
this.pickerSrv = pickerSrv;
this.dataSrv = dataSrv;
this.cdr = cdr;
this.scrollDispatcher = scrollDispatcher;
this.isWeekSelect = false;
this.currentBodyIndex = 0;
this.calendarItemSize = 186; // 一个月份日历的高度
this.unsubscribe$ = new Subject();
this.allMonthList = [];
this.yearAndMonthList = [];
this.isListCollopse = false;
this.weekHoverRange = [];
this.isSummerTimeZone = false;
}
setI18nText() {
this.i18nText = this.i18n.getI18nText().datePickerPro;
this.i18nSubscription = this.i18n.langChange().pipe(takeUntil(this.unsubscribe$)).subscribe((data) => {
this.i18nText = data.datePickerPro;
this.cdr.detectChanges();
});
}
ngOnInit() {
this.setI18nText();
this.today = new Date();
this.isSummerTimeZone = this.judgeIsSummerTimeZone();
this.initDataList();
this.initObservable();
}
// 判断当前时区是否需要夏令时变换
judgeIsSummerTimeZone() {
const Jan1 = new Date(2023, 0);
const Jul1 = new Date(2023, 6);
// 两个日期之间在非夏令时地区相差181天整
if ((Jul1.getTime() - Jan1.getTime()) / DAY_DURATION !== 181) {
return true;
}
;
return false;
}
initObservable() {
this.pickerSrv.toggleEvent.pipe(takeUntil(this.unsubscribe$)).subscribe(isOpen => {
if (isOpen) {
setTimeout(() => {
this.scrollBodyCmp.checkViewportSize();
this.scrollListCmp.checkViewportSize();
this.goToDate(this.curDate || new Date(), 'auto');
});
// 首次展开添加滚动监听
if (!this.scrollListener) {
this.initScrollListener();
}
}
else {
this.curHoverDate = null;
}
});
this.pickerSrv.updateDateValue.pipe(takeUntil(this.unsubscribe$)).subscribe(res => {
if (this.isRangeType) {
this.updateRangeDate(res.value);
}
else {
this.updateSingleDate(res.value);
}
});
this.pickerSrv.detectedChanges.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
this.cdr.detectChanges();
});
this.pickerSrv.activeInputChange.pipe(takeUntil(this.unsubscribe$)).subscribe(type => {
if (type === 'start') {
this.goToDate(this.selectedRangeDate[0] || this.selectedRangeDate[1] || new Date());
}
else {
if (!this.selectedRangeDate[1] && this.selectedRangeDate[0]) {
this.updateRangeDate([
this.selectedRangeDate[0],
new Date(new Date(this.selectedRangeDate[0].getTime()).setHours(23, 59, 59))
]);
}
this.goToDate(this.selectedRangeDate[1] || this.selectedRangeDate[0] || new Date());
}
});
}
initScrollListener() {
this.scrollDispatcher.scrolled().pipe(takeUntil(this.unsubscribe$), filter((res) => {
return res && res.getElementRef().nativeElement.classList.contains('devui-tbody-wrapper');
}), debounceTime(50)).subscribe(() => {
const offsetY = this.scrollBodyCmp.measureScrollOffset();
// 当滚动超过一个月面板的一半时,就更新月份
this.currentBodyIndex = Math.floor(offsetY / this.calendarItemSize) + (offsetY % this.calendarItemSize > 100 ? 1 : 0);
const listIndex = this.isListCollopse ?
Math.floor(this.currentBodyIndex / 12) : this.currentBodyIndex + Math.floor(this.currentBodyIndex / 12) + 1;
this.goToListByIndex(listIndex);
this.cdr.detectChanges();
});
}
initDataList() {
const key = `${this.pickerSrv.calendarRange.join('-')}-${this.pickerSrv.minDate.toDateString() + this.pickerSrv.maxDate.toDateString()}`;
if (this.dataSrv.calendarDataCache[key]) {
this.yearAndMonthList = this.dataSrv.calendarDataCache[key].yearAndMonthList;
this.allMonthList = this.dataSrv.calendarDataCache[key].allMonthList;
return;
}
this.yearAndMonthList = [];
this.allMonthList = [];
for (let yearIndex = this.pickerSrv.calendarRange[0]; yearIndex <= this.pickerSrv.calendarRange[1]; yearIndex++) {
this.yearAndMonthList.push({
year: yearIndex,
isMonth: false,
active: false
});
for (let monthIndex = 0; monthIndex < 12; monthIndex++) {
this.allMonthList.push({
year: yearIndex,
month: monthIndex,
displayWeeks: this.getDisplayWeeks(yearIndex, monthIndex)
});
this.yearAndMonthList.push({
year: yearIndex,
month: monthIndex,
isMonth: true,
active: false
});
}
}
this.dataSrv.calendarDataCache[key] = {
yearAndMonthList: this.yearAndMonthList,
allMonthList: this.allMonthList
};
}
getDisplayWeeks(yearIndex, monthIndex) {
const firstDayOfMonth = new Date(yearIndex, monthIndex, 1);
const weekOfDay = firstDayOfMonth.getDay();
const startDate = new Date(firstDayOfMonth.getTime() - weekOfDay * DAY_DURATION);
const displayWeeks = [];
for (let i = 0; i < 6; i++) {
const startWeekDate = startDate.getTime() + i * 7 * DAY_DURATION;
const weekDays = new Array(7).fill(0).map((value, index) => {
let currentDate = new Date(startWeekDate + index * DAY_DURATION);
// 夏令时区检测出错误的冬令时时间,加快一小时
if (this.isSummerTimeZone && currentDate.getHours() === 23) {
currentDate = new Date(startWeekDate + index * DAY_DURATION + HOUR_DURATION);
}
return {
day: this.fillLeft(currentDate.getDate()),
date: currentDate,
inMonth: currentDate.getMonth().toString() === monthIndex.toString(),
isToday: currentDate.toDateString() === this.today.toDateString()
};
});
displayWeeks.push(weekDays);
}
return displayWeeks;
}
goToDate(date, scrollBehavior) {
const indexObj = this.getCurrentIndex(date);
const scroll = scrollBehavior || (Math.abs(indexObj.bodyIndex - this.currentBodyIndex) > 18 ? 'auto' : 'smooth');
this.currentBodyIndex = indexObj.bodyIndex;
this.scrollBodyCmp.scrollToIndex(indexObj.bodyIndex, scroll);
this.goToListByIndex(indexObj.listIndex);
this.cdr.detectChanges();
}
goToListByIndex(index) {
const indexDelta = Math.abs(this.scrollListCmp.measureScrollOffset() / 30 - index);
this.scrollListCmp.scrollToIndex(index - 4, indexDelta < 12 ? 'smooth' : 'auto');
this.updateListActive(index);
}
selectMonth(year, month) {
const date = new Date(year, month, 1);
const curYear = this.yearAndMonthList.find(t => t.active)?.year || this.curDate.getFullYear();
// 太远的虚拟滚动会导致白屏,所以超过两年的滚动都直接跳转
const isSmoothAnimation = Math.abs(curYear - year) < 2;
if (this.isListCollopse) {
this.toggleListCollopse(date);
}
else {
this.goToDate(date, isSmoothAnimation ? 'smooth' : 'auto');
}
}
updateRangeDate(dateList) {
if (!dateList) {
this.selectedRangeDate = [];
this.cdr.detectChanges();
return;
}
const curDate = (this.pickerSrv.currentActiveInput === 'start' ?
(dateList[0] || dateList[1]) : (dateList[1] || dateList[0])) || new Date();
const moreThanOneYear = Math.abs(curDate.getFullYear() - (this.currentBodyIndex / 12 + this.pickerSrv.calendarRange[0])) > 1;
this.selectedRangeDate = dateList;
this.goToDate(curDate, moreThanOneYear ? 'auto' : 'smooth');
this.cdr.detectChanges();
}
updateSingleDate(date) {
if (!date) {
this.curDate = null;
this.cdr.detectChanges();
return;
}
const moreThanOneYear = Math.abs(date.getFullYear() - (this.currentBodyIndex / 12 + this.pickerSrv.calendarRange[0])) > 1;
this.curDate = date;
this.goToDate(this.curDate, moreThanOneYear ? 'auto' : 'smooth');
this.cdr.detectChanges();
}
updateListActive(index) {
const curActive = this.yearAndMonthList.find(t => t.active);
if (curActive) {
curActive.active = false;
}
this.yearAndMonthList[index].active = true;
}
getCurrentIndex(curDate) {
const year = curDate.getFullYear();
const month = curDate.getMonth();
const listIndex = this.isListCollopse ?
(year - this.pickerSrv.calendarRange[0]) : (year - this.pickerSrv.calendarRange[0]) * 13 + month + 1;
return {
bodyIndex: (year - this.pickerSrv.calendarRange[0]) * 12 + month,
listIndex
};
}
selectDate(day) {
if (this.isDisabled(day.date) || !day.inMonth) {
return;
}
if (this.isWeekSelect) {
this.pickerSrv.curRangeDate = this.getWeekRange(day.date);
this.pickerSrv.currentActiveInput = 'end';
}
else {
this.curDate = new Date(day.date.setHours(this.pickerSrv.curHour, this.pickerSrv.curMin, this.pickerSrv.curSec));
}
if (this.isRangeType) {
this.pickerSrv.fixRangeDate();
}
this.cdr.detectChanges();
// 非时间模式下选完开始日期跳转到结束日期
if (this.isRangeType && !this.pickerSrv.showTime) {
if (this.pickerSrv.currentActiveInput === 'start') {
this.pickerSrv.currentActiveInput = 'end';
}
else if (this.pickerSrv.currentActiveInput === 'end' && !this.selectedRangeDate[0]) {
this.selectedRangeDate[0] = this.curDate;
this.pickerSrv.currentActiveInput = 'start';
}
else {
this.pickerSrv.closeDropdownEvent.next(false);
}
}
this.pickerSrv.selectedDateChange.next({
type: this.isRangeType ? 'range' : 'single',
value: this.isRangeType ? this.selectedRangeDate : this.curDate
});
if (this.isRangeType && this.pickerSrv.showTime) {
this.pickerSrv.updateTimeChange.next({
activeInput: this.pickerSrv.currentActiveInput,
hour: this.pickerSrv.curHour,
min: this.pickerSrv.curMin,
seconds: this.pickerSrv.curSec
});
}
if (this.pickerSrv.closeAfterSelected) {
this.pickerSrv.closeDropdownEvent.next(false);
}
}
isStartDate(date) {
return this.pickerSrv.isStartDate(date);
}
isDisabled(date) {
return !this.pickerSrv.dateInRange(date);
}
isEndDate(date) {
return this.pickerSrv.isEndDate(date);
}
isDateInRange(date) {
if (this.isWeekSelect) {
return this.isInWeekHoverRange(date);
}
else {
return this.pickerSrv.isDateInRange(date);
}
}
isDateInSelectRange(date) {
return this.pickerSrv.isDateInSelectRange(date);
}
isDateActive(date) {
return this.pickerSrv.isDateActive(date);
}
isActiveTypeDate(date) {
return this.pickerSrv.isActiveInputTypeDate(date);
}
isDateAbandon(date) {
return this.pickerSrv.isDateAbandon(date);
}
isDateSuggest(date) {
return this.pickerSrv.isInSuggestList(date);
}
isDateMarked(date) {
return this.pickerSrv.isMarkedDate(date);
}
isSingleDate() {
if (this.pickerSrv.currentActiveInput === 'start') {
return !this.pickerSrv.curRangeDate[1];
}
else if (this.pickerSrv.currentActiveInput === 'end') {
return !this.pickerSrv.curRangeDate[0];
}
}
setHoverTarget(date, isInMonth) {
if (!isInMonth) {
this.curHoverDate = null;
return;
}
this.curHoverDate = date;
if (this.isWeekSelect) {
this.weekHoverRange = this.getWeekRange(date);
this.curWeekHoverDate = date;
this.cdr.markForCheck();
return;
}
}
getWeekRange(date) {
if (!date) {
return [];
}
const diff = date.getDay() < this.pickerSrv.startIndexOfWeek
? 7 - (this.pickerSrv.startIndexOfWeek - date.getDay())
: date.getDay() - this.pickerSrv.startIndexOfWeek;
const weekStart = new Date(date.getTime() - diff * DAY_DURATION);
const weekEnd = new Date(weekStart.getTime() + DAY_DURATION * 6);
weekEnd.setHours(23, 59, 59);
return [weekStart, weekEnd];
}
isInWeekHoverRange(date) {
const range = this.getWeekRange(this.curWeekHoverDate);
const time = date.getTime();
const timeStr = date.toDateString();
if (this.pickerSrv.isDateActive(date)) {
return false;
}
return ((range[0]?.getTime() < time && time < range[1]?.getTime()) ||
(range[0]?.toDateString() === timeStr || timeStr === ran