UNPKG

@hicoder/angular-cli

Version:

Angular UI componenets and service generator. It works with the mean-rest-express package to generate the end to end web application. The input to this generator is the Mongoose schema defined for the express application. mean-rest-express exposes the Res

386 lines (350 loc) 12.3 kB
import { Component, OnChanges, OnInit, Input, SimpleChanges, LOCALE_ID, Inject } from '@angular/core'; import { formatDate } from '@angular/common'; import { MddsCommonService } from '@hicoder/angular-core'; import { CalendarService, CalendarControlType, CalendarEventType, CalendarMessage, getRepeatTimeSlots, sortAndUniqueExcludes, } from '@hicoder/angular-calendar'; import { <%-SchemaName%>ListViewComponent } from './<%-schemaName%>-list-view.component'; @Component({ <%- include(`/widgets/list-view/component.template.custom.ts`)%> }) export class <%-SchemaName%><%-ComponentClassName%>Component extends <%-SchemaName%>ListViewComponent implements OnInit, OnChanges { public defaultCalendarView: string = '<%-calendarOptions.defaultView%>'; public weekHourRange: number[] = [<%-calendarOptions.weekHourRange.join(',')%>]; public isReadOnly: boolean = <%-calendarOptions.isReadOnly%>; public groupName: string = 'Categories'; private calendarFields = {<% for (let field of briefView) {%><% if (field.calendarGroup) {%> group: '<%-field.fieldName%>',<% }%><% if (field.calendarTitle) {%> title: '<%-field.fieldName%>',<% }%><% if (field.calendarStartTime) {%> start: '<%-field.fieldName%>',<% }%><% if (field.calendarEndTime) {%> end: '<%-field.fieldName%>',<% }%><% if (field.calendarRepeat) {%> repeat: '<%-field.fieldName%>',<% }%><% if (field.calendarRepeatStart) {%> repeatStart: '<%-field.fieldName%>',<% }%><% if (field.calendarRepeatEnd) {%> repeatEnd: '<%-field.fieldName%>',<% }%><% }%> }; private allGroups = new Set<string>(); private groups: string[] = []; private calendarFetchTime = new Map<string, number>(); // timestamp, keyed by month. private allDetails = new Map<string, any>(); private allSchedules = new Map<string, string[]>(); // schedule ids, keyed by detail id. private newSchedules: any[] = []; private updatedSchedules: any[] = []; private deletedSchedules: any[] = []; private calendarReady: boolean = false; private timeZone: string; private locale: string; private calendarID: string = ''; constructor( private commonService: MddsCommonService, public calendarService: CalendarService) { super(); this.locale = this.commonService.getLocale(); this.timeZone = this.commonService.getTimeZone(); this.groupName = this.calendarFields.group.charAt(0).toUpperCase() + this.calendarFields.group.slice(1); } override ngOnInit() { super.ngOnInit(); } ngOnChanges(changes: SimpleChanges) { // Take originalList. if (changes['originalList']) { this.generateSchedules(this.originalList as any[], false); } if (changes['editHintFields']) { this.createGroups(this.editHintFields); } if (changes['deletedItemIds']) { this.deleteSchedules(this.deletedItemIds); } } generateSchedules(list: any[], force: boolean) { for (let detail of list) { let d = this.allDetails.get(detail['_id']); if (!force && d && d[this.calendarFields.title] == detail[this.calendarFields.title] && d[this.calendarFields.group] == detail[this.calendarFields.group] && d[this.calendarFields.start] == detail[this.calendarFields.start] && d[this.calendarFields.end] == detail[this.calendarFields.end] && d[this.calendarFields.repeat] == detail[this.calendarFields.repeat] ) { // Schedule not changed. Skip; continue; } // Update the saved details. this.allDetails.set(detail['_id'], detail); // Delete the existing schedules. if (d) { let oldSchedules = this.allSchedules.get(detail['_id']); if (oldSchedules) { for (let sId of oldSchedules) { this.deletedSchedules.push({ id: sId, calendarId: d[this.calendarFields.group], }); } } this.allSchedules.delete(detail['_id']); } let grp = detail[this.calendarFields.group]; if (grp && !this.allGroups.has(grp)) { this.groups.push(grp); this.allGroups.add(grp); } let timeSlots: string[][] = [[detail[this.calendarFields.start], detail[this.calendarFields.end]]]; if (detail[this.calendarFields.repeat]) { timeSlots = getRepeatTimeSlots( this.timeZone, detail[this.calendarFields.start], detail[this.calendarFields.end], detail[this.calendarFields.repeat], ) } let sIds: string[] = []; for (let [i, slot] of timeSlots.entries()) { let sId = `${detail['_id']}_${i}`; let schedule: any = { id: sId, calendarId: grp, title: detail[this.calendarFields.title], category: 'time', dueDateClass: '', isAllDay: false, start: slot[0], end: slot[1], recurrenceRule: detail[this.calendarFields.repeat], } this.newSchedules.push(schedule); sIds.push(sId); } this.allSchedules.set(detail['_id'], sIds); } this.notifyCalendar(); } deleteSchedules(ids: string[]) { for (let id of ids) { let d = this.allDetails.get(id); if (!d) { continue; } this.allDetails.delete(id); let oldSchedules = this.allSchedules.get(id); if (!oldSchedules) { continue; } for (let sId of oldSchedules) { this.deletedSchedules.push({ id: sId, calendarId: d[this.calendarFields.group], }); } this.allSchedules.delete(id); } this.notifyCalendar(); } // Schedule has been updated. changedSchedule(changes: any) { if (!changes['changes'] || !changes['schedule']) { return; } let detailId = this.formatID(changes['schedule']['id']); let d = this.allDetails.get(detailId); if (!d) { return; } // Start or end time has changed for this schedule. Probably through UI drag. if (changes['changes']['start']) { d[this.calendarFields.start] = changes['changes']['start'].toDate().toISOString(); } if (changes['changes']['end'] ) { d[this.calendarFields.end] = changes['changes']['end'].toDate().toISOString(); } // Notify the parent of the change. this.onChanged(d); // Update the schedule in the calendar. this.generateSchedules([d], true); } viewSchedule(id: string) { this.onEmbeddedDetail(this.formatID(id)); } updateSchedule(id: string) { this.onEmbeddedEdit(this.formatID(id)); } deleteSchedule(id: string) { this.onDelete(this.formatID(id), null); } deleteOneSchedule(schedule: any) { let detailId = this.formatID(schedule.id); let d = this.allDetails.get(detailId); if (!d || !d.repeat) { return; } let repeatObj = JSON.parse(d.repeat); if (!repeatObj.exclude) { repeatObj.exclude = []; } repeatObj.exclude.push(schedule['start'].toDate().toISOString()); repeatObj.exclude = sortAndUniqueExcludes(repeatObj.exclude, this.timeZone); d.repeat = JSON.stringify(repeatObj); this.onChanged(d); this.generateSchedules([d], true); } addSchedule(schedule: any) { let detail: any = {}; // Start or end time should be available for this schedule. if (schedule['start']) { detail[this.calendarFields.start] = schedule['start'].toDate().toISOString(); } if (schedule['end'] ) { detail[this.calendarFields.end] = schedule['end'].toDate().toISOString(); } // Notify the parent of the new added schedule. Allow parent to change the start/end date. this.onEmbeddedAdd(detail, true); } createGroups(editHintFields: any) { let grps = this.editHintFields[this.calendarFields.group]||[]; grps = grps.map((x: any) => {return x['_id']}); for (let grp of grps) { if (!grp || this.allGroups.has(grp)) { continue; } this.groups.push(grp); this.allGroups.add(grp); } this.notifyCalendar(); } getCalendarData(d: Date) { this.notifyCalendar(); let date = new Date(d); date.setDate(1); let year = date.getFullYear(); let month = date.getMonth(); let monthStr = formatDate(date, 'y-MM', 'en-US'); date.setMonth(month+1); let monthStrNext = formatDate(date, 'y-MM', 'en-US'); date.setMonth(month-1); let monthStrPre = formatDate(date, 'y-MM', 'en-US'); let monthCache = this.calendarFetchTime.get(monthStr); let monthCacheNext = this.calendarFetchTime.get(monthStrNext); let monthCachePre = this.calendarFetchTime.get(monthStrPre); let currentTime = new Date().getTime(); let invalidateTime = currentTime - 1000 * 120; // 120 seconds. let monthPreCached = monthCachePre && monthCachePre > invalidateTime; let monthCached = monthCache && monthCache > invalidateTime; let monthNextCached = monthCacheNext && monthCacheNext > invalidateTime; let dateFrom = new Date(year, month-1, 1); let dateTo = new Date(year, month+2, 1); let detail:any = {}; detail[this.calendarFields.repeatStart] = { to: {year:dateTo.getFullYear(), month: dateTo.getMonth()+1, day: 1}, } detail[this.calendarFields.repeatEnd] = { from: {year:dateFrom.getFullYear(), month: dateFrom.getMonth()+1, day: 1}, } if (monthCached && monthPreCached && monthNextCached) { this.processSearchContext(detail); return; } this.searchListAll(detail); this.calendarFetchTime.set(monthStrPre, currentTime); this.calendarFetchTime.set(monthStr, currentTime); this.calendarFetchTime.set(monthStrNext, currentTime); } public onCalendarMessage(message: CalendarMessage) { // console.log('calendarEvent: ', message); switch (message.type) { case CalendarEventType.viewSchedule: this.viewSchedule(message.event.id); break; case CalendarEventType.addSchedule: this.addSchedule(message.event); break; case CalendarEventType.changedSchedule: this.changedSchedule(message.event); break; case CalendarEventType.updateSchedule: this.updateSchedule(message.event.id); break; case CalendarEventType.deleteSchedule: this.deleteSchedule(message.event.id); break; case CalendarEventType.deleteOneSchedule: this.deleteOneSchedule(message.event); break; case CalendarEventType.newDate: if (!this.calendarReady) { this.calendarReady = true; this.calendarID = message.id; // Get data with timeout to avoid list change during initialization. setTimeout(()=> { this.getCalendarData(message.event as Date); }, 50) } else { this.getCalendarData(message.event as Date); } break; } } private notifyCalendar() { if (!this.calendarReady || !this.calendarID) { return; } if (this.deletedSchedules.length > 0) { let schedules = this.deletedSchedules; this.deletedSchedules = []; this.calendarService.publishCalendarEvent({ type: CalendarControlType.delSchedules, id: this.calendarID, event: schedules, }); } if (this.newSchedules.length > 0) { let schedules = this.newSchedules; this.newSchedules = []; this.calendarService.publishCalendarEvent({ type: CalendarControlType.newSchedules, id: this.calendarID, event: schedules, }); } if (this.updatedSchedules.length > 0) { let schedules = this.updatedSchedules; this.updatedSchedules = []; this.calendarService.publishCalendarEvent({ type: CalendarControlType.updSchedules, id: this.calendarID, event: schedules, }); } if (this.groups.length > 0) { let groups = this.groups; this.groups = []; this.calendarService.publishCalendarEvent({ type: CalendarControlType.newGroups, id: this.calendarID, event: groups, }); } } private formatID(id: string): string { return id.split('_')[0]; } }