Advertisement
Guest User

Untitled

a guest
Jul 11th, 2017
226
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* global Module */
  2.  
  3. /* Magic Mirror
  4.  * Module: Calendar
  5.  *
  6.  * By Michael Teeuw http://michaelteeuw.nl
  7.  * MIT Licensed.
  8.  */
  9.  
  10. Module.register("calendar", {
  11.  
  12.       // Define module defaults
  13.       defaults: {
  14.         maximumEntries: 10, // Total Maximum Entries
  15.         maximumNumberOfDays: 365,
  16.         displaySymbol: true,
  17.         defaultSymbol: "calendar", // Fontawesome Symbol see http://fontawesome.io/cheatsheet/
  18.         displayRepeatingCountTitle: false,
  19.         defaultRepeatingCountTitle: "",
  20.         maxTitleLength: 25,
  21.         wrapEvents: false, // wrap events to multiple lines breaking at maxTitleLength
  22.         fetchInterval: 5 * 60 * 1000, // Update every 5 minutes.
  23.         animationSpeed: 2000,
  24.         fade: true,
  25.         urgency: 7,
  26.         timeFormat: "relative",
  27.         dateFormat: "MMM Do",
  28.         fullDayEventDateFormat: "MMM Do",
  29.         getRelative: 6,
  30.         fadePoint: 0.25, // Start on 1/4th of the list.
  31.         hidePrivate: false,
  32.         colored: false,
  33.         calendars: [{
  34.           symbol: "calendar",
  35.           url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics",
  36.         }, ],
  37.         titleReplace: {
  38.           "De verjaardag van ": "",
  39.           "'s birthday": ""
  40.         },
  41.         broadcastEvents: true,
  42.         excludedEvents: []
  43.       },
  44.  
  45.       // Define required scripts.
  46.       getStyles: function() {
  47.         return ["calendar.css", "font-awesome.css"];
  48.       },
  49.  
  50.       // Define required scripts.
  51.       getScripts: function() {
  52.         return ["moment.js"];
  53.       },
  54.  
  55.       // Define required translations.
  56.       getTranslations: function() {
  57.         // The translations for the default modules are defined in the core translation files.
  58.         // Therefor we can just return false. Otherwise we should have returned a dictionary.
  59.         // If you're trying to build your own module including translations, check out the documentation.
  60.         return false;
  61.       },
  62.  
  63.       // Override start method.
  64.       start: function() {
  65.         Log.log("Starting module: " + this.name);
  66.  
  67.         // Set locale.
  68.         moment.locale(config.language);
  69.  
  70.         switch (config.timeFormat) {
  71.           case 12:
  72.             {
  73.               moment.updateLocale(config.language, {
  74.                 longDateFormat: {
  75.                   LT: "h:mm A"
  76.                 }
  77.               });
  78.               break;
  79.             }
  80.           case 24:
  81.             {
  82.               moment.updateLocale(config.language, {
  83.                 longDateFormat: {
  84.                   LT: "hh:mm"
  85.                 }
  86.               });
  87.               break;
  88.             }
  89.             // If config.timeFormat was not given (or has invalid format) default to locale default
  90.           default:
  91.             {
  92.               break;
  93.             }
  94.         }
  95.  
  96.         for (var c in this.config.calendars) {
  97.           var calendar = this.config.calendars[c];
  98.           calendar.url = calendar.url.replace("webcal://", "http://");
  99.  
  100.           var calendarConfig = {
  101.             maximumEntries: calendar.maximumEntries,
  102.             maximumNumberOfDays: calendar.maximumNumberOfDays
  103.           };
  104.  
  105.           // we check user and password here for backwards compatibility with old configs
  106.           if (calendar.user && calendar.pass) {
  107.             calendar.auth = {
  108.               user: calendar.user,
  109.               pass: calendar.pass
  110.             }
  111.           }
  112.  
  113.           this.addCalendar(calendar.url, calendar.auth, calendarConfig);
  114.         }
  115.  
  116.         this.calendarData = {};
  117.         this.loaded = false;
  118.       },
  119.  
  120.       // Override socket notification handler.
  121.       socketNotificationReceived: function(notification, payload) {
  122.         if (notification === "CALENDAR_EVENTS") {
  123.           if (this.hasCalendarURL(payload.url)) {
  124.             this.calendarData[payload.url] = payload.events;
  125.             this.loaded = true;
  126.  
  127.             if (this.config.broadcastEvents) {
  128.               this.broadcastEvents();
  129.             }
  130.           }
  131.         } else if (notification === "FETCH_ERROR") {
  132.           Log.error("Calendar Error. Could not fetch calendar: " + payload.url);
  133.         } else if (notification === "INCORRECT_URL") {
  134.           Log.error("Calendar Error. Incorrect url: " + payload.url);
  135.         } else {
  136.           Log.log("Calendar received an unknown socket notification: " + notification);
  137.         }
  138.  
  139.         this.updateDom(this.config.animationSpeed);
  140.       },
  141.  
  142.       // Override dom generator.
  143.       getDom: function() {
  144.  
  145.         var events = this.createEventList();
  146.         var wrapper = document.createElement("table");
  147.         wrapper.className = "small";
  148.  
  149.         if (events.length === 0) {
  150.           wrapper.innerHTML = (this.loaded) ? this.translate("EMPTY") : this.translate("LOADING");
  151.           wrapper.className = "small dimmed";
  152.           return wrapper;
  153.         }
  154.  
  155.         for (var e in events) {
  156.           var event = events[e];
  157.  
  158.           var excluded = false;
  159.           for (var f in this.config.excludedEvents) {
  160.             var filter = this.config.excludedEvents[f];
  161.             if (event.title.toLowerCase().includes(filter.toLowerCase())) {
  162.               excluded = true;
  163.               break;
  164.             }
  165.           }
  166.  
  167.           if (excluded) {
  168.             continue;
  169.           }
  170.  
  171.           var eventWrapper = document.createElement("tr");
  172.  
  173.           if (this.config.colored) {
  174.             eventWrapper.style.cssText = "color:" + this.colorForUrl(event.url);
  175.           }
  176.  
  177.           eventWrapper.className = "normal";
  178.  
  179.           if (this.config.displaySymbol) {
  180.             var symbolWrapper = document.createElement("td");
  181.             symbolWrapper.className = "symbol align-right";
  182.             var symbols = this.symbolsForUrl(event.url);
  183.             if (typeof symbols === "string") {
  184.               symbols = [symbols];
  185.             }
  186.  
  187.             for (var i = 0; i < symbols.length; i++) {
  188.               var symbol = document.createElement("span");
  189.               symbol.className = "fa fa-" + symbols[i];
  190.               if (i > 0) {
  191.                 symbol.style.paddingLeft = "5px";
  192.               }
  193.               symbolWrapper.appendChild(symbol);
  194.             }
  195.             eventWrapper.appendChild(symbolWrapper);
  196.           }
  197.  
  198.           var titleWrapper = document.createElement("td"),
  199.             repeatingCountTitle = "";
  200.  
  201.           if (this.config.displayRepeatingCountTitle) {
  202.  
  203.             repeatingCountTitle = this.countTitleForUrl(event.url);
  204.  
  205.             if (repeatingCountTitle !== "") {
  206.               var thisYear = new Date(parseInt(event.startDate)).getFullYear(),
  207.                 yearDiff = thisYear - event.firstYear;
  208.  
  209.               repeatingCountTitle = ", " + yearDiff + ". " + repeatingCountTitle;
  210.             }
  211.           }
  212.  
  213.           titleWrapper.innerHTML = this.titleTransform(event.title) + repeatingCountTitle;
  214.  
  215.           if (!this.config.colored) {
  216.             titleWrapper.className = "title bright";
  217.           } else {
  218.             titleWrapper.className = "title";
  219.           }
  220.  
  221.           eventWrapper.appendChild(titleWrapper);
  222.  
  223.           var timeWrapper = document.createElement("td");
  224.           //console.log(event.today);
  225.           var now = new Date();
  226.           // Define second, minute, hour, and day variables
  227.           var oneSecond = 1000; // 1,000 milliseconds
  228.           var oneMinute = oneSecond * 60;
  229.           var oneHour = oneMinute * 60;
  230.           var oneDay = oneHour * 24;
  231.           if (event.fullDayEvent) {
  232.             if (event.today) {
  233.               timeWrapper.innerHTML = this.capFirst(this.translate("TODAY"));
  234.             } else if (event.startDate - now < oneDay && event.startDate - now > 0) {
  235.               timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW"));
  236.             } else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) {
  237.               if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") {
  238.                 timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW"));
  239.               } else {
  240.                 timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
  241.               }
  242.             } else {
  243.               /* Check to see if the user displays absolute or relative dates with their events
  244.                * Also check to see if an event is happening within an 'urgency' time frameElement
  245.                * For example, if the user set an .urgency of 7 days, those events that fall within that
  246.                * time frame will be displayed with 'in xxx' time format or moment.fromNow()
  247.                *
  248.                * Note: this needs to be put in its own function, as the whole thing repeats again verbatim
  249.                */
  250.               if (this.config.timeFormat === "absolute") {
  251.                 if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) {
  252.                   // This event falls within the config.urgency period that the user has set
  253.                   timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
  254.                 } else {
  255.                   timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat));
  256.                 }
  257.               } else {
  258.                 timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
  259.               }
  260.             }
  261.           } else {
  262.             if (event.startDate >= new Date()) {
  263.               if (event.startDate - now < 2 * oneDay) {
  264.                 // This event is within the next 48 hours (2 days)
  265.                 if (event.startDate - now < this.config.getRelative * oneHour) {
  266.                   // If event is within 6 hour, display 'in xxx' time format or moment.fromNow()
  267.                   timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
  268.                 } else {
  269.                   // Otherwise just say 'Today/Tomorrow at such-n-such time'
  270.                   timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar());
  271.                 }
  272.               } else {
  273.                 /* Check to see if the user displays absolute or relative dates with their events
  274.                  * Also check to see if an event is happening within an 'urgency' time frameElement
  275.                  * For example, if the user set an .urgency of 7 days, those events that fall within that
  276.                  * time frame will be displayed with 'in xxx' time format or moment.fromNow()
  277.                  *
  278.                  * Note: this needs to be put in its own function, as the whole thing repeats again verbatim
  279.                  */
  280.                 if (this.config.timeFormat === "absolute") {
  281.                   if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) {
  282.                     // This event falls within the config.urgency period that the user has set
  283.                     timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
  284.                   } else {
  285.                     timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
  286.                   }
  287.                 } else {
  288.                   timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
  289.                 }
  290.               }
  291.             } else {
  292.               timeWrapper.innerHTML = this.capFirst(
  293.                 this.translate("RUNNING", {
  294.                   fallback: this.translate("RUNNING") + " {timeUntilEnd}",
  295.                   timeUntilEnd: moment(event.endDate, "x").fromNow(true)
  296.                 })
  297.               );
  298.             }
  299.           }
  300.           //timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
  301.           //console.log(event);
  302.           timeWrapper.className = "time light";
  303.           eventWrapper.appendChild(timeWrapper);
  304.  
  305.           wrapper.appendChild(eventWrapper);
  306.  
  307.           // Create fade effect.
  308.           if (this.config.fade && this.config.fadePoint < 1) {
  309.             if (this.config.fadePoint < 0) {
  310.               this.config.fadePoint = 0;
  311.             }
  312.             var startingPoint = events.length * this.config.fadePoint;
  313.             var steps = events.length - startingPoint;
  314.             if (e >= startingPoint) {
  315.               var currentStep = e - startingPoint;
  316.               eventWrapper.style.opacity = 1 - (1 / steps * currentStep);
  317.             }
  318.           }
  319.         }
  320.  
  321.         return wrapper;
  322.       },
  323.  
  324.       /* hasCalendarURL(url)
  325.        * Check if this config contains the calendar url.
  326.        *
  327.        * argument url string - Url to look for.
  328.        *
  329.        * return bool - Has calendar url
  330.        */
  331.       hasCalendarURL: function(url) {
  332.         for (var c in this.config.calendars) {
  333.           var calendar = this.config.calendars[c];
  334.           if (calendar.url === url) {
  335.             return true;
  336.           }
  337.         }
  338.  
  339.         return false;
  340.       },
  341.  
  342.       /* createEventList()
  343.        * Creates the sorted list of all events.
  344.        *
  345.        * return array - Array with events.
  346.        */
  347.       createEventList: function() {
  348.         var events = [];
  349.         var today = moment().startOf("day");
  350.         for (var c in this.calendarData) {
  351.           var calendar = this.calendarData[c];
  352.           for (var e in calendar) {
  353.             var event = calendar[e];
  354.             if (this.config.hidePrivate) {
  355.               if (event.class === "PRIVATE") {
  356.                 // do not add the current event, skip it
  357.                 continue;
  358.               }
  359.             }
  360.             event.url = c;
  361.             event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000);
  362.             events.push(event);
  363.           }
  364.         }
  365.  
  366.  
  367.         eventList = events.filter(function(a) {
  368.           return typeof a.categories === ('zur Information');
  369.         });
  370.         events.sort(function(a, b) {
  371.           console.log(a, b);
  372.           return a.startDate - b.startDate;
  373.         });
  374.  
  375.         return events.slice(0, this.config.maximumEntries);
  376.       },
  377.  
  378.       /* createEventList(url)
  379.        * Requests node helper to add calendar url.
  380.        *
  381.        * argument url string - Url to add.
  382.        */
  383.       addCalendar: function(url, auth, calendarConfig) {
  384.         this.sendSocketNotification("ADD_CALENDAR", {
  385.           url: url,
  386.           maximumEntries: calendarConfig.maximumEntries || this.config.maximumEntries,
  387.           maximumNumberOfDays: calendarConfig.maximumNumberOfDays || this.config.maximumNumberOfDays,
  388.           fetchInterval: this.config.fetchInterval,
  389.           auth: auth
  390.         });
  391.       },
  392.  
  393.       /* symbolsForUrl(url)
  394.        * Retrieves the symbols for a specific url.
  395.        *
  396.        * argument url string - Url to look for.
  397.        *
  398.        * return string/array - The Symbols
  399.        */
  400.       symbolsForUrl: function(url) {
  401.         return this.getCalendarProperty(url, "symbol", this.config.defaultSymbol);
  402.       },
  403.  
  404.       /* colorForUrl(url)
  405.        * Retrieves the color for a specific url.
  406.        *
  407.        * argument url string - Url to look for.
  408.        *
  409.        * return string - The Color
  410.        */
  411.       colorForUrl: function(url) {
  412.         return this.getCalendarProperty(url, "color", "#fff");
  413.       },
  414.  
  415.       /* countTitleForUrl(url)
  416.        * Retrieves the name for a specific url.
  417.        *
  418.        * argument url string - Url to look for.
  419.        *
  420.        * return string - The Symbol
  421.        */
  422.       countTitleForUrl: function(url) {
  423.         return this.getCalendarProperty(url, "repeatingCountTitle", this.config.defaultRepeatingCountTitle);
  424.       },
  425.  
  426.       /* getCalendarProperty(url, property, defaultValue)
  427.        * Helper method to retrieve the property for a specific url.
  428.        *
  429.        * argument url string - Url to look for.
  430.        * argument property string - Property to look for.
  431.        * argument defaultValue string - Value if property is not found.
  432.        *
  433.        * return string - The Property
  434.        */
  435.       getCalendarProperty: function(url, property, defaultValue) {
  436.         for (var c in this.config.calendars) {
  437.           var calendar = this.config.calendars[c];
  438.           if (calendar.url === url && calendar.hasOwnProperty(property)) {
  439.             return calendar[property];
  440.           }
  441.         }
  442.  
  443.         return defaultValue;
  444.       },
  445.  
  446.       /* shorten(string, maxLength)
  447.        * Shortens a string if it's longer than maxLength.
  448.        * Adds an ellipsis to the end.
  449.        *
  450.        * argument string string - The string to shorten.
  451.        * argument maxLength number - The max length of the string.
  452.        * argument wrapEvents - Wrap the text after the line has reached maxLength
  453.        *
  454.        * return string - The shortened string.
  455.        */
  456.       shorten: function(string, maxLength, wrapEvents) {
  457.         if (wrapEvents) {
  458.           var temp = "";
  459.           var currentLine = "";
  460.           var words = string.split(" ");
  461.  
  462.           for (var i = 0; i < words.length; i++) {
  463.             var word = words[i];
  464.             if (currentLine.length + word.length < 25 - 1) { // max - 1 to account for a space
  465.               currentLine += (word + " ");
  466.             } else {
  467.               if (currentLine.length > 0) {
  468.                 temp += (currentLine + "<br>" + word + " ");
  469.               } else {
  470.                 temp += (word + "<br>");
  471.               }
  472.               currentLine = "";
  473.             }
  474.           }
  475.  
  476.           return temp + currentLine;
  477.         } else {
  478.           if (string.length > maxLength) {
  479.             return string.slice(0, maxLength) + "&hellip;";
  480.           } else {
  481.             return string;
  482.           }
  483.         }
  484.       },
  485.  
  486.       /* capFirst(string)
  487.        * Capitalize the first letter of a string
  488.        * Return capitalized string
  489.        */
  490.  
  491.       capFirst: function(string) {
  492.         return string.charAt(0).toUpperCase() + string.slice(1);
  493.       },
  494.  
  495.       /* titleTransform(title)
  496.        * Transforms the title of an event for usage.
  497.        * Replaces parts of the text as defined in config.titleReplace.
  498.        * Shortens title based on config.maxTitleLength and config.wrapEvents
  499.        *
  500.        * argument title string - The title to transform.
  501.        *
  502.        * return string - The transformed title.
  503.        */
  504.       titleTransform: function(title) {
  505.         for (var needle in this.config.titleReplace) {
  506.           var replacement = this.config.titleReplace[needle];
  507.  
  508.           var regParts = needle.match(/^\/(.+)\/([gim]*)$/);
  509.           if (regParts) {
  510.             // the parsed pattern is a regexp.
  511.             needle = new RegExp(regParts[1], regParts[2]);
  512.           }
  513.  
  514.           title = title.replace(needle, replacement);
  515.         }
  516.  
  517.         title = this.shorten(title, this.config.maxTitleLength, this.config.wrapEvents);
  518.         return title;
  519.       },
  520.  
  521.       /* broadcastEvents()
  522.        * Broadcasts the events to all other modules for reuse.
  523.        * The all events available in one array, sorted on startdate.
  524.        */
  525.       broadcastEvents: function() {
  526.         var eventList = [];
  527.         for (var url in this.calendarData) {
  528.           var calendar = this.calendarData[url];
  529.           for (var e in calendar) {
  530.             var event = cloneObject(calendar[e]);
  531.             delete event.url;
  532.             eventList.push(event);
  533.             console.log(event)
  534.           }
  535.         }
  536.  
  537.         eventList = eventList.filter(function(a) {
  538.             console.log(a);
  539.             return typeof a.categories === 'zur Information';
  540.                               });
  541.             eventList.sort(function(a, b) {
  542.               return a.startDate - b.startDate;
  543.             });
  544.  
  545.             this.sendNotification("CALENDAR_EVENTS", eventList);
  546.  
  547.           }
  548.         });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement