@rdkmaster/jigsaw-labs
Version:
Jigsaw, the next generation component set for RDK
848 lines (775 loc) • 32.2 kB
text/typescript
import {
Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Renderer2, Output, forwardRef
} from "@angular/core";
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
import {Subscription} from "rxjs/Subscription";
import {AbstractJigsawComponent} from "../common";
import {TimeGr, TimeService, TimeUnit, TimeWeekStart} from "../../service/time.service";
import {PopupInfo, PopupPositionType, PopupService} from "../../service/popup.service";
import {JigsawSimpleTooltipComponent} from "../tooltip/tooltip";
import {Time, WeekTime} from "../../service/time.types";
import {TranslateHelper} from "../../core/utils/translate-helper";
import {CommonUtils} from "../../core/utils/common-utils";
import {ElementEventHelper, InternalUtils} from "../../core/utils/internal-utils";
import {TranslateService} from "@ngx-translate/core";
/**
* 时间范围生成函数,用于生成自定义的时间范围
*
* $demo = range-time/gr-items
*/
export type TimeShortcutFunction = () => [WeekTime, WeekTime]
/**
* 表示一个自定义的时间范围,一般用于配合`JigsawRangeTime.grItems`属性使用,用于设置某个粒度下快速时间范围选择。
*/
export class Shortcut {
/**
* 国际化提示信息,将被直接显示在界面上
* $demo = range-time/gr-items
*/
label: string;
/**
* 时间范围的起止时间点,可以给出固定值,也可以给一个产生起止时间点的函数
* $demo = range-time/gr-items
*/
dateRange: [WeekTime, WeekTime] | TimeShortcutFunction;
}
/**
* 一个时间粒度
*/
export class GrItem {
/**
* 国际化提示信息,将被直接显示在界面上
*/
label: string;
/**
* 粒度值
*
* $demo = range-time/gr-items
* $demo = time/gr
*/
value: TimeGr;
/**
* 配置当前粒度下,用户能够选择的最大时间跨度。当某些查询请求必须约束用户选择某个范围内的时间时,这个配置项将非常有用。
* 例如查询银行流水时,我们常常被约束最长只能查询3个月的流水等。
*
* 支持时间宏。关于时间宏,请参考这里`TimeUnit`的说明。
*
* $demo = range-time/gr-items
*/
span?: string;
/**
* 给出一组预定义的时间范围,这样用户可以通过这些值快速的设置好待选的时间范围,提高易用性。
* 只在和`JigsawRangeTime`配合使用时才有效
*
* 支持时间宏。关于时间宏,请参考这里`TimeUnit`的说明。
*
* $demo = range-time/gr-items
*/
shortcuts?: Shortcut[];
}
/**
* 用于在界面上提供一个时刻的选择,支持多种时间粒度切换,支持年月日时分秒及其各种组合,如下是一些常见的场景及其建议:
*
* - 如果需要选择的是一个时间范围,则请使用`JigsawRangeTime`;
* - 如果你需要的是一个日历的功能,那请参考[这个demo]($demo=table/calendar),通过表格+渲染器的方式来模拟;
* - 时间选择器常常是收纳到下拉框中以解决视图空间,Jigsaw是通过`JigsawComboSelect`来组合使用的,
* 参考[这个demo]($demo=time/with-combo-select);
*
* 时间控件是对表单友好的,你可以给时间控件编写表单校验器,参考[这个demo]($demo=form/template-driven)。
*
* $demo = time/full
* $demo = time/basic
*/
export class JigsawTime extends AbstractJigsawComponent implements ControlValueAccessor, OnInit, OnDestroy {
public valid: boolean = true;
/**
* 当时间粒度被用户切换之后,Jigsaw会发出此事件。
*
* $demo = time/gr
*
* @type {EventEmitter<TimeGr>}
*/
public grChange = new EventEmitter<TimeGr>();
/**
* @internal
*/
public _$gr: TimeGr = TimeGr.date;
/**
* 时间当前的粒度,在双绑模式下改变这值可以让时间控件更换到对应的粒度。
*
* $demo = time/gr
*
* @return {TimeGr | string}
*/
public get gr(): TimeGr | string {
return this._$gr;
}
//粒度
public set gr(value: TimeGr | string) {
if (typeof value === 'string') {
value = TimeGr[value];
}
if (<TimeGr>value != this._$gr) {
this._$gr = <TimeGr>value;
this._value = TimeService.getFormatDate(this._value, this._$gr);
if (this._timePicker) {
this._initDatePicker();
}
}
}
private _value: Time;
/**
* 当前所选中的时刻,在双绑模式下,更新这个值可以让时间控件选中对应的时刻。
*
* 支持时间宏。关于时间宏,请参考这里`TimeUnit`的说明。
*
* $demo = time/basic
*
* @return {WeekTime}
*/
public get date(): WeekTime {
return this._value ? this._value : TimeService.convertValue(new Date(), <TimeGr>this.gr);
}
public set date(newValue: WeekTime) {
this.writeValue(newValue);
if (newValue && newValue != this._value) {
this._propagateChange(this._value);
}
}
/**
* 当时间被用户切换之后,Jigsaw会发出此事件。
*
* $demo = time/basic
*
* @type {EventEmitter<WeekTime>}
*/
public dateChange = new EventEmitter<WeekTime>();
private _limitEnd: Time;
/**
* 时间控件允许选择的时间截止时刻,默认是无限制的未来。这个约束对所有的粒度都生效。
*
* 支持时间宏。关于时间宏,请参考这里`TimeUnit`的说明。
*
* $demo = time/limit-start
* $demo = time/limit-end
*
* @return {Time}
*/
public get limitEnd(): Time {
return this._limitEnd && TimeService.convertValue(this._limitEnd, <TimeGr>this.gr)
}
public set limitEnd(value: Time) {
if (value) {
this._limitEnd = value;
this._checkMacro();
if (this._timePicker) {
if (this._timePicker.minDate() && this._timePicker.minDate() > TimeService.getDate(this.limitEnd, <TimeGr>this.gr)) {
this._timePicker.minDate(this.limitEnd)
}
this._timePicker.maxDate(this.limitEnd);
this._weekHandle();
this._handleRecommended(this._el.nativeElement, this._popService);
}
}
}
private _limitStart: Time;
/**
* 时间控件允许选择的时间开始时刻,默认是无限制的过去。这个约束对所有的粒度都生效。
*
* 支持时间宏。关于时间宏,请参考这里`TimeUnit`的说明。
*
* $demo = time/limit-start
* $demo = time/limit-end
*
* @return {Time}
*/
public get limitStart(): Time {
return this._limitStart && TimeService.convertValue(this._limitStart, <TimeGr>this.gr);
}
public set limitStart(value: Time) {
if (value) {
this._limitStart = value;
this._checkMacro();
if (this._timePicker) {
if (this._timePicker.maxDate() && this._timePicker.maxDate() < TimeService.getDate(this.limitStart, <TimeGr>this.gr)) {
this._timePicker.maxDate(this.limitStart)
}
this._timePicker.minDate(this.limitStart);
this._weekHandle();
this._handleRecommended(this._el.nativeElement, this._popService);
}
}
}
/**
* 时间刷新的间隔毫秒数,主要针对startDate或endDate设置为now或now-2h等需要不时刷新的场景
*/
private _refreshInterval: number;
/**
* 刷新时间宏的间隔毫秒数,默认不刷新。
*
* 解决的场景是:在界面上弄了个时间选择器,页面打开时默认选中当前时刻,并限制了用户只能选择过去3小时的时间,这很快就可以完成,毫无难度。
* 然而用户使用时是这样的,他打开了页面后,就去处理别的事情去了,几个小时之后再回来想用这个已经打开的页面去查询一些东西,
* 结果发现界面上时间怎么选都不对(因为那个时刻初始化了一次之后就再也没有更新,还停留在几个小时之前),只好刷新页面,用户常常抱怨这一点。
*
* 这个场景下,只要设置一个大于0的数字给时间控件的这个属性即可解决。
*
* $demo = time/refresh-interval
*
* @return {number}
*/
public get refreshInterval(): number {
return this._refreshInterval;
}
public set refreshInterval(value: number) {
if (value || value == 0) {
this._refreshInterval = value;
this._checkMacro();
}
}
private _weekStart: TimeWeekStart;
/**
* 设置周开始日期,可选值 sun mon tue wed thu fri sat,默认值是sun。
*
* $demo = time/week-start
*/
public get weekStart(): string | TimeWeekStart {
return this._weekStart;
}
public set weekStart(value: string | TimeWeekStart) {
if (value) {
if (typeof value === 'string') {
this._weekStart = TimeWeekStart[value];
} else {
this._weekStart = value;
}
if (this._timePicker) {
TimeService.setWeekStart(this._weekStart);
this._initDatePicker();
this._handleRecommended(this._el.nativeElement, this._popService);
}
}
}
/**
* 设置时间控件所支持的粒度。如果你的场景只允许用户选择天、周,则设置了这2个粒度之后,用户无法选择其他的粒度。
*
* $demo = time/gr-items
*/
public grItems: GrItem[];
/**
* 有些时候我们需要提示用户选择那些时间是最佳的,可以通过`recommendedBegin`和`recommendedEnd`来设置。
*
* $demo = time/recommended
*/
public recommendedBegin: Time;
/**
* 有些时候我们需要提示用户选择那些时间是最佳的,可以通过`recommendedBegin`和`recommendedEnd`来设置。
*
* $demo = time/recommended
*/
public recommendedEnd: Time;
/**
* 推荐日期提示标签,默认值是`"推荐日期"`或`"Recommend"`
*/
public recommendedLabel: String;
/**
* time插件容器(jq对象)
*/
private _timePicker: any;
//定时器Id
private _intervalId: number;
private _langChangeSubscriber: Subscription;
constructor(private _el: ElementRef, private _renderer: Renderer2,
private _popService: PopupService, private _translateService: TranslateService) {
super();
this._refreshInterval = 0;
this.weekStart = TimeWeekStart.sun;
this._langChangeSubscriber = TranslateHelper.languageChangEvent.subscribe(
langInfo => this._timePicker && this._timePicker.locale(langInfo.curLang));
InternalUtils.initI18n(_translateService, 'time', {
zh: {recommendedLabel: '推荐日期'},
en: {recommendedLabel: 'Recommend'}
});
_translateService.setDefaultLang(_translateService.getBrowserLang());
}
ngOnInit() {
this._defineLocale();
this._initDatePicker();
this._checkMacro();
}
private _defineLocale() {
moment.defineLocale('zh', {
months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'),
weekdaysMin: '日_一_二_三_四_五_六'.split('_'),
longDateFormat: {
LT: 'HH:mm',
LTS: 'HH:mm:ss',
L: 'YYYY年MMMD日',
LL: 'YYYY年MMMD日',
LLL: 'YYYY年MMMD日Ah点mm分',
LLLL: 'YYYY年MMMD日ddddAh点mm分',
l: 'YYYY年MMMD日',
ll: 'YYYY年MMMD日',
lll: 'YYYY年MMMD日 HH:mm',
llll: 'YYYY年MMMD日dddd HH:mm'
},
meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
meridiemHour: function (hour, meridiem) {
if (hour === 12) {
hour = 0;
}
if (meridiem === '凌晨' || meridiem === '早上' ||
meridiem === '上午') {
return hour;
} else if (meridiem === '下午' || meridiem === '晚上') {
return hour + 12;
} else {
// '中午'
return hour >= 11 ? hour : hour + 12;
}
},
meridiem: function (hour, minute, isLower) {
let hm = hour * 100 + minute;
if (hm < 600) {
return '凌晨';
} else if (hm < 900) {
return '早上';
} else if (hm < 1130) {
return '上午';
} else if (hm < 1230) {
return '中午';
} else if (hm < 1800) {
return '下午';
} else {
return '晚上';
}
},
calendar: {
sameDay: '[今天]LT',
nextDay: '[明天]LT',
nextWeek: '[下]ddddLT',
lastDay: '[昨天]LT',
lastWeek: '[上]ddddLT',
sameElse: 'L'
},
dayOfMonthOrdinalParse: /\d{1,2}([日月周])/,
ordinal: function (number, period) {
switch (period) {
case 'd':
case 'D':
case 'DDD':
return number + '日';
case 'M':
return number + '月';
case 'w':
case 'W':
return number + '周';
default:
return number;
}
},
relativeTime: {
future: '%s内',
past: '%s前',
s: '几秒',
m: '1 分钟',
mm: '%d 分钟',
h: '1 小时',
hh: '%d 小时',
d: '1 天',
dd: '%d 天',
M: '1 个月',
MM: '%d 个月',
y: '1 年',
yy: '%d 年'
},
week: {
// GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效
dow: 1, // Monday is the first day of the week.
doy: 4 // The week that contains Jan 4th is the first week of the year.
}
});
}
ngOnDestroy() {
window.clearInterval(this._intervalId);
super.ngOnDestroy();
this._destroyPicker();
this._langChangeSubscriber.unsubscribe();
}
private _destroyPicker() {
if (this._timePicker) {
this._timePicker.destroy();
}
}
private _initDatePicker() {
const insert = this._el.nativeElement.querySelector(".jigsaw-time-box");
TimeService.setWeekStart(this._weekStart);
let [result, isChange] = this._handleValue(<Time>this.date);
if (isChange) {
this._value = result;
}
this._destroyPicker();
const picker = $(insert).datetimepicker({
inline: true,
defaultDate: TimeService.getDate(<string>this.date, <TimeGr>this.gr),
format: TimeService.getFormatter(<TimeGr>this.gr),
minDate: this._limitStart && TimeService.getDate(<string>this.limitStart, <TimeGr>this.gr),
maxDate: this._limitEnd && TimeService.getDate(<string>this.limitEnd, <TimeGr>this.gr)
});
picker.off('dp.change');
picker.on("dp.change", (e) => {
let changeValue = TimeService.getFormatDate(e.date, <TimeGr>this.gr);
if (this.date != changeValue) {
this._handleValueChange(changeValue, <TimeGr>this.gr);
}
this._bindActiveDayClickHandler(picker);
// 选择了日期,让recommend的tooltip的销毁
if (this._tooltipInfo) {
this._tooltipInfo.dispose();
this._tooltipInfo = null;
}
});
picker.on("dp.update", () => {
// Fired (in most cases) when the viewDate changes. E.g. Next and Previous buttons, selecting a year.
this._weekHandle();
this._handleRecommended(this._el.nativeElement, this._popService);
});
// 点击day.active会重新渲染day table,但不会触发dp.change,此函数用于填补日期插件的坑
this._bindActiveDayClickHandler(picker);
this._timePicker = $(insert).data("DateTimePicker");
this._timePicker.locale(this._translateService.currentLang);
this._handleValueChange(<Time>this.date, <TimeGr>this.gr, true);
}
private _bindActiveDayClickHandler(picker) {
// 等待day.active刷新出来
this.callLater(() => {
picker.find('.datepicker-days table tbody tr td.day.active').on('click', () => {
// 等待点击后的day-btn刷新出来
this.callLater(() => {
// week select
this._weekHandle();
// recommend select
this._handleRecommended(this._el.nativeElement, this._popService);
this._bindActiveDayClickHandler(picker);
});
});
});
}
//设置插件选中时间值
private _setDate(value: Time) {
if (this._timePicker) {
this._handleValueChange(value, <TimeGr>this.gr);
this._timePicker.date(TimeService.getFormatDate(value, <TimeGr>this.gr));
this._weekHandle();
this._handleRecommended(this._el.nativeElement, this._popService);
}
}
/**
* @internal
*/
public _$changeGranularity(select: GrItem) {
this.gr = select.value;
this.grChange.emit(this.gr);
}
private _checkMacro() {
if (this._intervalId) {
window.clearInterval(this._intervalId);
}
if ((TimeService.isMacro(<string>this._limitStart) || TimeService.isMacro(<string>this._limitEnd)) && this._refreshInterval != 0) {
this._intervalId = window.setInterval(() => {
this._handleLimitStartAndEnd();
}, this._refreshInterval);
}
}
private _handleLimitStartAndEnd() {
if (this._timePicker) {
this._limitStart && this._timePicker.minDate(TimeService.addDate(<string>this.limitStart, -1, TimeUnit.s));
this._limitEnd && this._timePicker.maxDate(TimeService.addDate(<string>this.limitEnd, 1, TimeUnit.s));
this._weekHandle();
this._handleRecommended(this._el.nativeElement, this._popService);
}
}
private _weekHandle() {
if (this.gr == TimeGr.week) {
this._handleWeekSelect();
}
}
private _handleValueChange(changeValue: Time, gr: TimeGr, emit?: boolean) {
if (this.date != changeValue || emit) {
this._value = changeValue;
this.callLater(() => {
const val = gr == TimeGr.week ? this._handleWeekSelect() : this._value;
this.dateChange.emit(val);
this._propagateChange(val);
});
this._handleRecommended(this._el.nativeElement, this._popService);
}
}
private _handleValue(value: Time): [Time, boolean] {
if (this._limitStart && value < this.limitStart) {
return [this.limitStart, true];
}
if (this._limitEnd && value > this.limitEnd) {
return [this.limitEnd, true];
}
return [value, false];
}
private _handleWeekSelect() {
let weekNum = TimeService.getWeekOfYear(<string>this.date);
let year = TimeService.getYear(<string>this.date);
const tdActive = this._el.nativeElement.querySelector(".jigsaw-time-box .datepicker .datepicker-days>table>tbody>tr>td.active");
if (tdActive) {
tdActive.parentNode.classList.add("active");
}
return {year: year, week: weekNum};
}
private _tooltipInfo: PopupInfo;
private _eventHelper: ElementEventHelper = new ElementEventHelper();
private _handleRecommended(nativeElement: any, popService: PopupService) {
if (this.recommendedBegin && this.recommendedEnd) {
this.recommendedBegin = TimeService.getFormatDate(this.recommendedBegin);
this.recommendedEnd = TimeService.getFormatDate(this.recommendedEnd);
if (TimeService.getYear(<string>this.recommendedBegin) != TimeService.getYear(<string>this.recommendedEnd)) { //不支持跨年设置
throw "recommended not support different year times!";
}
const monthsNode: HTMLElement = JigsawTime._getDataPickerNode("months", nativeElement);
const monthsHeadNode: HTMLElement = JigsawTime._getDataPickerNode("months", nativeElement, true);
JigsawTime._searchDateForMonth(this.recommendedBegin, this.recommendedEnd, monthsNode, monthsHeadNode);
const daysNode = JigsawTime._getDataPickerNode("days", nativeElement);
const daysHeadNode: HTMLElement = JigsawTime._getDataPickerNode("days", nativeElement, true);
const daysObj = JigsawTime._parseDay(daysHeadNode.innerText);
JigsawTime._searchDateForDay(this.recommendedBegin, this.recommendedEnd, daysNode, daysObj);
nativeElement.querySelectorAll(".jigsaw-time-box .datepicker .expect-day").forEach(node => {
// #239 移除已经注册的事件. 点击事件会触发此操作, 造成重复注册事件. 引起tooltips 不能销毁.
const removeMouseEnterListeners = this._eventHelper.get(node, 'mouseenter');
if (removeMouseEnterListeners instanceof Array) {
removeMouseEnterListeners.forEach(removeMouseenterListener => {
removeMouseenterListener();
this._eventHelper.del(node, 'mouseenter', removeMouseenterListener);
})
}
const removeMouseLeaveListeners = this._eventHelper.get(node, 'mouseleave');
if (removeMouseLeaveListeners instanceof Array) {
removeMouseLeaveListeners.forEach(removeMouseleaveListener => {
removeMouseleaveListener();
this._eventHelper.del(node, 'mouseleave', removeMouseleaveListener);
})
}
const removeMouseEnterListener = this._renderer.listen(node, "mouseenter", (event) => {
if (this._tooltipInfo) {
this._tooltipInfo.dispose();
this._tooltipInfo = null;
}
this._tooltipInfo = popService.popup(JigsawSimpleTooltipComponent, {
modal: false, //是否模态
pos: {x: $(event.currentTarget).offset().left, y: $(event.currentTarget).offset().top},
posOffset: { //偏移位置
top: -40,
left: 0
},
posType: PopupPositionType.absolute, //定位类型
}, {
message: this.recommendedLabel || this._translateService.instant('time.recommendedLabel')
});
});
this._eventHelper.put(node, "mouseenter", removeMouseEnterListener);
const removeMouseleaveListener = this._renderer.listen(node, "mouseleave", () => {
if (this._tooltipInfo) {
this._tooltipInfo.dispose();
this._tooltipInfo = null;
}
});
this._eventHelper.put(node, "mouseleave", removeMouseleaveListener);
});
}
}
private static _searchDateForDay(begin: Time, end: Time, sourceNodes: HTMLElement[], headObj: any) {
const startMonth = TimeService.getMonth(begin);
const endMonth = TimeService.getMonth(end);
const startDate = TimeService.getDay(begin);
const endDate = TimeService.getDay(end);
if (TimeService.getYear(begin) == headObj.year &&
(startMonth == headObj.month || endMonth == headObj.month)) {
sourceNodes.forEach(node => {
const text = +node.innerText;
if (startMonth != endMonth) {
if (!node.classList.contains("old") && !node.classList.contains("new")) {
if ((startMonth == headObj.month && text >= startDate) ||
(endMonth == headObj.month && text <= endDate)) {
node.classList.add("expect-day");
}
if (text == startDate) {
node.classList.add("border-left");
}
if (text == endDate) {
node.classList.add("border-right");
}
} else if (node.classList.contains("new")) {
if (startMonth == headObj.month && text <= endDate) {
node.classList.add("expect-day");
}
if (text == endDate) {
node.classList.add("border-right");
}
} else if (node.classList.contains("old")) {
if (endMonth == headObj.month && text >= startDate) {
node.classList.add("expect-day");
}
}
} else {
if (!node.classList.contains("old") && !node.classList.contains("new")) {
if (text >= startDate && text <= endDate) {
node.classList.add("expect-day");
}
if (text == startDate) {
node.classList.add("border-left");
}
if (text == endDate) {
node.classList.add("border-right");
}
}
}
})
}
}
private static _parseDay(val: string) {
const charToNum = {一: 1, 二: 2, 三: 3, 四: 4, 五: 5, 六: 6, 七: 7, 八: 8, 九: 9, 十: 10, 十一: 11, 十二: 12};
const enUsToNum = {
January: 1,
February: 2,
March: 3,
April: 4,
May: 5,
June: 6,
July: 7,
August: 8,
September: 9,
October: 10,
November: 11,
December: 12
};
let result = {};
if (val.indexOf("月") == -1) {
const valArr = val.split(/\s+/);
result["month"] = +enUsToNum[valArr[0]];
result["year"] = +valArr[1];
} else {
const valArr = val.split("月");
result["month"] = charToNum[valArr[0].trim()];
result["year"] = +(valArr[1].trim());
}
return result;
}
private static _parseMonth(val: string) {
const enUsSimpleToNum = {
Jan: 1,
Feb: 2,
Mar: 3,
Apr: 4,
May: 5,
Jun: 6,
Jul: 7,
Aug: 8,
Sep: 9,
Oct: 10,
Nov: 11,
Dec: 12
};
if (val.indexOf("月") == -1) {
return enUsSimpleToNum[val];
} else {
return val.replace("月", '');
}
}
private static _searchDateForMonth(begin: Time, end: Time, sourceNodes: any, headNode: any) {
const startMonth = TimeService.getMonth(begin);
const endMonth = TimeService.getMonth(end);
if (TimeService.getYear(begin) == headNode.innerText) {
sourceNodes.forEach(node => {
if (!node.classList.contains("disabled")) {
const month = JigsawTime._parseMonth(node.innerText);
if (month >= startMonth && month <= endMonth) {
node.classList.add("expect-day");
}
if (month == startMonth) {
node.classList.add("border-left");
}
if (month == endMonth) {
node.classList.add("border-right");
}
}
})
}
}
private static _getDataPickerNode(granularity: string, nativeElement: any, isHead?: boolean) {
const selectorBefore: string = ".jigsaw-time-box .datepicker .datepicker-";
const selectorAfter: string = ">table>tbody>tr>";
let nodeName = "";
if (granularity == "years" || granularity == "months") {
nodeName = "td>span:not(.disabled)";
} else {
nodeName = "td:not(.disabled)";
}
let selector = selectorBefore + granularity + selectorAfter + nodeName;
if (isHead) {
const theadNode = ">table>thead>tr>th.picker-switch[colspan]";
selector = selectorBefore + granularity + theadNode;
return nativeElement.querySelector(selector);
}
return nativeElement.querySelectorAll(selector);
}
private _propagateChange:any = () => {};
public writeValue(newValue: any): void {
if (!newValue || newValue == this._value) {
// 此处也会过滤掉newValue是格式化过的,并且与_value相等的情况
return;
}
newValue = TimeService.convertValue(newValue, <TimeGr>this.gr);
if (newValue == this._value) {
// 此处把newValue格式化后,与_value比较,过滤掉相等的情况
return;
}
if (this._value && this.gr == TimeGr.week) {
let newValueYear = TimeService.getYear(<string>newValue);
let valueYear = TimeService.getYear(<string>this._value);
let newValueWeek = TimeService.getWeekOfYear(<string>newValue);
let valueWeek = TimeService.getWeekOfYear(<string>this._value);
if (newValueYear == valueYear && newValueWeek == valueWeek) return;
}
let [value,] = this._handleValue(newValue);
this._setDate(value);
this._value = newValue;
}
public registerOnChange(fn: any): void {
this._propagateChange = fn;
}
public registerOnTouched(fn: any): void {
}
}