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

feat: add firstDayOfWeek to datepickers #3220

Merged
merged 1 commit into from
Nov 8, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { convertToBoolProperty, NbBooleanInput } from '../../../helpers';
[weekNumberSymbol]="weekNumberSymbol">
</nb-calendar-week-numbers>
<div class="days-container">
<nb-calendar-days-names [size]="size"></nb-calendar-days-names>
<nb-calendar-days-names [size]="size" [firstDayOfWeek]="firstDayOfWeek"></nb-calendar-days-names>
<nb-calendar-picker
[data]="weeks"
[visibleDate]="visibleDate"
Expand Down Expand Up @@ -121,6 +121,12 @@ export class NbCalendarDayPickerComponent<D, T> implements OnChanges {
* */
@Input() weekNumberSymbol: string;

/**
* Sets first day of the week, it can be 1 if week starts from monday and 0 if from sunday and so on.
* `undefined` means that default locale setting will be used.
* */
@Input() firstDayOfWeek: number | undefined;

/**
* Fires newly selected date.
* */
Expand All @@ -141,9 +147,9 @@ export class NbCalendarDayPickerComponent<D, T> implements OnChanges {
constructor(private monthModel: NbCalendarMonthModelService<D>) {
}

ngOnChanges({ visibleDate, boundingMonths }: SimpleChanges) {
if (visibleDate || boundingMonths) {
this.weeks = this.monthModel.createDaysGrid(this.visibleDate, this.boundingMonths);
ngOnChanges({ visibleDate, boundingMonths, firstDayOfWeek }: SimpleChanges) {
if (visibleDate || boundingMonths || firstDayOfWeek) {
this.weeks = this.monthModel.createDaysGrid(this.visibleDate, this.boundingMonths, this.firstDayOfWeek);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import { ChangeDetectionStrategy, Component, OnInit, Input, HostBinding } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnInit, Input, HostBinding, SimpleChanges, OnChanges } from '@angular/core';

import { NbCalendarDay, NbCalendarSize, NbCalendarSizeValues } from '../../model';
import { NbDateService } from '../../services/date.service';
Expand All @@ -18,7 +18,7 @@ import { NbDateService } from '../../services/date.service';
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NbCalendarDaysNamesComponent<D> implements OnInit {
export class NbCalendarDaysNamesComponent<D> implements OnInit, OnChanges {

days: NbCalendarDay[];

Expand All @@ -30,6 +30,12 @@ export class NbCalendarDaysNamesComponent<D> implements OnInit {
return this.size === NbCalendarSize.LARGE;
}

/**
* Sets first day of the week, it can be 1 if week starts from monday and 0 if from sunday and so on.
* `undefined` means that default locale setting will be used.
* */
@Input() firstDayOfWeek: number | undefined;

constructor(private dateService: NbDateService<D>) {
}

Expand All @@ -38,13 +44,21 @@ export class NbCalendarDaysNamesComponent<D> implements OnInit {
this.days = this.shiftStartOfWeek(days);
}

ngOnChanges({firstDayOfWeek}: SimpleChanges) {
if (firstDayOfWeek) {
const days: NbCalendarDay[] = this.createDaysNames();
this.days = this.shiftStartOfWeek(days);
}
}

private createDaysNames(): NbCalendarDay[] {
return this.dateService.getDayOfWeekNames()
.map(this.markIfHoliday);
}

private shiftStartOfWeek(days: NbCalendarDay[]): NbCalendarDay[] {
for (let i = 0; i < this.dateService.getFirstDayOfWeek(); i++) {
const firstDayOfWeek = this.firstDayOfWeek ?? this.dateService.getFirstDayOfWeek();
for (let i = 0; i < firstDayOfWeek; i++) {
days.push(days.shift());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ export class NbCalendarMonthModelService<D> {
constructor(protected dateService: NbDateService<D>) {
}

createDaysGrid(activeMonth: D, boundingMonth: boolean = true): D[][] {
const weeks = this.createDates(activeMonth);
createDaysGrid(activeMonth: D, boundingMonth: boolean = true, firstDayOfWeek?: number): D[][] {
const weeks = this.createDates(activeMonth, firstDayOfWeek);
return this.withBoundingMonths(weeks, activeMonth, boundingMonth);
}

private createDates(activeMonth: D): D[][] {
private createDates(activeMonth: D, firstDayOfWeek?: number): D[][] {
const days = this.createDateRangeForMonth(activeMonth);
const startOfWeekDayDiff = this.getStartOfWeekDayDiff(activeMonth);
const startOfWeekDayDiff = this.getStartOfWeekDayDiff(activeMonth, firstDayOfWeek);
return batch(days, this.dateService.DAYS_IN_WEEK, startOfWeekDayDiff);
}

Expand Down Expand Up @@ -70,13 +70,14 @@ export class NbCalendarMonthModelService<D> {
.map(date => boundingMonth ? date : null);
}

private getStartOfWeekDayDiff(date: D): number {
private getStartOfWeekDayDiff(date: D, firstDayOfWeek?: number): number {
const startOfMonth = this.dateService.getMonthStart(date);
return this.getWeekStartDiff(startOfMonth);
return this.getWeekStartDiff(startOfMonth, firstDayOfWeek);
}

private getWeekStartDiff(date: D): number {
return (7 - this.dateService.getFirstDayOfWeek() + this.dateService.getDayOfWeek(date)) % 7;
private getWeekStartDiff(date: D, firstDayOfWeek?: number): number {
const weekOfset = firstDayOfWeek ?? this.dateService.getFirstDayOfWeek();
return (7 - weekOfset + this.dateService.getDayOfWeek(date)) % 7;
}

private isShouldAddPrevBoundingMonth(weeks: D[][]): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
[size]="size"
[date]="date"
[showWeekNumber]="showWeekNumber"
[firstDayOfWeek]="firstDayOfWeek"
(dateChange)="dateChange.emit($any($event))"
[weekNumberSymbol]="weekNumberSymbol">
</nb-calendar-day-picker>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ export class NbBaseCalendarComponent<D, T> implements OnInit {
* */
@Input() weekNumberSymbol: string;

/**
* Sets first day of the week, it can be 1 if week starts from monday and 0 if from sunday and so on.
* `undefined` means that default locale setting will be used.
* */
@Input() firstDayOfWeek: number | undefined;

/**
* Emits date when selected.
* */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export interface NbCalendarRange<D> {
[size]="size"
[showWeekNumber]="showWeekNumber"
[weekNumberSymbol]="weekNumberSymbol"
[firstDayOfWeek]="firstDayOfWeek"
></nb-base-calendar>
`,
})
Expand Down Expand Up @@ -284,6 +285,12 @@ export class NbCalendarRangeComponent<D> {
* */
@Input() weekNumberSymbol: string = '#';

/**
* Sets first day of the week, it can be 1 if week starts from monday and 0 if from sunday and so on.
* `undefined` means that default locale setting will be used.
* */
@Input() firstDayOfWeek: number | undefined;

/**
* Emits range when start selected and emits again when end selected.
* */
Expand Down
7 changes: 7 additions & 0 deletions src/framework/theme/components/calendar/calendar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ import { convertToBoolProperty, NbBooleanInput } from '../helpers';
[showNavigation]="showNavigation"
[showWeekNumber]="showWeekNumber"
[weekNumberSymbol]="weekNumberSymbol"
[firstDayOfWeek]="firstDayOfWeek"
(dateChange)="dateChange.emit($event)"
></nb-base-calendar>
`,
Expand Down Expand Up @@ -297,6 +298,12 @@ export class NbCalendarComponent<D> {
* */
@Input() weekNumberSymbol: string = '#';

/**
* Sets first day of the week, it can be 1 if week starts from monday and 0 if from sunday and so on.
* `undefined` means that default locale setting will be used.
* */
@Input() firstDayOfWeek: number | undefined;

/**
* Emits date when selected.
* */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { NbTimePickerComponent } from '../timepicker/timepicker.component';
[showNavigation]="showNavigation"
[showWeekNumber]="showWeekNumber"
[weekNumberSymbol]="weekNumberSymbol"
[firstDayOfWeek]="firstDayOfWeek"
(dateChange)="onDateValueChange($event)"
>
</nb-base-calendar>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ export abstract class NbBasePicker<D, T, P> extends NbDatepicker<T, D> {
* */
abstract showWeekNumber: boolean;

/**
* Sets first day of the week, it can be 1 if week starts from monday and 0 if from sunday and so on.
* `undefined` means that default locale setting will be used.
* */
abstract firstDayOfWeek: number | undefined;

readonly formatChanged$: Subject<void> = new Subject();

/**
Expand Down Expand Up @@ -351,6 +357,7 @@ export abstract class NbBasePicker<D, T, P> extends NbDatepicker<T, D> {
this.picker.visibleDate = this.visibleDate;
this.picker.showWeekNumber = this.showWeekNumber;
this.picker.weekNumberSymbol = this.weekNumberSymbol;
this.picker.firstDayOfWeek = this.firstDayOfWeek;
}

protected checkFormat() {
Expand Down Expand Up @@ -465,6 +472,8 @@ export class NbBasePickerComponent<D, T, P> extends NbBasePicker<D, T, P> implem
protected _showWeekNumber: boolean = false;
static ngAcceptInputType_showWeekNumber: NbBooleanInput;

@Input() firstDayOfWeek: number | undefined;

/**
* Determines picker overlay offset (in pixels).
* */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
[step]="step"
[twelveHoursFormat]="twelveHoursFormat"
[showAmPmLabel]="false"
[firstDayOfWeek]="firstDayOfWeek"
#dateTimePicker
></nb-date-timepicker>
</section>
Expand Down Expand Up @@ -47,5 +48,21 @@
{{ formatToggleTimer ? 'Stop' : 'Start' }} auto format toggle
</button>
</section>

<section>
<nb-select [(selected)]="firstDayOfWeek">
<nb-option>LOCALE_ID</nb-option>
<nb-option [value]="0">Sunday</nb-option>
<nb-option [value]="1">Moday</nb-option>
<nb-option [value]="2">Tuesday</nb-option>
<nb-option [value]="3">Wednesday</nb-option>
<nb-option [value]="4">Thursday</nb-option>
<nb-option [value]="5">Friday</nb-option>
<nb-option [value]="6">Saturday</nb-option>
</nb-select>
<button nbButton (click)="toggleFirstDayOfWeekSwitching()">
{{ firstDayOfWeekToggleTimer ? 'Stop' : 'Start' }} auto firstDayOfWeek toggle
</button>
</section>
</nb-card-body>
</nb-card>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Component } from '@angular/core';
margin-bottom: 2rem;
}
button + button {
section > * + * {
margin-left: 1rem;
}
`,
Expand Down Expand Up @@ -113,4 +113,26 @@ export class DateTimepickerDynamicInputsShowcaseComponent {
toggleFormat() {
this.format = this.format === 'dd/MM/yyyy HH:mm' ? 'HH:mm dd/MM/yyyy' : 'dd/MM/yyyy HH:mm';
}

firstDayOfWeek: number | undefined = undefined;
firstDayOfWeekToggleTimer = null;

toggleFirstDayOfWeekSwitching() {
if (this.firstDayOfWeekToggleTimer == null) {
this.firstDayOfWeekToggleTimer = setInterval(() => {
this.toggleFirstDayOfWeek();
}, 1000);
} else {
clearInterval(this.firstDayOfWeekToggleTimer);
this.firstDayOfWeekToggleTimer = null;
}
}

toggleFirstDayOfWeek() {
this.firstDayOfWeek ??= 0;
this.firstDayOfWeek++;
if (this.firstDayOfWeek > 6) {
this.firstDayOfWeek = 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<nb-card-body>
<section>
<input nbInput placeholder="Pick Date" [ngModel]="now" [nbDatepicker]="datePicker" />
<nb-datepicker [format]="format" #datePicker></nb-datepicker>
<nb-datepicker [format]="format" [firstDayOfWeek]="firstDayOfWeek" #datePicker></nb-datepicker>
</section>

<section>
Expand All @@ -11,5 +11,21 @@
{{ formatToggleTimer ? 'Stop' : 'Start' }} auto format toggle
</button>
</section>

<section>
<nb-select [(selected)]="firstDayOfWeek">
<nb-option>LOCALE_ID</nb-option>
<nb-option [value]="0">Sunday</nb-option>
<nb-option [value]="1">Moday</nb-option>
<nb-option [value]="2">Tuesday</nb-option>
<nb-option [value]="3">Wednesday</nb-option>
<nb-option [value]="4">Thursday</nb-option>
<nb-option [value]="5">Friday</nb-option>
<nb-option [value]="6">Saturday</nb-option>
</nb-select>
<button nbButton (click)="toggleFirstDayOfWeekSwitching()">
{{ firstDayOfWeekToggleTimer ? 'Stop' : 'Start' }} auto firstDayOfWeek toggle
</button>
</section>
</nb-card-body>
</nb-card>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Component } from '@angular/core';
margin-bottom: 2rem;
}
button + button {
section > * + * {
margin-left: 1rem;
}
`,
Expand All @@ -26,6 +26,8 @@ export class DatepickerDynamicInputsShowcaseComponent {

format = 'dd/MM/yyyy HH:mm';
formatToggleTimer = null;
firstDayOfWeek: number | undefined = undefined;
firstDayOfWeekToggleTimer = null;

toggleFormatSwitching() {
if (this.formatToggleTimer == null) {
Expand All @@ -41,4 +43,23 @@ export class DatepickerDynamicInputsShowcaseComponent {
toggleFormat() {
this.format = this.format === 'dd/MM/yyyy HH:mm' ? 'HH:mm dd/MM/yyyy' : 'dd/MM/yyyy HH:mm';
}

toggleFirstDayOfWeekSwitching() {
if (this.firstDayOfWeekToggleTimer == null) {
this.firstDayOfWeekToggleTimer = setInterval(() => {
this.toggleFirstDayOfWeek();
}, 1000);
} else {
clearInterval(this.firstDayOfWeekToggleTimer);
this.firstDayOfWeekToggleTimer = null;
}
}

toggleFirstDayOfWeek() {
this.firstDayOfWeek ??= 0;
this.firstDayOfWeek++;
if (this.firstDayOfWeek > 6) {
this.firstDayOfWeek = 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NbButtonModule, NbCardModule, NbDatepickerModule, NbInputModule, NbTimepickerModule } from '@nebular/theme';
import { NbButtonModule, NbCardModule, NbDatepickerModule, NbInputModule, NbSelectModule, NbTimepickerModule } from '@nebular/theme';
import { DatepickerWithFormatRoutingModule } from './datepicker-with-format-routing.module';
import { DateTimepickerDynamicInputsShowcaseComponent } from './date-timepicker-dynamic-inputs-showcase.component';
import { NbDateFnsDateModule } from '@nebular/date-fns';
Expand All @@ -29,6 +29,7 @@ import { RangepickerDynamicInputsShowcaseComponent } from './rangepicker-dynamic
NbCardModule,
NbButtonModule,
NbDateFnsDateModule.forRoot({}),
NbSelectModule,
],
})
export class DatepickerWithFormatModule {}
Loading
Loading