• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 6146764501

11 Sep 2023 01:01PM UTC coverage: 92.263%. Remained the same
6146764501

push

github

web-flow
Merge pull request #13437 from IgniteUI/thristodorova/fix-13433-16.0.x

fix(grid): add return type and return value to endEdit method

15311 of 17991 branches covered (0.0%)

1 of 1 new or added line in 1 file covered. (100.0%)

26844 of 29095 relevant lines covered (92.26%)

29497.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.0
/projects/igniteui-angular/src/lib/calendar/calendar.ts
1
import { DateRangeDescriptor, DateRangeType } from '../core/dates';
2
import { mkenum } from '../core/utils';
3

4
/**
5
 * Sets the selection type - single, multi or range.
6
 */
2✔
7
export const CalendarSelection = mkenum({
8
    SINGLE: 'single',
9
    MULTI: 'multi',
10
    RANGE: 'range'
11
});
12
export type CalendarSelection = (typeof CalendarSelection)[keyof typeof CalendarSelection];
2✔
13

2✔
14
export enum ScrollMonth {
2✔
15
    PREV = 'prev',
2✔
16
    NEXT = 'next',
4✔
17
    NONE = 'none'
2✔
18
}
19

20
export interface IViewDateChangeEventArgs {
21
    previousValue: Date;
22
    currentValue: Date;
23
}
24

25
export const IgxCalendarView = mkenum({
26
    Month: 'month',
2✔
27
    Year: 'year',
2✔
28
    Decade: 'decade'
2✔
29
});
4✔
30

2✔
31
/**
2✔
32
 * Determines the Calendar active view - days, months or years.
2!
33
 */
8,298✔
34
export type IgxCalendarView = (typeof IgxCalendarView)[keyof typeof IgxCalendarView];
8,298!
35

8,298!
36
/**
8,298!
37
 * @hidden
49,830✔
38
 */
39
enum TimeDeltaInterval {
8,298✔
40
    Month = 'month',
41
    Year = 'year'
42
}
43

44
const MDAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
45
const FEBRUARY = 1;
46

47
export const range = (start = 0, stop, step = 1) => {
48
    const res = [];
3!
49
    const cur = (stop === undefined) ? 0 : start;
16✔
50
    const max = (stop === undefined) ? start : stop;
51
    for (let i = cur; step < 0 ? i > max : i < max; i += step) {
52
        res.push(i);
53
    }
54
    return res;
55
};
56

57
/**
58
 * Returns true for leap years, false for non-leap years.
2✔
59
 *
16✔
60
 * @export
2✔
61
 * @param year
62
 * @returns
14✔
63
 */
14✔
64
export const isLeap = (year: number): boolean => (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0));
14✔
65

1✔
66
export const weekDay = (year: number, month: number, day: number): number => new Date(year, month, day).getDay();
67

14✔
68
/**
69
 * Return weekday and number of days for year, month.
2✔
70
 *
727,074✔
71
 * @export
727,074✔
72
 * @param year
727,074✔
73
 * @param month
553,251✔
74
 * @returns
75
 */
173,823✔
76
export const monthRange = (year: number, month: number): number[] => {
517,990✔
77
    if ((month < 0) || (month > 11)) {
266,124!
78
        throw new Error('Invalid month specified');
79
    }
1,335✔
80
    const day = weekDay(year, month, 1);
567✔
81
    let nDays = MDAYS[month];
82
    if ((month === FEBRUARY) && (isLeap(year))) {
768✔
83
        nDays++;
84
    }
2,895✔
85
    return [day, nDays];
1,299✔
86
};
87

1,596✔
88
export const isDateInRanges = (date: Date, ranges: DateRangeDescriptor[]): boolean => {
89
    date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
486,612✔
90
    const dateInMs = date.getTime();
243,306✔
91

243,306✔
92
    if (!ranges) {
243,306✔
93
        return false;
50,567✔
94
    }
95

192,739✔
96
    for (const descriptor of ranges) {
97
        const dRanges = descriptor.dateRange ? descriptor.dateRange.map(
27,148✔
98
            r => new Date(r.getFullYear(), r.getMonth(), r.getDate())) : undefined;
13,647✔
99
        switch (descriptor.type) {
26,827✔
100
            case (DateRangeType.After):
460✔
101
                if (dateInMs > dRanges[0].getTime()) {
102
                    return true;
103
                }
13,187✔
104

105
                break;
634✔
106
            case (DateRangeType.Before):
634✔
107
                if (dateInMs < dRanges[0].getTime()) {
453✔
108
                    return true;
109
                }
181✔
110

111
                break;
4,307✔
112
            case (DateRangeType.Between):
4,307✔
113
                const dRange = dRanges.map(d => d.getTime());
1,270✔
114
                const min = Math.min(dRange[0], dRange[1]);
115
                const max = Math.max(dRange[0], dRange[1]);
3,037✔
116
                if (dateInMs >= min && dateInMs <= max) {
117
                    return true;
×
118
                }
119

120
                break;
119,207✔
121
            case (DateRangeType.Specific):
122
                const datesInMs = dRanges.map(d => d.getTime());
123
                for (const specificDateInMs of datesInMs) {
2✔
124
                    if (dateInMs === specificDateInMs) {
2✔
125
                        return true;
2✔
126
                    }
2✔
127
                }
2✔
128

2✔
129
                break;
2✔
130
            case (DateRangeType.Weekdays):
2✔
131
                const day = date.getDay();
4✔
132
                if (day % 6 !== 0) {
133
                    return true;
1,207✔
134
                }
1,207✔
135

136
                break;
137
            case (DateRangeType.Weekends):
36,423✔
138
                const weekday = date.getDay();
139
                if (weekday % 6 === 0) {
140
                    return true;
1,314✔
141
                }
142

143
                break;
144
            default:
145
                return false;
146
        }
147
    }
148

149
    return false;
150
};
151

152
export interface ICalendarDate {
153
    date: Date;
154
    isCurrentMonth: boolean;
2✔
155
    isPrevMonth: boolean;
2✔
156
    isNextMonth: boolean;
14✔
157
}
158

2✔
159
export interface IFormattedParts {
160
    value: string;
161
    literal?: string;
162
    combined: string;
163
}
164

165
export interface IFormattingOptions {
166
    day?: 'numeric' | '2-digit';
167
    month?: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow';
168
    weekday?: 'long' | 'short' | 'narrow';
169
    year?: 'numeric' | '2-digit';
170
}
171

3✔
172

5,556✔
173
export interface IFormattingViews {
5,556✔
174
    day?: boolean;
5,556✔
175
    month?: boolean;
13✔
176
    year?: boolean;
177
}
5,556✔
178

5,556✔
179
export enum WEEKDAYS {
180
    SUNDAY = 0,
181
    MONDAY = 1,
5,556✔
182
    TUESDAY = 2,
195,475✔
183
    WEDNESDAY = 3,
195,475✔
184
    THURSDAY = 4,
195,475✔
185
    FRIDAY = 5,
195,475✔
186
    SATURDAY = 6
5,556✔
187
}
2,705✔
188

18,935✔
189
export class Calendar {
18,935✔
190

18,935✔
191
    private _firstWeekDay: WEEKDAYS | number;
192

193
    constructor(firstWeekDay: WEEKDAYS = WEEKDAYS.SUNDAY) {
5,556✔
194
        this._firstWeekDay = firstWeekDay;
195
    }
196

5,556✔
197
    public get firstWeekDay(): number {
198
        return this._firstWeekDay % 7;
199
    }
200

201
    public set firstWeekDay(value: number) {
202
        this._firstWeekDay = value;
203
    }
204

205
    /**
206
     * Returns an array of weekdays for one week starting
207
     * with the currently set `firstWeekDay`
208
     *
2,776✔
209
     * this.firstWeekDay = 0 (Sunday) --> [0, 1, 2, 3, 4, 5, 6]
5,552✔
210
     * this.firstWeekDay = 1 (Monday) --> [1, 2, 3, 4, 5, 6, 0]
5,552✔
211
     *
5,552✔
212
     * @returns
30,608✔
213
     *
214
     * @memberof Calendar
5,552✔
215
     */
216
    public weekdays(): number[] {
217
        const res = [];
248,661✔
218
        for (const i of range(this.firstWeekDay, this.firstWeekDay + 7)) {
248,661✔
219
            res.push(i % 7);
22,670!
220
        }
×
221
        return res;
222
    }
223

248,661✔
224
    /**
225
     * Returns the date values for one month. It will always iterate throught
203✔
226
     * complete weeks, so it will contain dates outside the specified month.
203✔
227
     *
203✔
228
     * @param year
229
     * @param month
2✔
230
     * @param boolean
2✔
231
     * @returns
2✔
232
     *
233
     * @memberof Calendar
22,465✔
234
     */
22,465✔
235
    public monthdates(year: number, month: number, extraWeek = false): ICalendarDate[] {
22,465✔
236
        let date = new Date(year, month, 1);
237
        let days = (date.getDay() - this.firstWeekDay) % 7;
3✔
238
        if (days < 0) {
3✔
239
            days = 7 - Math.abs(days);
240
        }
222,517✔
241
        date = this.timedelta(date, 'day', -days);
222,517✔
242
        const res = [];
243
        let value: ICalendarDate;
1,390✔
244

1,390✔
245
        // eslint-disable-next-line no-constant-condition
246
        while (true) {
1,385✔
247

1,385✔
248
            value = this.generateICalendarDate(date, year, month);
249
            res.push(value);
695✔
250

695✔
251
            date = this.timedelta(date, 'day', 1);
252

1✔
253
            if ((date.getMonth() !== month) && (date.getDay() === this.firstWeekDay)) {
254
                if (extraWeek && res.length <= 35) {
248,660✔
255
                    for (const _ of range(0, 7)) {
256
                        value = this.generateICalendarDate(date, year, month);
257
                        res.push(value);
3,853✔
258
                        date = this.timedelta(date, 'day', 1);
3,853✔
259
                    }
260
                }
261
                break;
262
            }
3,853!
263
        }
3,853✔
264
        return res;
3,853✔
265
    }
88,619✔
266

19,265✔
267
    /**
19,265!
268
     * Returns a matrix (array of arrays) representing a month's calendar.
×
269
     * Each row represents a full week; week entries are ICalendarDate objects.
×
270
     *
271
     * @param year
19,265✔
272
     * @param month
3,853✔
273
     * @returns
274
     *
15,412✔
275
     * @memberof Calendar
15,412✔
276
     */
15,412✔
277
    public monthdatescalendar(year: number, month: number, extraWeek = false): ICalendarDate[][] {
15,412✔
278
        const dates = this.monthdates(year, month, extraWeek);
279
        const res = [];
3,853✔
280
        for (const i of range(0, dates.length, 7)) {
19,265✔
281
            res.push(dates.slice(i, i + 7));
282
        }
283
        return res;
284
    }
×
285

×
286
    public timedelta(date: Date, interval: string, units: number): Date {
287
        const ret = new Date(date);
288

3,853✔
289
        const checkRollover = () => {
290
            if (ret.getDate() !== date.getDate()) {
291
                ret.setDate(0);
7✔
292
            }
293
        };
294

1,398✔
295
        switch (interval.toLowerCase()) {
296
            case 'year':
297
                ret.setFullYear(ret.getFullYear() + units);
22✔
298
                checkRollover();
299
                break;
300
            case 'quarter':
1,420✔
301
                ret.setMonth(ret.getMonth() + 3 * units);
302
                checkRollover();
303
                break;
92✔
304
            case 'month':
305
                ret.setMonth(ret.getMonth() + units);
306
                checkRollover();
88✔
307
                break;
308
            case 'week':
309
                ret.setDate(ret.getDate() + 7 * units);
310
                break;
60✔
311
            case 'day':
312
                ret.setDate(ret.getDate() + units);
60✔
313
                break;
60!
314
            case 'hour':
60✔
315
                ret.setTime(ret.getTime() + units * 3600000);
316
                break;
60✔
317
            case 'minute':
318
                ret.setTime(ret.getTime() + units * 60000);
319
                break;
320
            case 'second':
321
                ret.setTime(ret.getTime() + units * 1000);
60!
322
                break;
323
            default:
60✔
324
                throw new Error('Invalid interval specifier');
325
        }
326
        return ret;
327
    }
×
328

329
    public formatToParts(date: Date, locale: string, options: any, parts: string[]) {
330
        const formatter = new Intl.DateTimeFormat(locale, options);
60✔
331
        const result = {
332
            date,
4✔
333
            full: formatter.format(date)
334
        };
4✔
335

4!
336
        if ((formatter as any).formatToParts) {
337
            const formattedParts = (formatter as any).formatToParts(date);
338

4!
339
            const toType = (partType: string) => {
340
                const index = formattedParts.findIndex(({ type }) => type === partType);
60✔
341
                const o: IFormattedParts = { value: '', literal: '', combined: '' };
342

343
                if (partType === 'era' && index > -1) {
214,410✔
344
                    o.value = formattedParts[index].value;
345
                    return o;
422,107✔
346
                } else if (partType === 'era' && index === -1) {
347
                    return o;
348
                }
349

350
                o.value = formattedParts[index].value;
351
                o.literal = formattedParts[index + 1] ? formattedParts[index + 1].value : '';
214,410✔
352
                o.combined = [o.value, o.literal].join('');
207,697✔
353
                return o;
354
            };
6,713✔
355

356
            for (const each of parts) {
357
                result[each] = toType(each);
214,410✔
358
            }
207,697✔
359
        } else {
360
            for (const each of parts) {
6,713✔
361
                result[each] = { value: '', literal: '', combined: '' };
362
            }
363
        }
364
        return result;
365
    }
366

367
    public getFirstViewDate(date: Date, interval: string, activeViewIdx: number) {
368
        return this.timedelta(date, interval, -activeViewIdx);
369
    }
370

371
    public getDateByView(date: Date, interval: string, activeViewIdx: number) {
372
        return this.timedelta(date, interval, activeViewIdx);
373
    }
374

375
    public getNextMonth(date: Date) {
376
        return this.timedelta(date, TimeDeltaInterval.Month, 1);
377
    }
378

379
    public getPrevMonth(date: Date) {
380
        return this.timedelta(date, TimeDeltaInterval.Month, -1);
381
    }
382

383
    public getNextYear(date: Date) {
384
        return this.timedelta(date, TimeDeltaInterval.Year, 1);
385
    }
386

387
    public getPrevYear(date: Date) {
388
        return this.timedelta(date, TimeDeltaInterval.Year, -1);
389
    }
390

391
    public getWeekNumber(date: Date, weekStart: WEEKDAYS | number) {
392
        // current year
393
        const yearStart = new Date(date.getFullYear(), 0, 1);
394
        // first day number of the current year
395
        let firstDayOfTheYear = yearStart.getDay() - weekStart;
396
        firstDayOfTheYear = firstDayOfTheYear >= 0 ? firstDayOfTheYear : firstDayOfTheYear + 7;
397
        const dayInMilSeconds = 86400000;
398
        // day number in the year
399
        const dayNumber = Math.floor((date.getTime() - yearStart.getTime() - 
400
        (date.getTimezoneOffset() - yearStart.getTimezoneOffset()) * 60000) / dayInMilSeconds) + 1;
401
        let weekNumber;
402
        // if 01 Jan is Monday to Thursday, is considered 1st week of the year 
403
        // if 01 Jan starts Friday to Sunday, is considered last week of previous year
404
        if (firstDayOfTheYear < 4) {
405
            // when calculating the week number we add 1 for the 1st week
406
            weekNumber = Math.floor((dayNumber + firstDayOfTheYear - 1) / 7) + 1;
407
        } else {
408
            // calculating the week number
409
            weekNumber = Math.floor((dayNumber + firstDayOfTheYear - 1) / 7);
410
        }
411
        // if the week number is greater than week 52
412
        if (weekNumber > 52) {
413
            // next year
414
            let nextYear = new Date(date.getFullYear() + 1, 0, 1);
415
            // first day of the next year
416
            let nextYearFirstDay = nextYear.getDay() - weekStart;
417
            nextYearFirstDay = nextYearFirstDay >= 0 ? nextYearFirstDay : nextYearFirstDay + 7;
418
            // if 01 Jan of the next year is Monday to Thursday, is considered 1st week of the next year 
419
            // if 01 Jan is Friday to Sunday, is considered 53rd week of the current year
420
            weekNumber = nextYearFirstDay < 4 ? 1 : 53;
421
        }
422
        return weekNumber;
423
    }
424

425
    private generateICalendarDate(date: Date, year: number, month: number): ICalendarDate {
426
        return {
427
            date,
428
            isCurrentMonth: date.getFullYear() === year && date.getMonth() === month,
429
            isNextMonth: this.isNextMonth(date, year, month),
430
            isPrevMonth: this.isPreviousMonth(date, year, month)
431
        };
432
    }
433

434
    private isPreviousMonth(date: Date, year: number, month: number): boolean {
435
        if (date.getFullYear() === year) {
436
            return date.getMonth() < month;
437
        }
438
        return date.getFullYear() < year;
439
    }
440

441
    private isNextMonth(date: Date, year: number, month: number): boolean {
442
        if (date.getFullYear() === year) {
443
            return date.getMonth() > month;
444
        }
445

446
        return date.getFullYear() > year;
447
    }
448
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc