Git Product home page Git Product logo

mmm-calendarext3's Introduction

MMM-CalendarExt3

MagicMirror module for calendar view.

Screenshot

screenshot

Concept

My previous module, MMM-CalendarExt2, was always notorious for its difficulty to use. I need a more easy and light one. So I re-write this from scratch newly.

Features

What's different with CX2.

  • Only focusing on how it shows; Parsing is delegated to original MagicMirror module calendar. (It means the calendar module is REQUIRED to use this module.)
  • Only week and month views. I found that people are rarely interested in other views on CX2. So I drop out different views.
  • Respect to original MM's hide/show mechanism. Now you can hide/show this module easily with other scheduler or control modules. (By the way, Look at this module also. - MMM-Scenes)
  • No dependency on the 3rd party modules (e.g. momentJS or Luxon, etc.). This is built with pure JS and CSS only.

Main Features

  • week view or month view
  • locale-aware calendar
  • customizing events: filtering, sorting, transforming
  • multi-instance available. You don't need to copy and rename the module. Just add one more configuration in your config.js.

Install OR Update

cd ~/MagicMirror/modules
git clone https://github.com/MMRIZE/MMM-CalendarExt3
cd MMM-CalendarExt3
npm install
git submodule update --init --recursive

Usually, the last line is needless because it would be executed automatically in npm install , but many people forgot to execute npm install, so I'm exaggarating.

When some submodule seems not installed and updated properly, try this.

cd ~/MagicMirror/modules/MMM-CalendarExt3
git submodule update --init --recursive

If you want to return to 1.2.6 version,

cd ~/MagicMirror/modules/MMM-CalendarExt3
git checkout snap-1.2.6

Config

Anyway, even this simplest will work.

{
  module: "MMM-CalendarExt3",
  position: "bottom_bar",
},

More conventional;

{
  module: "MMM-CalendarExt3",
  position: "bottom_bar",
  title: "",
  config: {
    mode: "month",
    instanceId: "basicCalendar",
    locale: 'de-DE',
    maxEventLines: 5,
    firstDayOfWeek: 1,
    calendarSet: ['us_holiday', 'abfall', 'mytest'],
    ...
  }
},

You need setup default calendar configuration also.

/* default/calendar module configuration */
{
  module: "calendar",
  position: "top_left",
  config: {
    broadcastPastEvents: true, // <= IMPORTANT to see past events
    calendars: [
      {
        url: "webcal://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics",
        name: "us_holiday", // <= RECOMMENDED to assign name
        color: "red" // <= RECOMMENDED to assign color
      },
      ...

Config details

All the properties are omittable, and if omitted, a default value will be applied.

property default description
mode 'week' Calendar view type. You can choose between 'week', 'month', 'day'
weekIndex -1 Which week starts in a week view. -1 is the previous week of the current focusing moment. 0 is the focusing week of the moment. 1 will be the next week, and so on.
Ignored on mode:'month' and mode:'week'.
dayIndex -1 Which day starts in a day view. -1 is the previous day of the current focusing moment, 0 is the focusing day of the moment. 1 will be the next day, and so on.
Ignored on mode:'month' and mode:'week'.
weeksInView 3 How many weeks from the index.
weekIndex:-1, weeksInView:3 means 3 weeks view from the last week.
Ignored on mode:'month'
instanceId (auto-generated) When you want more than 1 instance of this module, each instance would need this value to distinguish each other. If you don't assign this property, the identifier of the module instance will be assigned automatically but not recommended to use it. (Hard to guess the auto-assigned value.)
locale (language of MM config) de or ko-KR or ja-Jpan-JP-u-ca-japanese-hc-h12. It defines how to handle and display your date-time values by the locale. When omitted, the default language config value of MM.
calendarSet [] When you want to display only selected calendars, fulfil this array with the targeted calendar name(of the default calendar module).
e.g) calendarSet: ['us_holiday', 'office'],
[] or null will allow all the calendars.
maxEventLines 5 How many events will be displayed in 1-day cell. The overflowed events will be hidden.
fontSize '18px' Default font size of this module.
eventHeight '22px' The height of each event.
cellDateOptions {month: 'short',
day: 'numeric'}
The format of day cell date. It varies by the locale and this option.
locale:'en-US', the default displaying will be Jun 1 or 1.
See options
eventTimeOptions {timeStyle: 'short'} The format of event time. It varies by the locale and this option.
locale:'en-US', the default displaying will be 3:45 pm.
See options
headerWeekDayOptions {weekday: 'long'} The format of weekday header. It varies by the locale and this option.
locale:'en-US', the default displaying will be Tuesday.
See options
headerTitleOptions {month: 'long'} The format of module header of the month view. It varies by the locale and this option.
locale:'en-US', the default displaying will be December. In mode:'week', this will be ignored.
See options
eventFilter callback function See the Filtering part.
eventSorter callback function See the Sorting part.
eventTransformer callback function See the Transforming part.
waitFetch 5000 (ms) waiting the fetching of last calendar to prevent flickering view by too frequent fetching.
refreshInterval 1800000 (ms) refresh view by force if you need it.
animationSpeed 1000 (ms) Refreshing the view smoothly.
useSymbol true Whether to show font-awesome symbold instead of simple dot icon.
displayLegend false If you set as true, legend will be displayed. (Only the clanear which has name assigned)
eventNotification 'CALENDAR_EVENTS' A carrier notification of event source.
eventPayload callback function A converter for event payload before using it.
useWeather true Whether to show forecasted weather information of default weather module.
weatherLocationName null When you have multi forecasting instances of several locations, you can describe specific weather location to show.
weatherNotification 'WEATHER_UPDATED' A carrier notification of weather forecasting source
weatherPayload callback function A converter for weather foracasting payload before using it.
displayWeatherTemp false If you want to show the temperature of the forecasting, set this to true
preProcessor callback function See the preProcessing part.
manipulateDateCell callback function See the manipulating dateCell part.
displayEndTime false If you want to show the end time of the event, set this to true
popoverTemplate './popover.html' If you want to change the template of popover, use this. (Usually not needed)
popoverPeriodOptions {timeStyle: 'short', dateStyle: 'short'} The format of period of event time on popover displayed,
It varies by the locale and the period itself how consisted.
See options
popoverTimeout 30000 (ms) The popover has light dismiss but for the convenience, I added timeout dismission.
0 will not dismiss popover forever unless other popover activated or you dismiss popover by click outside manually
animateIn 'fadeIn' Animation effect on refresh. (Since MM 2.25)
animateOut 'fadeOut' Animation effect on refresh. (Since MM 2.25)
skipPassedEventToday false If set true, the passed singleday events (not fullday, not multiday events) of today will be disappeard to save screen asset. It will be useful when you have too many events to show in maxEventLines. It will be applied only for today.
showMore true When the number of events is more than maxEventLines, the number of overflowed events would be displayed in the right-bottom cornor of the cell. And also it will popover whole day event list by click/touch it.
useIconify false If set true, You can use iconify-icon instead of fontawesome.
weekends auto-filled by locale. (Array of day order). e.g. weekends: [1, 3] means Monday and Wedneseday would be regarded as weekends. Usually you don't have to set this value.
Auto-filled by locale unless you set manually.
firstDayOfWeek auto-filled by locale Monday is the first day of the week according to the international standard ISO 8601, but in the US, Canada, Japan and some cultures, it's counted as the second day of the week. If you want to start the week from Monday, set this property to 1. If you want Sunday, set 0.
Sunday:0, Monday:1, Tuesday:2, ..., Saturday:6
Auto-filled by locale unless you set manually.
minimalDaysOfNewYear auto-filled by locale ISO 8601 also says each week's year is the Gregorian year in which the Thursday falls. The first week of the year, hence, always contains 4 January. However, the US (Yes, it is.) system differs from standards. In the US, containing 1 January defines the first week. In that case, set this value to 1. And under some other culture, you might need to modify this.
Auto-filled by locale unless you set manually.

Notification

Incoming Notifications

(deprecated) CX3_MOVE_CALENDAR, payload: {instanceId, step}

CX3_GLANCE_CALENDAR, payload: {instanceId, step}

Jump calendar view to another moment. It will return after refreshInterval from last notification command.

  • instanceId : If you have more than 1 instance of this module, you can specify the instance to manipulate. If omitted or null, all instances would obey this notification order.
  • step : How many leaps of the current view. In mode:'week' 1 step will be a week. In mode:'month' 1 step will be a month. Negative value is allowed.

CX3_SET_DATE, payload: {instanceId, date}

Set the date of specific view.

  • instanceId : See the above
  • date : Specific date to move. e.g) In mode:'month', date: "2022-12-25" would display calendar view of 2022 Decemeber. Be aware of weekIndex of mode:'week'. The view range will be calculated with weekIndex, weeksInView and this value.

CX3_RESET

Return to the default view instantly. (no payload)

CALENDAR_EVENTS

Any module which can emit this notification could become the source of this module. Generally, the default calendar module would be.

WEATHER_UPDATED

Any module which can emit this notification could become the source of weather forecasting. Generally, the default weather module would be.

Outgoing Notification

Nothing yet. (Does it need?)

Styling with CSS

You can handle almost all of the visual things with CSS. See the module.css and override your needs into your custom.css.

  • CX3, CX3_{instanceId}, mode_week or mode_month : The root selector. Each instance of this module will have CX3_{instanceId} as another root selector. With this CSS selector, you can assign individual look to each instance.
.CX3 {
  /* you CAN modify these values; but SHOULD NOT to remove */
  --celllinecolor: #333;
  --cellbgcolor: rgba(0, 0, 0, 0.2);
  --cellheaderheight: 25px;
  --cellfooterheight: 2px;
  --defaultcolor: #FFF;
  --eventheight: calc(var(--fontsize) + 4px);
  --totalheight: calc(var(--eventheight) * var(--maxeventlines));
  font-size: var(--fontsize);
  color: var(--defaultcolor);
  line-height: calc(var(--eventheight))
}

Most commonly used values would be defined in .CX3 selector as variables.

--fontsize, --maxeventlines, --eventheight would be imported from configuration for your setup convenience.

  • .cell : Every day cell has this selector. Each cell could have these class name together by its condition.

    • .today, .thisMonth, .thisYear
    • .year_2022, .month_12, .date_25, .weekday_0, weekend, weekend_1
  • .cellHeader, .cellFooter : Parts of day cell. .cellHeader would have .cw(count of week) and .cellDate as children.

    • .cellHeader .cellDate : Displaying date of the cell. The date would have many parts of date/hour information from cellDateOptions of config.
  • .event : Every event has this selector. Each event could have these class name together by its condition.

    • .continueFromPreviousWeek, .continueToNextWeek
    • .calendar_{calendarName}, {class} : Orginal calendar
    • .passed, .future, .current,
    • .multiday, .singleday, .fullday

And event also has dataSet (data-*) as its attributes. (e.g. data-title="...", data-start-date="...") You can use these attributes also.

  • .event
    • .headline
      • .symbol
      • .time.startTime
        • .dateParts
      • .time.endTime
        • .dateParts
      • .title
    • .description
    • .location

Each event component would be shown/hidden by the virtues of events. Of course, you can redeclare its behaviors with CSS.

  • .weekGrid, .weekGridRow : Definition of calendar grid. You can adjust the grid itself. (e.g. Shrink the width of weekend cells)

Handling Events

Each event object has this structure.

{
  "title": "Leeds United - Chelsea",
  "startDate": 1650193200000,
  "endDate": 1650199500000,
  "fullDayEvent": false,
  "class": "PUBLIC",
  "location": false,
  "geo": false,
  "description": "...",
  "today": false,
  "symbol": ["calendar-alt"],
  "calendarName": "tottenham",
  "color": "gold",
  "calendarSeq": 1, // This would be the order from `calendarSet` of configuration
  "isPassed": true,
  "isCurrent": false,
  "isFuture": false,
  "isFullday": false,
  "isMultiday": false,
  "skip": false, // If this is set, event will not be rendered.
}

You can use these values to handle events.

Filtering

You can filter each event by its condition.

eventFilter: (ev) => {
  if (ev.isFullday) return false
  return true
}

This example shows how you can filter out 'fullday' events.

Sorting

You can sort each event by its condition. However, this module arranges events masonry with density. So displaying would not fit with your sorting intention. Anyway, try if you need it.

eventSorter: (a, b) => {
  return a.calendarSeq - b.calendarSeq
}

This example tries to sort events by calendar order in calendarSet.

Transforming

You can manipulate or change the properties of the event.

eventTransformer: (ev) => {
  if (ev.title.search('John') > -1) ev.color = 'blue'
  return ev
}

This example shows how you can transform the color of events when the event title has specific text.

eventPayload / weatherPayload

You can convert or transform the payload of incoming notification instantly before used in this module. It would be convenient when conversion or manipulating payload from uncompatible module.

weatherPayload: (payload) => {
  if (Array.isArray(payload?.forecastArray)) {
    payload.forecastArray = payload.forecastArray.map((f) => {
      f.maxTemperature = Math.round(f.maxTemperature * 9 / 5 + 32)
      f.minTemperature = Math.round(f.minTemperature * 9 / 5 + 32)
      return f
    })
  }
  return payload
},

This example show how to transform Celcius temperature to Fahrenheit units. (Original default weather module has a bug to deliver Fahrenheit temperature of broadcasted forecasts.)

preProcessor could be replaced with this eventPayload but for backward-compatibility I'll keep it for a while.

preProcessing

preProcessor: (ev) => {
  if (ev.title.includes('test')) return null
  if (ev.calendarName === 'Specific calendar') ev.startDate += 2 * 60 * 60 * 1000
  return ev
}

This example shows

  1. if the title of an event has "test", drop the event off

  2. then add 2 hours to the start time of events on the specific calendar.

Unlike eventTransformer, the preProcessor would be applied to raw data format of events from the default calendar module or equivalent after receiving notification.

This is the better place to adjust the event itself to make it compatible with this module before the main logic of the module handle and regularize events.

manipulating dateCell

manipulateDateCell: (cellDom, events) => {
  if (Array.isArray(events) && events.some(e => e.calendarName === 'Holidays')) {
    let dateIcon = document.createElement('span')
    dateIcon.classList.add('fa', 'fa-fas', 'fa-fw', 'fa-gift')
    let header = cellDom.querySelector('.cellHeader')
    let celldate = header.querySelector('.cellDate')
    header.insertBefore(dateIcon, celldate)
    // you don't need to return anything.
  }
}

If you want to handle date cell with events of that day, you can use it.

skip to draw

if an evnet has .skip: true attribute as a property, this event will not be rendered on the screen. However, it will remain in the data, so you can sort, filter or use that event. It will be especially useful in your custom manipulateDateCell.

For example; you can paint a date cell background instead of showing a holiday event itself., Or you can skip less-important events to save real-estate.

Generally, this attribute will not derived from the original calendar provider(e.g. default calendar module). You may need to assign the value by yourself with event-handling.

using iconify.

Even though fontawesome is the default icon framework of MM, there are many needs of iconify. And I prefer it to font-awesome. Now you can use iconify icons by config value useIconify: true

// In your calendar module config
defaultSymbolClassName: '', // <-- Important to identify iconify properly.
calendars: [
  {
    color: "red",
    symbol: "flag:us-4x3",
    url: "https://ics.calendarlabs.com/76/mm3137/US_Holidays.ics"
  },
  {
    color: "red",
    symbol: "fa fa-fw fa-flag",
    url: "https://ics.calendarlabs.com/76/mm3137/US_Holidays.ics"
  },
],

image

WARNING To use iconify, you should set defaultSymbolClassName: '', in your default calendar module. Ususally it is enough when you hide the original default calendar module to use with CX3. But if you want to use font-awesome icons together, you should add font-awesome classnames (e.g fa, fas, ...) by yourself.

Fun things

Weather forecast

When you are using MM's default weather forecasting, weather icon will be displayed on the day cell.

useWeather: true,
weatherLocationName: 'New York',
// Original weather module might have its location name with more details. (e.g. 'New York City, US'), but the partial text included would be acceptable for this attribute.
// When the location name would not match, warning messgage will be shown on dev console. Check it.

Not the bug, but...

  • The default calendar module cannot emit the exact starting time of multidays-fullday-event which is passing current moment. Always it starts from today despite of original event starting time. So this module displays these kinds of multidays-fullday-event weirdly.
  • I'll add TimeLine(MMM-CalendarExt3Timeline and TimeTable views/extended modules in future.

Latest Updates

1.7.0 (2023-11-12) (details)

  • ADDED skip of event Object property
  • ADDED skipPassedEventToday of config
  • FIXED eventTime color in multiday event
  • ADDED end-eventTime of multiday event (if not fullday event)
  • ADDED more, morePopover feature.
  • ADDED Support iconify
  • ADDED auto-detect firstDayOfWeek and minimalDaysOfNewYear

Full History

More Info.

Author

ko-fi

mmm-calendarext3's People

Contributors

eouia avatar btastic avatar jcherniak avatar kblankenship1989 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.