Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(module:date-picker): will not sort range date #5812

Merged
merged 2 commits into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion components/core/time/candy-date.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CandyDate } from './candy-date';
import { CandyDate, normalizeRangeValue, SingleValue } from './candy-date';

describe('candy-date coverage supplements', () => {
const date = new CandyDate('2018-5-5 12:12:12');
Expand Down Expand Up @@ -83,4 +83,29 @@ describe('candy-date coverage supplements', () => {
const errorMessage = 'The input date type is not supported ("Date" is now recommended)';
expect(() => new CandyDate({} as any)).toThrowError(errorMessage); // tslint:disable-line:no-any
});

it('should normalizeRangeValue work', () => {
const randomDay = new CandyDate('2020-09-17');
const now = new Date();
let result: SingleValue[];
result = normalizeRangeValue([null, randomDay], false);
expect(result[0]!.getMonth()).toEqual(7);
expect(result[1]!.getMonth()).toEqual(8);

result = normalizeRangeValue([randomDay, null], false);
expect(result[0]!.getMonth()).toEqual(8);
expect(result[1]!.getMonth()).toEqual(9);

result = normalizeRangeValue([null, null], false);
expect(result[0]!.getMonth()).toEqual(now.getMonth());
expect(result[1]!.getMonth()).toEqual(now.getMonth() + 1);

result = normalizeRangeValue([new CandyDate(), new CandyDate()], false);
expect(result[0]!.getMonth()).toEqual(now.getMonth());
expect(result[1]!.getMonth()).toEqual(now.getMonth() + 1);

result = normalizeRangeValue([new CandyDate(), new CandyDate()], true);
expect(result[0]!.getMonth()).toEqual(now.getMonth());
expect(result[1]!.getMonth()).toEqual(now.getMonth());
});
}); // /candy-date coverage supplements
30 changes: 19 additions & 11 deletions components/core/time/candy-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,32 @@ import startOfWeek from 'date-fns/startOfWeek';
import { warn } from 'ng-zorro-antd/core/logger';
import { IndexableObject, NzSafeAny } from 'ng-zorro-antd/core/types';

type CandyDateCompareGrain = 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second';

export type WeekDayIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6;
export type CandyDateCompareGrain = 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second';
export type CandyDateType = CandyDate | Date | null;
export type SingleValue = CandyDate | null;
export type CompatibleValue = SingleValue | SingleValue[];

export function sortRangeValue(rangeValue: SingleValue[]): SingleValue[] {
if (Array.isArray(rangeValue)) {
const [start, end] = rangeValue;
return start && end && start.isAfterSecond(end) ? [end, start] : [start, end];
}
return rangeValue;
export function wrongSortOrder(rangeValue: SingleValue[]): boolean {
const [start, end] = rangeValue;
return !!start && !!end && start.isAfterSecond(end);
}

export function normalizeRangeValue(value: SingleValue[]): CandyDate[] {
const [start, end] = value || [];
const newStart = start || new CandyDate();
const newEnd = end?.isSameMonth(newStart) ? end.addMonths(1) : end || newStart.addMonths(1);
export function normalizeRangeValue(value: SingleValue[], allowSameMonth: boolean): CandyDate[] {
const [start, end] = value;
let newStart: CandyDate = start || new CandyDate();
let newEnd: CandyDate = end || new CandyDate();
if (start && !end) {
newStart = start;
newEnd = start.addMonths(1);
} else if (!start && end) {
newStart = end.addMonths(-1);
newEnd = end;
}
if (newEnd.isSameMonth(newStart) && !allowSameMonth) {
newEnd = newStart.addMonths(1);
}
return [newStart, newEnd];
}

Expand Down
6 changes: 3 additions & 3 deletions components/date-picker/date-picker.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class DatePickerService implements OnDestroy {

hasValue(value: CompatibleValue = this.value): boolean {
if (Array.isArray(value)) {
return !!value[0] && !!value[1];
return !!value[0] || !!value[1];
} else {
return !!value;
}
Expand All @@ -47,9 +47,9 @@ export class DatePickerService implements OnDestroy {
}
}

setActiveDate(value: CompatibleValue, normalize: boolean = false): void {
setActiveDate(value: CompatibleValue, allowSameMonth: boolean = false): void {
if (this.isRange) {
this.activeDate = normalize ? normalizeRangeValue(value as CandyDate[]) : value;
this.activeDate = normalizeRangeValue(value as CandyDate[], allowSameMonth);
} else {
this.activeDate = cloneDate(value);
}
Expand Down
79 changes: 41 additions & 38 deletions components/date-picker/date-range-popup.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
ViewEncapsulation
} from '@angular/core';

import { CandyDate, cloneDate, CompatibleValue, SingleValue, sortRangeValue } from 'ng-zorro-antd/core/time';
import { CandyDate, cloneDate, CompatibleValue, SingleValue, wrongSortOrder } from 'ng-zorro-antd/core/time';
import { FunctionProp } from 'ng-zorro-antd/core/types';
import { NzCalendarI18nInterface } from 'ng-zorro-antd/i18n';
import { Subject } from 'rxjs';
Expand Down Expand Up @@ -152,6 +152,7 @@ export class DateRangePopupComponent implements OnInit, OnChanges, OnDestroy {
endPanelMode: NzDateMode | NzDateMode[] = 'date';
timeOptions: SupportTimeOptions | SupportTimeOptions[] | null = null;
hoverValue: SingleValue[] = []; // Range ONLY
checkedPartArr: boolean[] = [false, false];
destroy$ = new Subject();

get hasTimePicker(): boolean {
Expand All @@ -166,7 +167,7 @@ export class DateRangePopupComponent implements OnInit, OnChanges, OnDestroy {

ngOnInit(): void {
this.datePickerService.valueChange$.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.initActiveDate();
this.updateActiveDate();
this.cdr.markForCheck();
});
}
Expand All @@ -182,7 +183,7 @@ export class DateRangePopupComponent implements OnInit, OnChanges, OnDestroy {
this.endPanelMode = this.panelMode;
}
if (changes.defaultPickerValue) {
this.initActiveDate();
this.updateActiveDate();
}
}

Expand All @@ -191,11 +192,11 @@ export class DateRangePopupComponent implements OnInit, OnChanges, OnDestroy {
this.destroy$.complete();
}

initActiveDate(): void {
updateActiveDate(): void {
const activeDate = this.datePickerService.hasValue()
? this.datePickerService.value
: this.datePickerService.makeValue(this.defaultPickerValue!);
this.datePickerService.setActiveDate(activeDate, !this.showTime);
this.datePickerService.setActiveDate(activeDate, this.hasTimePicker);
}

onClickOk(): void {
Expand Down Expand Up @@ -237,19 +238,16 @@ export class DateRangePopupComponent implements OnInit, OnChanges, OnDestroy {
} else {
this.panelMode = mode;
}
// this.cdr.markForCheck();
this.panelModeChange.emit(this.panelMode);
}

onActiveDateChange(value: CandyDate, partType: RangePartType): void {
if (this.isRange) {
if (partType === 'left') {
this.datePickerService.activeDate = [value, value.addMonths(1)];
} else {
this.datePickerService.activeDate = [value.addMonths(-1), value];
}
const activeDate: SingleValue[] = [];
activeDate[this.datePickerService.getActiveIndex(partType)] = value;
this.datePickerService.setActiveDate(activeDate, this.hasTimePicker);
} else {
this.datePickerService.activeDate = value;
this.datePickerService.setActiveDate(value);
}
}

Expand All @@ -269,51 +267,56 @@ export class DateRangePopupComponent implements OnInit, OnChanges, OnDestroy {

changeValueFromSelect(value: CandyDate, emitValue: boolean = true): void {
if (this.isRange) {
let selectedValue: SingleValue[] = cloneDate(this.datePickerService.value) as CandyDate[];
let otherPart: RangePartType;
if (this.datePickerService.activeInput === 'left') {
otherPart = 'right';
selectedValue[0] = value;
} else {
otherPart = 'left';
selectedValue[1] = value;
}
const selectedValue: SingleValue[] = cloneDate(this.datePickerService.value) as CandyDate[];
const checkedPart: RangePartType = this.datePickerService.activeInput;
const otherPart = this.reversedPart(checkedPart);

selectedValue = sortRangeValue(selectedValue);
selectedValue[this.datePickerService.getActiveIndex(checkedPart)] = value;
this.checkedPartArr[this.datePickerService.getActiveIndex(checkedPart)] = true;
this.hoverValue = selectedValue;
this.datePickerService.setValue(selectedValue);
this.datePickerService.setActiveDate(selectedValue, !this.showTime);
this.datePickerService.inputPartChange$.next();

if (!this.isAllowed(selectedValue)) {
return;
}

if (emitValue) {
// If the other input has value
if (this.isBothAllowed(selectedValue)) {
/**
* if sort order is wrong, clear the other part's value
*/
if (wrongSortOrder(selectedValue)) {
// selectedValue = sortRangeValue(selectedValue);
selectedValue[this.datePickerService.getActiveIndex(otherPart)] = null;
this.checkedPartArr[this.datePickerService.getActiveIndex(otherPart)] = false;
}

this.datePickerService.setValue(selectedValue);

/**
* range date usually selected paired,
* so we emit the date value only both date is allowed and both part are checked
*/
if (this.isBothAllowed(selectedValue) && this.checkedPartArr[0] && this.checkedPartArr[1]) {
this.calendarChange.emit(selectedValue);
this.clearHoverValue();
this.datePickerService.emitValue$.next();
} else {
} else if (this.isAllowed(selectedValue)) {
this.calendarChange.emit([value.clone()]);
this.datePickerService.inputPartChange$.next(otherPart!);
this.datePickerService.inputPartChange$.next(otherPart);
}
} else {
this.datePickerService.setValue(selectedValue);
this.datePickerService.inputPartChange$.next();
}
} else {
this.datePickerService.setValue(value);
this.datePickerService.setActiveDate(value, !this.showTime);
this.datePickerService.inputPartChange$.next();

if (!this.isAllowed(value)) {
return;
}
if (emitValue) {
if (emitValue && this.isAllowed(value)) {
this.datePickerService.emitValue$.next();
}
}
}

reversedPart(part: RangePartType): RangePartType {
return part === 'left' ? 'right' : 'left';
}

getPanelMode(panelMode: NzDateMode | NzDateMode[], partType?: RangePartType): NzDateMode {
if (this.isRange) {
return panelMode[this.datePickerService.getActiveIndex(partType)] as NzDateMode;
Expand Down
36 changes: 21 additions & 15 deletions components/date-picker/picker.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { ESCAPE } from '@angular/cdk/keycodes';
import {
CdkConnectedOverlay,
CdkOverlayOrigin,
Expand Down Expand Up @@ -36,8 +37,7 @@ import {
} from '@angular/core';
import { slideMotion } from 'ng-zorro-antd/core/animation';

import { ESCAPE } from '@angular/cdk/keycodes';
import { CandyDate, CompatibleValue } from 'ng-zorro-antd/core/time';
import { CandyDate, CompatibleValue, wrongSortOrder } from 'ng-zorro-antd/core/time';
import { NgStyleInterface, NzSafeAny } from 'ng-zorro-antd/core/types';
import { DateHelperService } from 'ng-zorro-antd/i18n';
import { fromEvent, Subject } from 'rxjs';
Expand Down Expand Up @@ -179,8 +179,8 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe
@ViewChild(CdkConnectedOverlay, { static: false }) cdkConnectedOverlay?: CdkConnectedOverlay;
@ViewChild('separatorElement', { static: false }) separatorElement?: ElementRef;
@ViewChild('pickerInput', { static: false }) pickerInput?: ElementRef<HTMLInputElement>;
@ViewChildren('rangePickerInput') rangePickerInputs!: QueryList<ElementRef<HTMLInputElement>>;
@ContentChild(DateRangePopupComponent) panel!: DateRangePopupComponent;
@ViewChildren('rangePickerInput') rangePickerInputs?: QueryList<ElementRef<HTMLInputElement>>;
@ContentChild(DateRangePopupComponent) panel?: DateRangePopupComponent;

origin: CdkOverlayOrigin;
document: Document;
Expand All @@ -189,8 +189,7 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe
arrowLeft?: number;
destroy$ = new Subject();
prefixCls = PREFIX_CLASS;
// Index signature in type 'string | string[]' only permits reading
inputValue: NzSafeAny = '';
inputValue!: NzSafeAny;
activeBarStyle: object = { position: 'absolute' };
animationOpenState = false;
overlayOpen: boolean = false; // Available when "open"=undefined
Expand Down Expand Up @@ -250,7 +249,7 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe

ngOnInit(): void {
this.inputSize = Math.max(10, this.format.length) + 2;

this.inputValue = this.isRange ? ['', ''] : '';
this.datePickerService.valueChange$.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.updateInputValue();
});
Expand Down Expand Up @@ -280,9 +279,7 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe
...this.datePickerService.arrowPositionStyle,
width: `${this.inputWidth}px`
};
if (this.document.activeElement !== this.getInput(this.datePickerService.activeInput)) {
this.focus();
}
this.focus();
this.panel?.cdr.markForCheck();
this.cdr.markForCheck();
});
Expand All @@ -304,16 +301,19 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe
this.arrowLeft = this.inputWidth + this.separatorElement?.nativeElement.offsetWidth || 0;
}

getInput(partType?: RangePartType): HTMLInputElement {
getInput(partType?: RangePartType): HTMLInputElement | undefined {
return this.isRange
? partType === 'left'
? this.rangePickerInputs.first.nativeElement
: this.rangePickerInputs.last.nativeElement
? this.rangePickerInputs?.first.nativeElement
: this.rangePickerInputs?.last.nativeElement
: this.pickerInput!.nativeElement;
}

focus(): void {
this.getInput(this.datePickerService.activeInput).focus(); // Focus on the first input
const activeInputElement = this.getInput(this.datePickerService.activeInput);
if (this.document.activeElement !== activeInputElement) {
activeInputElement?.focus();
}
}

onFocus(partType?: RangePartType): void {
Expand Down Expand Up @@ -359,7 +359,13 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe
}

onClickBackdrop(): void {
if (this.panel.isAllowed(this.datePickerService.value!, true)) {
if (this.panel?.isAllowed(this.datePickerService.value!, true)) {
if (Array.isArray(this.datePickerService.value) && wrongSortOrder(this.datePickerService.value)) {
const index = this.datePickerService.getActiveIndex(this.datePickerService.activeInput);
const value = this.datePickerService.value[index];
this.panel?.changeValueFromSelect(value!, true);
return;
}
this.updateInputValue();
this.datePickerService.emitValue$.next();
} else {
Expand Down
Loading