Skip to content

Commit 8e570ca

Browse files
committed
Merge branch 'mpopov/bootstrap-dialog' of github.com:IgniteUI/igniteui-angular into mpopov/bootstrap-dialog
2 parents 84b3780 + 1c756e7 commit 8e570ca

16 files changed

+871
-820
lines changed

projects/igniteui-angular/src/lib/date-picker/date-picker.utils.ts

Lines changed: 81 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,13 @@ export const enum DateState {
1111
Invalid = 'invalid',
1212
}
1313

14-
/**
15-
* @hidden
16-
*/
14+
/** @hidden */
1715
const enum FormatDesc {
1816
Numeric = 'numeric',
1917
TwoDigits = '2-digit'
2018
}
2119

22-
/**
23-
* @hidden
24-
*/
20+
/** @hidden */
2521
const enum DateChars {
2622
YearChar = 'y',
2723
MonthChar = 'M',
@@ -31,25 +27,32 @@ const enum DateChars {
3127
const DATE_CHARS = ['h', 'H', 'm', 's', 'S', 't', 'T'];
3228
const TIME_CHARS = ['d', 'D', 'M', 'y', 'Y'];
3329

34-
/**
35-
* @hidden
36-
*/
30+
/** @hidden */
3731
const enum DateParts {
3832
Day = 'day',
3933
Month = 'month',
4034
Year = 'year'
4135
}
4236

43-
/**
44-
* @hidden
45-
*/
37+
38+
/** @hidden */
4639
export abstract class DatePickerUtil {
40+
public static readonly DEFAULT_INPUT_FORMAT = 'MM/dd/yyyy';
41+
// TODO: this is the def mask for the date-picker, should remove it during refactoring
4742
private static readonly SHORT_DATE_MASK = 'MM/dd/yy';
4843
private static readonly SEPARATOR = 'literal';
4944
private static readonly NUMBER_OF_MONTHS = 12;
5045
private static readonly PROMPT_CHAR = '_';
5146
private static readonly DEFAULT_LOCALE = 'en';
5247

48+
49+
50+
/**
51+
* TODO: Unit tests for all public methods.
52+
*/
53+
54+
55+
5356
/**
5457
* Parse a Date value from masked string input based on determined date parts
5558
* @param inputData masked value to parse
@@ -92,20 +95,6 @@ export abstract class DatePickerUtil {
9295
);
9396
}
9497

95-
private static ensureLeadingZero(part: DatePartInfo) {
96-
switch (part.type) {
97-
case DatePart.Date:
98-
case DatePart.Month:
99-
case DatePart.Hours:
100-
case DatePart.Minutes:
101-
case DatePart.Seconds:
102-
if (part.format.length === 1) {
103-
part.format = part.format.repeat(2);
104-
}
105-
break;
106-
}
107-
}
108-
10998
/**
11099
* Parse the mask into date/time and literal parts
111100
*/
@@ -256,6 +245,72 @@ export abstract class DatePickerUtil {
256245
return newDate;
257246
}
258247

248+
/**
249+
* Determines whether the provided value is less than the provided min value.
250+
* @param includeTime set to false if you want to exclude time portion of the two dates
251+
* @param includeDate set to false if you want to exclude the date portion of the two dates
252+
*/
253+
public static greaterThanMaxValue(value: Date, maxValue: Date, includeTime = true, includeDate = true): boolean {
254+
if (includeTime && includeDate) {
255+
return value.getTime() > maxValue.getTime();
256+
}
257+
258+
let _value = new Date(value.getTime());
259+
let _maxValue = new Date(maxValue.getTime());
260+
if (includeDate) {
261+
_value.setHours(0, 0, 0, 0);
262+
_maxValue.setHours(0, 0, 0, 0);
263+
return _value.getTime() > maxValue.getTime();
264+
}
265+
if (includeTime) {
266+
_value = new Date(0, 0, 0, _value.getHours(), _value.getMinutes(), _value.getSeconds());
267+
_maxValue = new Date(0, 0, 0, _maxValue.getHours(), _maxValue.getMinutes(), _maxValue.getSeconds());
268+
return _value.getTime() > _maxValue.getTime();
269+
}
270+
271+
// throw?
272+
}
273+
274+
/**
275+
* Determines whether the provided value is greater than the provided min value.
276+
* @param includeTime set to false if you want to exclude time portion of the two dates
277+
* @param includeDate set to false if you want to exclude the date portion of the two dates
278+
*/
279+
public static lessThanMinValue(value: Date, minValue: Date, includeTime = true, includeDate = true): boolean {
280+
if (includeTime && includeDate) {
281+
return value.getTime() < minValue.getTime();
282+
}
283+
284+
let _value = new Date(value.getTime());
285+
let _minValue = new Date(minValue.getTime());
286+
if (includeDate) {
287+
_value.setHours(0, 0, 0, 0);
288+
_minValue.setHours(0, 0, 0, 0);
289+
return _value.getTime() < _minValue.getTime();
290+
}
291+
if (includeTime) {
292+
_value = new Date(0, 0, 0, _value.getHours(), _value.getMinutes(), _value.getSeconds());
293+
_minValue = new Date(0, 0, 0, _minValue.getHours(), _minValue.getMinutes(), _minValue.getSeconds());
294+
return _value.getTime() > _minValue.getTime();
295+
}
296+
297+
// throw?
298+
}
299+
300+
private static ensureLeadingZero(part: DatePartInfo) {
301+
switch (part.type) {
302+
case DatePart.Date:
303+
case DatePart.Month:
304+
case DatePart.Hours:
305+
case DatePart.Minutes:
306+
case DatePart.Seconds:
307+
if (part.format.length === 1) {
308+
part.format = part.format.repeat(2);
309+
}
310+
break;
311+
}
312+
}
313+
259314
private static getCleanVal(inputData: string, datePart: DatePartInfo, promptChar?: string): string {
260315
return DatePickerUtil.trimEmptyPlaceholders(inputData.substring(datePart.start, datePart.end), promptChar);
261316
}

projects/igniteui-angular/src/lib/date-range-picker/date-range-picker.component.spec.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,6 @@ describe('IgxDateRangePicker', () => {
4545
expect(dateRange.value.end).toEqual(startDate);
4646
});
4747

48-
it('should set range dates correctly through selectToday method', () => {
49-
const dateRange = new IgxDateRangePickerComponent(elementRef, null, null, null);
50-
dateRange.calendar = calendar;
51-
const today = new Date();
52-
53-
dateRange.selectRange(new Date());
54-
expect(dateRange.value.start).toEqual(today);
55-
expect(dateRange.value.end).toEqual(today);
56-
});
57-
5848
it('should emit rangeSelected on selection', () => {
5949
const dateRange = new IgxDateRangePickerComponent(elementRef, null, null, null);
6050
dateRange.calendar = calendar;
@@ -78,19 +68,6 @@ describe('IgxDateRangePicker', () => {
7868
expect(dateRange.rangeSelected.emit).toHaveBeenCalledWith({ start: startDate, end: startDate });
7969
});
8070

81-
it('should emit rangeSelected on selectToday()', () => {
82-
const dateRange = new IgxDateRangePickerComponent(elementRef, null, null, null);
83-
dateRange.calendar = calendar;
84-
spyOn(dateRange.rangeSelected, 'emit');
85-
const today = new Date();
86-
87-
dateRange.selectRange(new Date());
88-
expect(dateRange.value.start).toEqual(today);
89-
expect(dateRange.value.end).toEqual(today);
90-
expect(dateRange.rangeSelected.emit).toHaveBeenCalledTimes(1);
91-
expect(dateRange.rangeSelected.emit).toHaveBeenCalledWith({ start: today, end: today });
92-
});
93-
9471
it('should correctly implement interface methods - ControlValueAccessor ', () => {
9572
const mockNgControl = jasmine.createSpyObj('NgControl', ['registerOnChangeCb', 'registerOnTouchedCb']);
9673
const range = { start: new Date(2020, 1, 18), end: new Date(2020, 1, 28) };

projects/igniteui-angular/src/lib/date-range-picker/date-range-picker.component.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ import { CurrentResourceStrings } from '../core/i18n/resources';
4949
import { DisplayDensityBase, DisplayDensityToken, IDisplayDensityOptions } from '../core/density';
5050
import { DatePickerUtil } from '../date-picker/date-picker.utils';
5151
import { DateRangeType } from '../core/dates';
52-
import { TreeGridFilteringStrategy } from '../grids/tree-grid/tree-grid.filtering.pipe';
53-
54-
const DEFAULT_INPUT_FORMAT = 'MM/dd/yyyy';
5552

5653
/**
5754
* Provides the ability to select a range of dates from a calendar UI or editable inputs.
@@ -385,9 +382,9 @@ export class IgxDateRangePickerComponent extends DisplayDensityBase
385382
// TODO: use displayFormat - see how shortDate, longDate can be defined
386383
return this.inputFormat
387384
? `${this.inputFormat} - ${this.inputFormat}`
388-
: `${DEFAULT_INPUT_FORMAT} - ${DEFAULT_INPUT_FORMAT}`;
385+
: `${DatePickerUtil.DEFAULT_INPUT_FORMAT} - ${DatePickerUtil.DEFAULT_INPUT_FORMAT}`;
389386
} else {
390-
return this.inputFormat || DEFAULT_INPUT_FORMAT;
387+
return this.inputFormat || DatePickerUtil.DEFAULT_INPUT_FORMAT;
391388
}
392389
}
393390

@@ -632,7 +629,7 @@ export class IgxDateRangePickerComponent extends DisplayDensityBase
632629
/** @hidden @internal */
633630
public ngOnChanges(changes: SimpleChanges): void {
634631
if (changes['locale']) {
635-
this.inputFormat = DatePickerUtil.getDefaultInputFormat(this.locale || 'en') || DEFAULT_INPUT_FORMAT;
632+
this.inputFormat = DatePickerUtil.getDefaultInputFormat(this.locale || 'en') || DatePickerUtil.DEFAULT_INPUT_FORMAT;
636633
}
637634
}
638635

projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.spec.ts

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { IgxDateTimeEditorDirective, IgxDateTimeEditorModule } from './date-time-editor.directive';
22
import { DatePart } from './date-time-editor.common';
33
import { DOCUMENT } from '@angular/common';
4-
import { Component, ViewChild, DebugElement, LOCALE_ID, EventEmitter, Output, SimpleChange, SimpleChanges } from '@angular/core';
5-
import { async, fakeAsync, TestBed, tick, flush, ComponentFixture } from '@angular/core/testing';
6-
import { FormsModule, FormGroup, FormBuilder, FormControl, ReactiveFormsModule, NgModel, Validators } from '@angular/forms';
4+
import { Component, ViewChild, DebugElement, EventEmitter, Output, SimpleChange, SimpleChanges } from '@angular/core';
5+
import { async, fakeAsync, TestBed, tick, } from '@angular/core/testing';
6+
import { FormsModule, FormGroup, FormBuilder, ReactiveFormsModule, Validators, NgControl } from '@angular/forms';
77
import { By } from '@angular/platform-browser';
88
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
99
import { IgxInputGroupModule, IgxInputGroupComponent, IgxInputDirective } from '../../input-group';
@@ -17,11 +17,17 @@ describe('IgxDateTimeEditor', () => {
1717
['parseMask', 'restoreValueFromMask', 'parseMaskValue', 'applyMask']);
1818
const renderer2 = jasmine.createSpyObj('Renderer2', ['setAttribute']);
1919
const locale = 'en';
20+
const ngControl = {
21+
control: { touched: false, dirty: false, validator: null, setValue: (value: any) => { } },
22+
valid: false,
23+
statusChanges: new EventEmitter(),
24+
};
2025
let elementRef = { nativeElement: null };
2126
let inputFormat: string;
2227
let inputDate: string;
23-
function initializeDateTimeEditor() {
24-
dateTimeEditor = new IgxDateTimeEditorDirective(renderer2, elementRef, maskParsingService, DOCUMENT, locale);
28+
function initializeDateTimeEditor(control?: NgControl) {
29+
const injector = { get: () => control };
30+
dateTimeEditor = new IgxDateTimeEditorDirective(renderer2, elementRef, maskParsingService, DOCUMENT, locale, injector);
2531
dateTimeEditor.inputFormat = inputFormat;
2632
dateTimeEditor.ngOnInit();
2733

@@ -30,7 +36,7 @@ describe('IgxDateTimeEditor', () => {
3036
dateTimeEditor.ngOnChanges(changes);
3137
}
3238
describe('Properties & Events', () => {
33-
it('should emit valueChanged event on clear()', () => {
39+
it('should emit valueChange event on clear()', () => {
3440
inputFormat = 'dd/M/yy';
3541
inputDate = '6/6/2000';
3642
elementRef = { nativeElement: { value: inputDate } };
@@ -305,6 +311,22 @@ describe('IgxDateTimeEditor', () => {
305311
dateTimeEditor.decrement(DatePart.Seconds);
306312
expect(dateTimeEditor.value.getSeconds()).toEqual(59);
307313
});
314+
315+
it('should properly parse AM/PM no matter where it is in the format', () => {
316+
inputFormat = 'dd tt yyyy-MM mm-ss-hh';
317+
inputDate = '12 AM 2020-06 14-15-11';
318+
elementRef = { nativeElement: { value: inputDate } };
319+
initializeDateTimeEditor();
320+
321+
dateTimeEditor.inputFormat = inputFormat;
322+
expect(dateTimeEditor.mask).toEqual('00 LL 0000-00 00-00-00');
323+
324+
dateTimeEditor.value = new Date(2020, 5, 12, 11, 15, 14);
325+
spyOnProperty((dateTimeEditor as any), 'inputValue', 'get').and.returnValue(inputDate);
326+
327+
dateTimeEditor.increment(DatePart.AmPm);
328+
expect(dateTimeEditor.value).toEqual(new Date(2020, 5, 12, 23, 15, 14));
329+
});
308330
});
309331
});
310332

@@ -831,7 +853,7 @@ describe('IgxDateTimeEditor', () => {
831853
expect(dateTimeEditorDirective.setDisabledState).toHaveBeenCalledTimes(2);
832854
expect(dateTimeEditorDirective.setDisabledState).toHaveBeenCalledWith(false);
833855
}));
834-
it('should emit valueChanged event on blur', () => {
856+
it('should emit valueChange event on blur', () => {
835857
const newDate = new Date(2004, 11, 18);
836858
fixture.componentInstance.dateTimeFormat = 'dd/MM/yy';
837859
fixture.detectChanges();
@@ -849,6 +871,18 @@ describe('IgxDateTimeEditor', () => {
849871
expect(dateTimeEditorDirective.valueChange.emit).toHaveBeenCalledTimes(1);
850872
expect(dateTimeEditorDirective.valueChange.emit).toHaveBeenCalledWith(newDate);
851873
});
874+
it('should emit valueChange event after input is complete', () => {
875+
const newDate = new Date(2012, 11, 12);
876+
fixture.componentInstance.dateTimeFormat = 'dd/MM/yy';
877+
fixture.detectChanges();
878+
spyOn(dateTimeEditorDirective.valueChange, 'emit');
879+
inputElement.triggerEventHandler('focus', {});
880+
fixture.detectChanges();
881+
UIInteractions.simulateTyping('121212', inputElement);
882+
fixture.detectChanges();
883+
expect(dateTimeEditorDirective.valueChange.emit).toHaveBeenCalledTimes(1);
884+
expect(dateTimeEditorDirective.valueChange.emit).toHaveBeenCalledWith(newDate);
885+
});
852886
it('should fire validationFailed when input date is outside date range.', () => {
853887
fixture.componentInstance.dateTimeFormat = 'dd-MM-yyyy';
854888
fixture.componentInstance.minDate = new Date(2020, 1, 20);

0 commit comments

Comments
 (0)