mirror of
				https://github.com/MichMich/MagicMirror.git
				synced 2025-10-31 10:48:10 +00:00 
			
		
		
		
	New calendar display format with date headers for days and times listed next to events for that date
IE: Sunday, May 1st 2:00 pm Soccer 4:00 pm Basketball
This commit is contained in:
		
							
								
								
									
										2
									
								
								modules/default/calendar/README.md
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										2
									
								
								modules/default/calendar/README.md
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -41,7 +41,7 @@ The following properties can be configured: | ||||
| | `displayRepeatingCountTitle` | Show count title for yearly repeating events (e.g. "X. Birthday", "X. Anniversary") <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false` | ||||
| | `dateFormat`                 | Format to use for the date of events (when using absolute dates) <br><br> **Possible values:** See [Moment.js formats](http://momentjs.com/docs/#/parsing/string-format/) <br> **Default value:** `MMM Do` (e.g. Jan 18th) | ||||
| | `fullDayEventDateFormat`     | Format to use for the date of full day events (when using absolute dates) <br><br> **Possible values:** See [Moment.js formats](http://momentjs.com/docs/#/parsing/string-format/) <br> **Default value:** `MMM Do` (e.g. Jan 18th) | ||||
| | `timeFormat`                 | Display event times as absolute dates, or relative time <br><br> **Possible values:** `absolute` or `relative` <br> **Default value:** `relative` | ||||
| | `timeFormat`                 | Display event times as absolute dates, or relative time, or using absolute date headers with times for each event next to it <br><br> **Possible values:** `absolute` or `relative` or `dateheader` <br> **Default value:** `relative` | ||||
| | `getRelative`                | How much time (in hours) should be left until calendar events start getting relative? <br><br> **Possible values:** `0` (events stay absolute) - `48` (48 hours before the event starts) <br> **Default value:** `6` | ||||
| | `urgency`                    | When using a timeFormat of `absolute`, the `urgency` setting allows you to display events within a specific time frame as `relative`. This allows events within a certain time frame to be displayed as relative (in xx days) while others are displayed as absolute dates <br><br> **Possible values:** a positive integer representing the number of days for which you want a relative date, for example `7` (for 7 days) <br><br> **Default value:** `7` | ||||
| | `broadcastEvents`            | If this property is set to true, the calendar will broadcast all the events to all other modules with the notification message: `CALENDAR_EVENTS`. The event objects are stored in an array and contain the following fields: `title`, `startDate`, `endDate`, `fullDayEvent`, `location` and `geo`. <br><br> **Possible values:** `true`, `false` <br><br> **Default value:** `true` | ||||
|   | ||||
							
								
								
									
										199
									
								
								modules/default/calendar/calendar.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										199
									
								
								modules/default/calendar/calendar.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -132,8 +132,29 @@ Module.register("calendar", { | ||||
| 			return wrapper; | ||||
| 		} | ||||
|  | ||||
| 		var lastSeenDate = ''; | ||||
|  | ||||
| 		for (var e in events) { | ||||
| 			var event = events[e]; | ||||
| 			var dateAsString = moment(event.startDate, "x").format(this.config.dateFormat); | ||||
| 			if(this.config.timeFormat === "dateheaders"){ | ||||
| 				if(lastSeenDate !== dateAsString){ | ||||
| 					var dateRow = document.createElement("tr"); | ||||
| 					dateRow.className = "normal" | ||||
| 					var dateCell = document.createElement("td"); | ||||
|  | ||||
| 					dateCell.colSpan = "3"; | ||||
| 					dateCell.innerHTML = dateAsString; | ||||
| 					dateRow.appendChild(dateCell); | ||||
| 					wrapper.appendChild(dateRow); | ||||
|  | ||||
|  | ||||
| 					lastSeenDate = dateAsString; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
|  | ||||
| 			 | ||||
| 			var eventWrapper = document.createElement("tr"); | ||||
|  | ||||
| 			if (this.config.colored && !this.config.coloredSymbolOnly) { | ||||
| @@ -164,6 +185,10 @@ Module.register("calendar", { | ||||
| 					symbolWrapper.appendChild(symbol); | ||||
| 				} | ||||
| 				eventWrapper.appendChild(symbolWrapper); | ||||
| 			}else if(this.config.timeFormat === "dateheaders"){ | ||||
| 				var blankCell = document.createElement("td"); | ||||
| 				blankCell.innerHTML = "   " | ||||
| 				eventWrapper.appendChild(blankCell); | ||||
| 			} | ||||
|  | ||||
| 			var titleWrapper = document.createElement("td"), | ||||
| @@ -189,89 +214,123 @@ Module.register("calendar", { | ||||
| 				titleWrapper.className = "title"; | ||||
| 			} | ||||
|  | ||||
| 			eventWrapper.appendChild(titleWrapper); | ||||
|  | ||||
| 			var timeWrapper = document.createElement("td"); | ||||
| 			//console.log(event.today); | ||||
| 			var now = new Date(); | ||||
| 			// Define second, minute, hour, and day variables | ||||
| 			var oneSecond = 1000; // 1,000 milliseconds | ||||
| 			var oneMinute = oneSecond * 60; | ||||
| 			var oneHour = oneMinute * 60; | ||||
| 			var oneDay = oneHour * 24; | ||||
| 			if (event.fullDayEvent) { | ||||
| 				if (event.today) { | ||||
| 					timeWrapper.innerHTML = this.capFirst(this.translate("TODAY")); | ||||
| 				} else if (event.startDate - now < oneDay && event.startDate - now > 0) { | ||||
| 					timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW")); | ||||
| 				} else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) { | ||||
| 					if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") { | ||||
| 						timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW")); | ||||
| 					} else { | ||||
| 						timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 					} | ||||
| 				} else { | ||||
| 					/* Check to see if the user displays absolute or relative dates with their events | ||||
| 					 * Also check to see if an event is happening within an 'urgency' time frameElement | ||||
| 					 * For example, if the user set an .urgency of 7 days, those events that fall within that | ||||
| 					 * time frame will be displayed with 'in xxx' time format or moment.fromNow() | ||||
| 					 * | ||||
| 					 * Note: this needs to be put in its own function, as the whole thing repeats again verbatim | ||||
| 					 */ | ||||
| 					if (this.config.timeFormat === "absolute") { | ||||
| 						if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) { | ||||
| 							// This event falls within the config.urgency period that the user has set | ||||
| 							timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 						} else { | ||||
| 							timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat)); | ||||
| 			if(this.config.timeFormat === "dateheaders"){ | ||||
| 				 | ||||
| 				if (event.fullDayEvent) { | ||||
| 					titleWrapper.colSpan = "2"; | ||||
| 					titleWrapper.align = "left"; | ||||
| 					 | ||||
| 				}else{ | ||||
| 					var timeWrapper = document.createElement("td"); | ||||
| 					timeWrapper.className = "time light"; | ||||
| 					timeWrapper.align = "left"; | ||||
| 					timeWrapper.style.paddingLeft = "2px"; | ||||
| 					var timeFormatString = ""; | ||||
| 					switch (config.timeFormat) { | ||||
| 						case 12: { | ||||
| 							timeFormatString = "h:mm A"; | ||||
| 							break; | ||||
| 						} | ||||
| 						case 24: { | ||||
| 							timeFormatString = "HH:mm"; | ||||
| 							break; | ||||
| 						} | ||||
| 						default: { | ||||
| 							timeFormatString = "HH:mm"; | ||||
| 							break; | ||||
| 						} | ||||
| 					} else { | ||||
| 						timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 					} | ||||
| 					timeWrapper.innerHTML = moment(event.startDate, "x").format(timeFormatString); | ||||
| 					eventWrapper.appendChild(timeWrapper); | ||||
| 					titleWrapper.align = "right"; | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (event.startDate >= new Date()) { | ||||
| 					if (event.startDate - now < 2 * oneDay) { | ||||
| 						// This event is within the next 48 hours (2 days) | ||||
| 						if (event.startDate - now < this.config.getRelative * oneHour) { | ||||
| 							// If event is within 6 hour, display 'in xxx' time format or moment.fromNow() | ||||
| 							timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 				 | ||||
| 				eventWrapper.appendChild(titleWrapper); | ||||
| 			}else{ | ||||
| 				var timeWrapper = document.createElement("td"); | ||||
|  | ||||
| 				eventWrapper.appendChild(titleWrapper); | ||||
| 				//console.log(event.today); | ||||
| 				var now = new Date(); | ||||
| 				// Define second, minute, hour, and day variables | ||||
| 				var oneSecond = 1000; // 1,000 milliseconds | ||||
| 				var oneMinute = oneSecond * 60; | ||||
| 				var oneHour = oneMinute * 60; | ||||
| 				var oneDay = oneHour * 24; | ||||
| 				if (event.fullDayEvent) { | ||||
| 					if (event.today) { | ||||
| 						timeWrapper.innerHTML = this.capFirst(this.translate("TODAY")); | ||||
| 					} else if (event.startDate - now < oneDay && event.startDate - now > 0) { | ||||
| 						timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW")); | ||||
| 					} else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) { | ||||
| 						if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") { | ||||
| 							timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW")); | ||||
| 						} else { | ||||
| 							// Otherwise just say 'Today/Tomorrow at such-n-such time' | ||||
| 							timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar()); | ||||
| 							timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 						} | ||||
| 					} else { | ||||
| 						/* Check to see if the user displays absolute or relative dates with their events | ||||
| 						 * Also check to see if an event is happening within an 'urgency' time frameElement | ||||
| 						 * For example, if the user set an .urgency of 7 days, those events that fall within that | ||||
| 						 * time frame will be displayed with 'in xxx' time format or moment.fromNow() | ||||
| 						 * | ||||
| 						 * Note: this needs to be put in its own function, as the whole thing repeats again verbatim | ||||
| 						 */ | ||||
| 						* Also check to see if an event is happening within an 'urgency' time frameElement | ||||
| 						* For example, if the user set an .urgency of 7 days, those events that fall within that | ||||
| 						* time frame will be displayed with 'in xxx' time format or moment.fromNow() | ||||
| 						* | ||||
| 						* Note: this needs to be put in its own function, as the whole thing repeats again verbatim | ||||
| 						*/ | ||||
| 						if (this.config.timeFormat === "absolute") { | ||||
| 							if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) { | ||||
| 								// This event falls within the config.urgency period that the user has set | ||||
| 								timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 							} else { | ||||
| 								timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat)); | ||||
| 								timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat)); | ||||
| 							} | ||||
| 						} else { | ||||
| 							timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					timeWrapper.innerHTML = this.capFirst( | ||||
| 						this.translate("RUNNING", { | ||||
| 							fallback: this.translate("RUNNING") + " {timeUntilEnd}", | ||||
| 							timeUntilEnd: moment(event.endDate, "x").fromNow(true) | ||||
| 						}) | ||||
| 					); | ||||
| 					if (event.startDate >= new Date()) { | ||||
| 						if (event.startDate - now < 2 * oneDay) { | ||||
| 							// This event is within the next 48 hours (2 days) | ||||
| 							if (event.startDate - now < this.config.getRelative * oneHour) { | ||||
| 								// If event is within 6 hour, display 'in xxx' time format or moment.fromNow() | ||||
| 								timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 							} else { | ||||
| 								// Otherwise just say 'Today/Tomorrow at such-n-such time' | ||||
| 								timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar()); | ||||
| 							} | ||||
| 						} else { | ||||
| 							/* Check to see if the user displays absolute or relative dates with their events | ||||
| 							* Also check to see if an event is happening within an 'urgency' time frameElement | ||||
| 							* For example, if the user set an .urgency of 7 days, those events that fall within that | ||||
| 							* time frame will be displayed with 'in xxx' time format or moment.fromNow() | ||||
| 							* | ||||
| 							* Note: this needs to be put in its own function, as the whole thing repeats again verbatim | ||||
| 							*/ | ||||
| 							if (this.config.timeFormat === "absolute") { | ||||
| 								if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) { | ||||
| 									// This event falls within the config.urgency period that the user has set | ||||
| 									timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 								} else { | ||||
| 									timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat)); | ||||
| 								} | ||||
| 							} else { | ||||
| 								timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); | ||||
| 							} | ||||
| 						} | ||||
| 					} else { | ||||
| 						timeWrapper.innerHTML = this.capFirst( | ||||
| 							this.translate("RUNNING", { | ||||
| 								fallback: this.translate("RUNNING") + " {timeUntilEnd}", | ||||
| 								timeUntilEnd: moment(event.endDate, "x").fromNow(true) | ||||
| 							}) | ||||
| 						); | ||||
| 					} | ||||
| 				} | ||||
| 				//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll'); | ||||
| 				//console.log(event); | ||||
| 				timeWrapper.className = "time light"; | ||||
| 				eventWrapper.appendChild(timeWrapper); | ||||
| 			} | ||||
| 			//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll'); | ||||
| 			//console.log(event); | ||||
| 			timeWrapper.className = "time light"; | ||||
| 			eventWrapper.appendChild(timeWrapper); | ||||
|  | ||||
| 			wrapper.appendChild(eventWrapper); | ||||
|  | ||||
| @@ -359,6 +418,9 @@ Module.register("calendar", { | ||||
| 						continue; | ||||
| 					} | ||||
| 				} | ||||
|         if(this.listContainsEvent(events,event)){ | ||||
| 					continue; | ||||
| 				} | ||||
| 				event.url = c; | ||||
| 				event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000); | ||||
| 				events.push(event); | ||||
| @@ -372,6 +434,17 @@ Module.register("calendar", { | ||||
| 		return events.slice(0, this.config.maximumEntries); | ||||
| 	}, | ||||
|  | ||||
|  | ||||
| 	listContainsEvent: function(eventList, event){ | ||||
| 		for(let evt of eventList){ | ||||
| 			if(evt.title === event.title && parseInt(evt.startDate) === parseInt(event.startDate)){ | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
|  | ||||
| 	}, | ||||
|  | ||||
| 	/* createEventList(url) | ||||
| 	 * Requests node helper to add calendar url. | ||||
| 	 * | ||||
|   | ||||
		Reference in New Issue
	
	Block a user