MagicMirror Forum
    • Recent
    • Tags
    • Unsolved
    • Solved
    • MagicMirror² Repository
    • Documentation
    • 3rd-Party-Modules
    • Donate
    • Discord
    • Register
    • Login
    A New Chapter for MagicMirror: The Community Takes the Lead
    Read the statement by Michael Teeuw here.

    MMM-CalendarExt3

    Scheduled Pinned Locked Moved Utilities
    676 Posts 81 Posters 2.4m Views 85 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • S Offline
      sdetweil @Ragged4310
      last edited by

      @Ragged4310 said in MMM-CalendarExt3:

      I understand this request may be complex, and if a solution isn’t feasible,

      its just code, if you can do it in your head, then code can do it…

      Sam

      How to add modules

      learning how to use browser developers window for css changes

      1 Reply Last reply Reply Quote 0
      • M Offline
        MMRIZE @Ragged4310
        last edited by

        @Ragged4310
        Sure, that’s doable. There’s no reason why it shouldn’t be possible.

        This kind of work is domain analysis, which is basically my real-world job.

        However, it’s not exactly simple. By simple, I mean it’ll take more than the usual 10 minutes I’d spend diving into this hobby project that genuinely interests me.

        And honestly, my rate is quite high. :D (Just kidding.)

        Let’s clarify a few things first.

        • CX3 is usually useful for viewing events from multiple calendars at once, so you’re probably using other types of calendars (e.g., personal meetings, family schedules) together. For this task, let’s assume that the target “customer reservation” events are in a separate, independent calendar. For convenience, I’ll call this calendar “Reservation” from now on.
        • Given the nature of calendars, I assume that there won’t be any overlapping events in the Reservation calendar. Additionally, I’ll assume there are no full-day events or events that span midnight.

        With these assumptions, I’ll give it a shot sometime tomorrow when I have some free time. I can’t make any promises, so please don’t get your hopes up too high.

        1 Reply Last reply Reply Quote 0
        • M Offline
          MMRIZE @Ragged4310
          last edited by MMRIZE

          @Ragged4310

          See the green events
          0771ed78-ac78-4934-a294-ffb5c971240e-image.png

          b4009779-62fa-4c74-975d-5d5460f16111-image.png

          eventPayload in CX3 config;

          /* CX3 config section in `config/config.js` */
          eventPayload: (payload) => {
          	const targetCalendar = "Reservation"
          	const divideGap = 1000 * 60 * 60 * 1
          	const locale = 'en-US'
          	const timeStyle = { timeStyle: 'short' }
          
          	const condition = (ev) => { return (ev.calendarName === targetCalendar && ev.fullDayEvent === false) }
          	const target = payload.filter(condition).sort((a, b) => a.endDate - b.endDate)
          	const result = payload.filter(e => !condition(e))
          	const dateStr = (dateValue) => Intl.DateTimeFormat(locale, timeStyle).format(new Date(+dateValue))
          	const collapse = (template, ev) => {
          		if (!template?.["title"]) template = { ...ev, collapseCount: 0, description: '', location: '' }
          		template.collapseCount++
          		template.startDate = String(Math.min(+template.startDate, +ev.startDate))
          		template.endDate = String(Math.max(+template.endDate, +ev.endDate))
          		template.title = `${dateStr(template.startDate)} - ${dateStr(template.endDate)}`
          		if (template.collapseCount > 1) template.title += ` <span class="count">${template.collapseCount}</span>`
          		template.description += `<div class="collapsedEvent">
          			<p class="title">${ev.title}</p>
          			<p class="period">${dateStr(ev.startDate)} - ${dateStr(ev.endDate)}</p>`
          		if (ev.description) template.description += `<p class="description">${ev.description}</p>`
          		if (ev.location) template.description += `<p class="location">${ev.location}</p>`
          		template.description += '</div>'
          		return template
          	}
          	const dateKey = (dateValue) => new Date(+dateValue).toLocaleDateString('en-CA')
          	let collapsedEvent = {}
          	for (const ev of target) {
          		const currentKey = dateKey(ev.startDate)
          		if (!collapsedEvent?.[ 'title' ]) {
          			collapsedEvent = collapse(collapsedEvent, ev)
          			continue
          		}
          		const collapsedKey = dateKey(collapsedEvent.startDate)
          		if (collapsedKey !== currentKey || +ev.startDate - +collapsedEvent.endDate > divideGap) {
          			result.push(collapsedEvent)
          			collapsedEvent = collapse({}, ev)
          		} else {
          			collapsedEvent = collapse(collapsedEvent, ev)
          		}
          	}
          	if (collapsedEvent?.[ 'title' ]) result.push(collapsedEvent)
          	return result
          }
          

          You can modify targetCalendar, divideGap, locale ande timeStyle for your purpose.

          To beautify;

          /* css/custom.css */
          .CX3 .event.calendar_Reservation .headline .time {
            display: none;
          }
          
          #CX3_POPOVER .title .count,
          .CX3 .calendar_Reservation .title .count {
            font-weight: bold;
            color: gray;
          }
          
          #CX3_POPOVER .title .count::before,
          .CX3 .calendar_Reservation .title .count::before {
            content: "[";
          }
          
          #CX3_POPOVER .title .count::after,
          .CX3 .calendar_Reservation .title .count::after {
            content: "]";
          }
          
          #CX3_POPOVER .description .collapsedEvent {
            line-height: 115%;
            border-bottom: 2px solid silver;
          
            p {
              margin-top: 0;
              margin-bottom: 0;
            }
          
            .title {
              font-weight: bold;
            }
          
            .period {
              text-align: right;
            }
          
            .description {
              font-style: italic;
              white-space: pre;
              padding-left: 20px;
            }
          
            .location {
              font-style: italic;
              text-align: right;
            }
          }
          
          R 1 Reply Last reply Reply Quote 0
          • R Offline
            Ragged4310 @MMRIZE
            last edited by

            @MMRIZE said in MMM-CalendarExt3:

            @Ragged4310

            See the green events
            0771ed78-ac78-4934-a294-ffb5c971240e-image.png

            b4009779-62fa-4c74-975d-5d5460f16111-image.png

            eventPayload in CX3 config;

            /* CX3 config section in `config/config.js` */
            eventPayload: (payload) => {
            	const targetCalendar = "Reservation"
            	const divideGap = 1000 * 60 * 60 * 1
            	const locale = 'en-US'
            	const timeStyle = { timeStyle: 'short' }
            
            	const condition = (ev) => { return (ev.calendarName === targetCalendar && ev.fullDayEvent === false) }
            	const target = payload.filter(condition).sort((a, b) => a.endDate - b.endDate)
            	const result = payload.filter(e => !condition(e))
            	const dateStr = (dateValue) => Intl.DateTimeFormat(locale, timeStyle).format(new Date(+dateValue))
            	const collapse = (template, ev) => {
            		if (!template?.["title"]) template = { ...ev, collapseCount: 0, description: '', location: '' }
            		template.collapseCount++
            		template.startDate = String(Math.min(+template.startDate, +ev.startDate))
            		template.endDate = String(Math.max(+template.endDate, +ev.endDate))
            		template.title = `${dateStr(template.startDate)} - ${dateStr(template.endDate)}`
            		if (template.collapseCount > 1) template.title += ` <span class="count">${template.collapseCount}</span>`
            		template.description += `<div class="collapsedEvent">
            			<p class="title">${ev.title}</p>
            			<p class="period">${dateStr(ev.startDate)} - ${dateStr(ev.endDate)}</p>`
            		if (ev.description) template.description += `<p class="description">${ev.description}</p>`
            		if (ev.location) template.description += `<p class="location">${ev.location}</p>`
            		template.description += '</div>'
            		return template
            	}
            	const dateKey = (dateValue) => new Date(+dateValue).toLocaleDateString('en-CA')
            	let collapsedEvent = {}
            	for (const ev of target) {
            		const currentKey = dateKey(ev.startDate)
            		if (!collapsedEvent?.[ 'title' ]) {
            			collapsedEvent = collapse(collapsedEvent, ev)
            			continue
            		}
            		const collapsedKey = dateKey(collapsedEvent.startDate)
            		if (collapsedKey !== currentKey || +ev.startDate - +collapsedEvent.endDate > divideGap) {
            			result.push(collapsedEvent)
            			collapsedEvent = collapse({}, ev)
            		} else {
            			collapsedEvent = collapse(collapsedEvent, ev)
            		}
            	}
            	if (collapsedEvent?.[ 'title' ]) result.push(collapsedEvent)
            	return result
            }
            

            You can modify targetCalendar, divideGap, locale ande timeStyle for your purpose.

            To beautify;

            /* css/custom.css */
            .CX3 .event.calendar_Reservation .headline .time {
              display: none;
            }
            
            #CX3_POPOVER .title .count,
            .CX3 .calendar_Reservation .title .count {
              font-weight: bold;
              color: gray;
            }
            
            #CX3_POPOVER .title .count::before,
            .CX3 .calendar_Reservation .title .count::before {
              content: "[";
            }
            
            #CX3_POPOVER .title .count::after,
            .CX3 .calendar_Reservation .title .count::after {
              content: "]";
            }
            
            #CX3_POPOVER .description .collapsedEvent {
              line-height: 115%;
              border-bottom: 2px solid silver;
            
              p {
                margin-top: 0;
                margin-bottom: 0;
              }
            
              .title {
                font-weight: bold;
              }
            
              .period {
                text-align: right;
              }
            
              .description {
                font-style: italic;
                white-space: pre;
                padding-left: 20px;
              }
            
              .location {
                font-style: italic;
                text-align: right;
              }
            }
            

            I had to play around with it a bit to get it just right, but you nailed it!

            alt text

            My calendar is a lot less cluttered now. Thank you for all your help!

            1 Reply Last reply Reply Quote 0
            • G Offline
              GerrieD
              last edited by

              thanks for adding maxEventLines: { row: line, row: line, … } .

              But I am having trouble getting it to work.

              		 {
                         module: "MMM-CalendarExt3",
                         position: "top_right",
                         title: "",
                         instanceId: '1',
              		   config: {
                           mode: 'month',
                           carouselId: "basicCalendar",
                           locale: 'en-ZA',
              		     header: "",
                           //headerTitleOptions: {month: 'long' , year:'numeric'},
              		     eventTimeOptions: {timeStyle: 'short'},
              		     useWeather: false,
                           //maxEventLines: 1,
                           firstDayOfWeek: 1,
              		     displayEndTime: false,
              		     useMarquee: true,
              		     displayCW: false,
              		     showMore: true,
              		     showEnd: false,
              		     weekIndex: 0, // From which week the view starts; -1 : last week, 0: this week 2: 2 weeks later, ...
              		     //weeksInView: 5, // How many weeks will be shown from `weekIndex`
              		     fontSize: "18px",
                           eventHight: "20px",
              		     calendarSet: ['Pieter', 'US_holiday'],
              			 maxEventLines: { 4:6, 5:5, 6:4 , 7:3},
              		   }
                       },
              

              I would expect this line maxEventLines: { 4:6, 5:5, 6:4 , 7:3}, to limit the number of rows based on the number of weeks so this month has 6 week rows so the entries in the cell should be limited to 4?

              I even did a test case just to see if it would only make one line by doing this
              maxEventLines: { 3:1, 4:1, 5:1, 6:1 , 7:1, 8:1}, and it did not work.

              What am I missing.

              thanks for your help.

              M 1 Reply Last reply Reply Quote 0
              • M Offline
                MMRIZE @GerrieD
                last edited by

                @GerrieD
                Sorry, a hidden bug was only revealed in December—my fault. I fix it now. 1.9.4

                G 2 Replies Last reply Reply Quote 0
                • G Offline
                  GerrieD @MMRIZE
                  last edited by

                  @MMRIZE thanks for all your help.

                  I will update later and let you know if it worked.

                  1 Reply Last reply Reply Quote 0
                  • G Offline
                    GerrieD @MMRIZE
                    last edited by

                    @MMRIZE the updated fixed my issue.

                    thanks.

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      Decimeter9667 @MMRIZE
                      last edited by Decimeter9667

                      @MMRIZE

                      I’m working in the same situation: using an old iPad and trying to conserve space. I used this transform you posted way back in this thread:

                      /* In your config */
                      eventTransformer: (ev) => {
                        if (!ev.isFullday) {
                          let t = new Date(ev.startDate)
                          let time = (t.getMinutes() === 0) ? String(t.getHours()) : String(t.getHours() + ':' + t.getMinutes())
                          ev.title = `<span class="myTime">${time}</span> ${ev.title}`	
                        }
                        return ev 
                      }
                      

                      That works great, but how can I get it to display the hour in 12h, not 24h?

                      S 1 Reply Last reply Reply Quote 0
                      • S Offline
                        sdetweil @Decimeter9667
                        last edited by

                        @Decimeter9667 time see theIMG_0598.png eventTimeOptions

                        Sam

                        How to add modules

                        learning how to use browser developers window for css changes

                        D 1 Reply Last reply Reply Quote 0
                        • 1
                        • 2
                        • 57
                        • 58
                        • 59
                        • 60
                        • 61
                        • 67
                        • 68
                        • 59 / 68
                        • First post
                          Last post
                        Enjoying MagicMirror? Please consider a donation!
                        MagicMirror created by Michael Teeuw.
                        Forum managed by Sam, technical setup by Karsten.
                        This forum is using NodeBB as its core | Contributors
                        Contact | Privacy Policy