From 9920fc4cde0d309455501a2d448eb6d2d0fb71ca Mon Sep 17 00:00:00 2001 From: xlou978 Date: Sun, 6 Oct 2019 09:52:36 -0700 Subject: [PATCH 1/2] Adds a date selection model --- .../core/datetime/date-selection-model.ts | 138 ++++++++++++++++++ src/material/core/datetime/index.ts | 1 + 2 files changed, 139 insertions(+) create mode 100644 src/material/core/datetime/date-selection-model.ts diff --git a/src/material/core/datetime/date-selection-model.ts b/src/material/core/datetime/date-selection-model.ts new file mode 100644 index 000000000000..73254e66953b --- /dev/null +++ b/src/material/core/datetime/date-selection-model.ts @@ -0,0 +1,138 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {DateAdapter} from '@angular/material/core'; +import {Subject} from 'rxjs'; + +export abstract class MatDateSelectionModel { + private _valueChangesSubject = new Subject(); + valueChanges = this._valueChangesSubject.asObservable(); + + constructor(protected readonly adapter: DateAdapter) {} + + destroy() { + this.valueChanges.complete(); + } + + abstract add(date: D | null): void; + abstract isComplete(): boolean; + abstract isSame(other: MatDateSelectionModel): boolean; + abstract isValid(): boolean; +} + +export interface DateRange { + start: D | null; + end: D | null; +} + +/** + * Concrete implementation of a MatDateSelectionModel that holds a single date. + */ +export class MatSingleDateSelectionModel extends MatDateSelectionModel { + private _date: D | null = null; + + constructor(adapter: DateAdapter, date?: D | null) { + super(adapter); + this._date = date === undefined ? null : date; + } + + add(date: D | null) { + this._date = date; + this.valueChanges.next(); + } + + compareDate(other: MatSingleDateSelectionModel) { + const date = this.asDate(); + const otherDate = other.asDate(); + if (date != null && otherDate != null) { + return this.adapter.compareDate(date, otherDate); + } + return date === otherDate; + } + + isComplete() { return this._date != null; } + + isSame(other: MatDateSelectionModel): boolean { + return other instanceof MatSingleDateSelectionModel && + this.adapter.sameDate(other.asDate(), this._date); + } + + isValid(): boolean { + return this._date != null && this.adapter.isDateInstance(this._date) && + this.adapter.isValid(this._date); + } + + asDate(): D | null { + return (this.isValid()) ? this._date : null; + } +} + +/** + * Concrete implementation of a MatDateSelectionModel that holds a date range, represented by + * a start date and an end date. + */ +export class MatRangeDateSelectionModel extends MatDateSelectionModel { + private _start: D | null = null; + private _end: D | null = null; + + constructor(adapter: DateAdapter, start?: D | null, end?: D | null) { + super(adapter); + + this._start = start === undefined ? null : start; + + this._end = end === undefined ? null : end; + } + + /** + * Adds an additional date to the range. If no date is set thus far, it will set it to the + * beginning. If the beginning is set, it will set it to the end. + * If add is called on a complete selection, it will empty the selection and set it as the start. + */ + add(date: D | null): void { + if (this._start == null) { + this._start = date; + } else if (this._end == null) { + this._end = date; + } else { + this._start = date; + this._end = null; + } + + this.valueChanges.next(); + } + + setRange(start: D | null, end: D | null) { + this._start = start; + this._end = end; + } + + isComplete(): boolean { + return this._start != null && this._end != null; + } + + isSame(other: MatDateSelectionModel): boolean { + if (other instanceof MatRangeDateSelectionModel) { + otherRange = other.asRange(); + return this.adapter.sameDate(this._start, otherRange.start) && + this.adapter.sameDate(this._end, otherRange.end); + } + return false; + } + + isValid(): boolean { + return this._start != null && this._end != null && + this.adapter.isValid(this._start!) && this.adapter.isValid(this._end!); + } + + asRange(): DateRange { + return { + start: this._start, + end: this._end, + }; + } +} diff --git a/src/material/core/datetime/index.ts b/src/material/core/datetime/index.ts index 5c94050408a0..3bf1ea2459e1 100644 --- a/src/material/core/datetime/index.ts +++ b/src/material/core/datetime/index.ts @@ -17,6 +17,7 @@ export * from './date-adapter'; export * from './date-formats'; export * from './native-date-adapter'; export * from './native-date-formats'; +export * from './date-selection-model'; @NgModule({ From f45ca82e4cafd441be1fb7f051d00aea5140540e Mon Sep 17 00:00:00 2001 From: xlou978 Date: Sun, 6 Oct 2019 09:52:36 -0700 Subject: [PATCH 2/2] Adds a date selection model --- .../core/datetime/date-selection-model.ts | 18 ++++----- tools/public_api_guard/material/core.d.ts | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/material/core/datetime/date-selection-model.ts b/src/material/core/datetime/date-selection-model.ts index 73254e66953b..1bc4df380bfc 100644 --- a/src/material/core/datetime/date-selection-model.ts +++ b/src/material/core/datetime/date-selection-model.ts @@ -7,16 +7,16 @@ */ import {DateAdapter} from '@angular/material/core'; -import {Subject} from 'rxjs'; +import {Subject, Observable} from 'rxjs'; export abstract class MatDateSelectionModel { - private _valueChangesSubject = new Subject(); - valueChanges = this._valueChangesSubject.asObservable(); + protected _valueChangesSubject = new Subject(); + valueChanges: Observable = this._valueChangesSubject.asObservable(); constructor(protected readonly adapter: DateAdapter) {} destroy() { - this.valueChanges.complete(); + this._valueChangesSubject.complete(); } abstract add(date: D | null): void; @@ -43,7 +43,7 @@ export class MatSingleDateSelectionModel extends MatDateSelectionModel { add(date: D | null) { this._date = date; - this.valueChanges.next(); + this._valueChangesSubject.next(); } compareDate(other: MatSingleDateSelectionModel) { @@ -68,7 +68,7 @@ export class MatSingleDateSelectionModel extends MatDateSelectionModel { } asDate(): D | null { - return (this.isValid()) ? this._date : null; + return this.isValid() ? this._date : null; } } @@ -82,9 +82,7 @@ export class MatRangeDateSelectionModel extends MatDateSelectionModel { constructor(adapter: DateAdapter, start?: D | null, end?: D | null) { super(adapter); - this._start = start === undefined ? null : start; - this._end = end === undefined ? null : end; } @@ -103,7 +101,7 @@ export class MatRangeDateSelectionModel extends MatDateSelectionModel { this._end = null; } - this.valueChanges.next(); + this._valueChangesSubject.next(); } setRange(start: D | null, end: D | null) { @@ -117,7 +115,7 @@ export class MatRangeDateSelectionModel extends MatDateSelectionModel { isSame(other: MatDateSelectionModel): boolean { if (other instanceof MatRangeDateSelectionModel) { - otherRange = other.asRange(); + const otherRange = other.asRange(); return this.adapter.sameDate(this._start, otherRange.start) && this.adapter.sameDate(this._end, otherRange.end); } diff --git a/tools/public_api_guard/material/core.d.ts b/tools/public_api_guard/material/core.d.ts index 907906947a8b..88703a257c63 100644 --- a/tools/public_api_guard/material/core.d.ts +++ b/tools/public_api_guard/material/core.d.ts @@ -79,6 +79,11 @@ export declare abstract class DateAdapter { abstract today(): D; } +export interface DateRange { + end: D | null; + start: D | null; +} + export declare const JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SEP = 8, OCT = 9, NOV = 10, DEC = 11; export declare const defaultRippleAnimationConfig: { @@ -213,6 +218,18 @@ export declare type MatDateFormats = { }; }; +export declare abstract class MatDateSelectionModel { + protected _valueChangesSubject: Subject; + protected readonly adapter: DateAdapter; + valueChanges: Observable; + constructor(adapter: DateAdapter); + abstract add(date: D | null): void; + destroy(): void; + abstract isComplete(): boolean; + abstract isSame(other: MatDateSelectionModel): boolean; + abstract isValid(): boolean; +} + export declare const MATERIAL_SANITY_CHECKS: InjectionToken; export declare class MatLine { @@ -289,6 +306,16 @@ export declare class MatPseudoCheckboxModule { export declare type MatPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate'; +export declare class MatRangeDateSelectionModel extends MatDateSelectionModel { + constructor(adapter: DateAdapter, start?: D | null, end?: D | null); + add(date: D | null): void; + asRange(): DateRange; + isComplete(): boolean; + isSame(other: MatDateSelectionModel): boolean; + isValid(): boolean; + setRange(start: D | null, end: D | null): void; +} + export declare class MatRipple implements OnInit, OnDestroy, RippleTarget { animation: RippleAnimationConfig; centered: boolean; @@ -310,6 +337,16 @@ export declare class MatRipple implements OnInit, OnDestroy, RippleTarget { export declare class MatRippleModule { } +export declare class MatSingleDateSelectionModel extends MatDateSelectionModel { + constructor(adapter: DateAdapter, date?: D | null); + add(date: D | null): void; + asDate(): D | null; + compareDate(other: MatSingleDateSelectionModel): number | boolean; + isComplete(): boolean; + isSame(other: MatDateSelectionModel): boolean; + isValid(): boolean; +} + export declare const JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SEP = 8, OCT = 9, NOV = 10, DEC = 11; export declare function mixinColor>(base: T, defaultColor?: ThemePalette): CanColorCtor & T;