├── gplaypattern.png ├── party.sh ├── normal.sh ├── README.md ├── .gitattributes ├── .gitignore ├── party_config.js ├── normal_config.js ├── party_custom.css ├── normal_custom.css └── calendar.js /gplaypattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinkybluebug/MMM-CustomCSSv2/HEAD/gplaypattern.png -------------------------------------------------------------------------------- /party.sh: -------------------------------------------------------------------------------- 1 | cp ../MagicMirror/css/party_custom.css ../MagicMirror/css/custom.css 2 | cp ../MagicMirror/config/party_config.js ../MagicMirror/config/config.js 3 | pm2 restart all -------------------------------------------------------------------------------- /normal.sh: -------------------------------------------------------------------------------- 1 | cp ../MagicMirror/css/normal_custom.css ../MagicMirror/css/custom.css 2 | cp ../MagicMirror/config/normal_config.js ../MagicMirror/config/config.js 3 | pm2 restart all -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MMM-CustomCSSv2, 2 | Custom Magic Mirror CSS and config files. 3 | 4 | Put normal_config.js and party_config in config directory, 5 | Put normal_custom.css, party_custom.css and gplaypattern.jpg in css directory. 6 | 7 | In SSH, use command 'bash part.sh' to use party config and css file, 8 | use 'bash normal.sh' to use normal config and css file 9 | 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /party_config.js: -------------------------------------------------------------------------------- 1 | /* Magic Mirror Config Sample 2 | * 3 | * By Michael Teeuw http://michaelteeuw.nl 4 | * MIT Licensed. 5 | */ 6 | 7 | var config = { 8 | port: 8080, 9 | 10 | language: 'en-gb', 11 | timeFormat: 24, 12 | units: 'metric', 13 | 14 | modules: [ 15 | 16 | 17 | 18 | 19 | 20 | { 21 | module: 'clock', 22 | position: 'top_left' 23 | }, 24 | 25 | { 26 | module: 'newsfeed', 27 | position: 'bottom_bar', 28 | config: { 29 | feeds: [ 30 | { 31 | title: "Google News", 32 | url: "http://news.google.co.uk/news?cf=all&hl=en&pz=1&ned=uk&output=rss", 33 | 34 | } 35 | ], 36 | showSourceTitle: true, 37 | showPublishDate: true, 38 | showDescription: false 39 | } 40 | }, 41 | 42 | { 43 | module: 'sonos', 44 | position: 'middle_center', // you may choose any location 45 | config: { 46 | showStoppedRoom: false, 47 | showAlbumArt: true, 48 | updateInterval: 0.1, // every 0.1 minutes 49 | showRoomName: false, 50 | exclude: ['Living Room','Bedroom','Bathroom'], 51 | } 52 | }, 53 | { 54 | module: 'MMM-Remote-Control' 55 | // uncomment the following line to show the URL of the remote control on the mirror 56 | // , position: 'bottom_left' 57 | // you can hide this module afterwards from the remote control itself 58 | }, 59 | { 60 | module: 'MMM-WatchDog', 61 | config: { 62 | // See 'Configuration options' for more information. 63 | } 64 | }, 65 | ] 66 | 67 | }; 68 | 69 | /*************** DO NOT EDIT THE LINE BELOW ***************/ 70 | if (typeof module !== 'undefined') {module.exports = config;} 71 | -------------------------------------------------------------------------------- /normal_config.js: -------------------------------------------------------------------------------- 1 | /* Magic Mirror Config Sample 2 | * 3 | * By Michael Teeuw http://michaelteeuw.nl 4 | * MIT Licensed. 5 | */ 6 | 7 | var config = { 8 | port: 8080, 9 | 10 | language: 'en-gb', 11 | timeFormat: 24, 12 | units: 'metric', 13 | 14 | modules: [ 15 | 16 | 17 | 18 | 19 | 20 | { 21 | module: 'clock', 22 | position: 'top_left' 23 | }, 24 | 25 | { 26 | module: 'newsfeed', 27 | position: 'bottom_bar', 28 | config: { 29 | feeds: [ 30 | { 31 | title: "Google News", 32 | url: "http://news.google.co.uk/news?cf=all&hl=en&pz=1&ned=uk&output=rss", 33 | 34 | } 35 | ], 36 | showSourceTitle: true, 37 | showPublishDate: true, 38 | showDescription: false 39 | } 40 | }, 41 | { 42 | module: 'MMM-WunderGround', 43 | position: 'top_right', 44 | config: { 45 | fade: false, 46 | apikey: 'xxxxxxxxxxxxxxxxxxxxxx', // private; don't share! 47 | pws: 'xxxxxxxxxxxxxx', //culemborg 48 | hourly: '1', 49 | fctext: '1', 50 | fcdaycount: "5", 51 | fcdaystart: "1", 52 | hourlyinterval: "3", 53 | hourlycount: "2", 54 | alerttime: 10000, 55 | alerttruncatestring: "english:", 56 | fadepoint: 1, 57 | } 58 | }, 59 | { 60 | module: 'sonos', 61 | position: 'top_center', // you may choose any location 62 | config: { 63 | showStoppedRoom: false, 64 | showAlbumArt: true, 65 | showRoomName: false, 66 | exclude: ['Living Room','Bedroom','Bathroom'], 67 | } 68 | }, 69 | { 70 | module: 'calendar', 71 | header: 'Family Calendar', 72 | position: 'top_left', 73 | config: { 74 | fadePoint: 1, // Start on 1/4th of the list. 75 | maxTitleLength: 35, 76 | urgency: 1, 77 | timeFormat: "absolute", 78 | calendars: [ 79 | { 80 | symbol: 'check-square-o', 81 | url: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 82 | } 83 | ] 84 | } 85 | }, 86 | { 87 | module: 'MMM-Remote-Control' 88 | // uncomment the following line to show the URL of the remote control on the mirror 89 | // , position: 'bottom_left' 90 | // you can hide this module afterwards from the remote control itself 91 | }, 92 | { 93 | module: 'MMM-WatchDog', 94 | config: { 95 | // See 'Configuration options' for more information. 96 | } 97 | }, 98 | ] 99 | 100 | }; 101 | 102 | /*************** DO NOT EDIT THE LINE BELOW ***************/ 103 | if (typeof module !== 'undefined') {module.exports = config;} 104 | -------------------------------------------------------------------------------- /party_custom.css: -------------------------------------------------------------------------------- 1 | /***************************************************** 2 | * Magic Mirror * 3 | * Custom CSS * 4 | * * 5 | * By Michael Teeuw http://michaelteeuw.nl * 6 | * MIT Licensed. * 7 | * * 8 | * Add any custom CSS below. * 9 | * Changes to this files will be ignored by GIT. * 10 | *****************************************************/ 11 | 12 | body { 13 | margin: 40px; 14 | background-image: url("gplaypattern.png"); 15 | background-repeat: repeat; 16 | background-size: 300px; 17 | padding-bottom: 0px; 18 | width: 1200px; 19 | font-weight: 300; 20 | 21 | } 22 | 23 | .region.top.left { 24 | width: 800px 25 | } 26 | .region.top.right { 27 | width: 350px 28 | } 29 | div.region.bottom.bar { 30 | top: 510px; 31 | height : 150px; 32 | overflow: hidden; 33 | } 34 | div.region.top.center { 35 | * height: 100px; 36 | overflow: hidden; 37 | left: 568px; 38 | } 39 | .name.normal.medium { 40 | width: 375px; 41 | text-align: left; 42 | } 43 | 44 | div#module_3_sonos.module.sonos { 45 | margin-top: 0px; 46 | } 47 | 48 | .calendar, div#module_2_MMM-WunderGround table.small { 49 | background-color: rgba(63, 182, 236, 0.23); 50 | border-radius: 10px; 51 | padding: 10px; 52 | box-shadow: 5px 5px 5px 1px #d3d3d3; 53 | 54 | } 55 | div#module_2_MMM-WunderGround div.large.light { 56 | margin-bottom: 27px; 57 | } 58 | div#module_3_sonos { 59 | margin-top: 00px; 60 | } 61 | 62 | .calendar .title, .weatherforecast .weather-icon, .bright, .calendar .time, .weatherforecast .day, .currentweather .weathericon, .MMM-WunderGround .day, .MMM-WunderGround .max-temp , .MMM-WunderGround .min-temp, .MMM-WunderGround .forecastText, .MMM-WunderGround .hour , .MMM-WunderGround .pop, .MMM-WunderGround .mm { 63 | color: #262626; 64 | } 65 | 66 | .xsmall, td.forecastText { 67 | font-size: 20px; 68 | line-height: 22px; 69 | } 70 | 71 | .small { 72 | font-size: 28px; 73 | line-height: 32px; 74 | } 75 | 76 | .medium { 77 | font-size: 35px; 78 | line-height: 40px; 79 | } 80 | 81 | .large { 82 | font-size: 65px; 83 | line-height: 65px; 84 | } 85 | 86 | .xlarge { 87 | font-size: 75px; 88 | line-height: 75px; 89 | letter-spacing: -3px; 90 | } 91 | 92 | .sonos ul .art img { 93 | height: 350px; 94 | } 95 | 96 | .sonos ul .name { 97 | font-size: 75px; 98 | line-height: 80px; 99 | } 100 | 101 | 102 | div#module_2_sonos.module.sonos img { 103 | border-radius: 20px; 104 | } 105 | 106 | div.name.normal.medium { 107 | width: 700px; 108 | } -------------------------------------------------------------------------------- /normal_custom.css: -------------------------------------------------------------------------------- 1 | /***************************************************** 2 | * Magic Mirror * 3 | * Custom CSS * 4 | * * 5 | * By Michael Teeuw http://michaelteeuw.nl * 6 | * MIT Licensed. * 7 | * * 8 | * Add any custom CSS below. * 9 | * Changes to this files will be ignored by GIT. * 10 | *****************************************************/ 11 | 12 | body { 13 | margin: 40px; 14 | background-image: url("gplaypattern.png"); 15 | background-repeat: repeat; 16 | background-size: 300px; 17 | padding-bottom: 0px; 18 | width: 1200px; 19 | font-weight: 300; 20 | 21 | } 22 | 23 | .region.top.left { 24 | width: 800px 25 | } 26 | .region.top.right { 27 | width: 350px 28 | } 29 | div.region.bottom.bar { 30 | top: 510px; 31 | height : 150px; 32 | overflow: hidden; 33 | } 34 | div.region.top.center { 35 | * height: 100px; 36 | overflow: hidden; 37 | left: 568px; 38 | } 39 | .name.normal.medium { 40 | width: 375px; 41 | text-align: right; 42 | } 43 | 44 | div#module_3_sonos.module.sonos { 45 | margin-top: 0px; 46 | } 47 | 48 | .calendar, div#module_2_MMM-WunderGround table.small { 49 | background-color: rgba(63, 182, 236, 0.23); 50 | border-radius: 10px; 51 | padding: 10px; 52 | box-shadow: 5px 5px 5px 1px #d3d3d3; 53 | 54 | } 55 | div#module_2_MMM-WunderGround div.large.light { 56 | margin-bottom: 27px; 57 | } 58 | div#module_3_sonos { 59 | margin-top: 20px; 60 | } 61 | 62 | .calendar .title, .hourv, .weatherforecast .weather-icon, .bright, .calendar .time, .weatherforecast .day, .currentweather .weathericon, .MMM-WunderGround .day, .MMM-WunderGround .max-temp , .MMM-WunderGround .min-temp, .MMM-WunderGround .forecastText, .MMM-WunderGround .hour , .MMM-WunderGround .pop, .MMM-WunderGround .mm { 63 | color: #262626; 64 | } 65 | 66 | .xsmall, td.forecastText { 67 | font-size: 20px; 68 | line-height: 22px; 69 | } 70 | 71 | .small { 72 | font-size: 28px; 73 | line-height: 32px; 74 | } 75 | 76 | .medium { 77 | font-size: 35px; 78 | line-height: 40px; 79 | } 80 | 81 | .large { 82 | font-size: 65px; 83 | line-height: 65px; 84 | } 85 | 86 | .xlarge { 87 | font-size: 75px; 88 | line-height: 75px; 89 | letter-spacing: -3px; 90 | } 91 | 92 | .sonos ul .art img { 93 | height: 80px; 94 | } 95 | 96 | .sonos ul .name { 97 | font-size: 25px; 98 | line-height: 22px; 99 | } 100 | td.title.bright { 101 | width: 480px; 102 | } 103 | div#module_4_calendar { 104 | margin-top: 9px; 105 | } 106 | div#module_2_MMM-WunderGround div.large.light { 107 | margin-bottom:8px; 108 | } 109 | 110 | td.forecastText { 111 | text-align: justify; 112 | } 113 | div#module_3_sonos.module.sonos img { 114 | border-radius: 10px; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /calendar.js: -------------------------------------------------------------------------------- 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 | fetchInterval: 5 * 60 * 1000, // Update every 5 minutes. 22 | animationSpeed: 2000, 23 | fade: true, 24 | 25 | fadePoint: 0.25, // Start on 1/4th of the list. 26 | calendars: [ 27 | { 28 | symbol: "calendar", 29 | url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics", 30 | }, 31 | ], 32 | titleReplace: { 33 | "De verjaardag van ": "", 34 | "'s birthday": "" 35 | }, 36 | }, 37 | 38 | // Define required scripts. 39 | getStyles: function() { 40 | return ["calendar.css", "font-awesome.css"]; 41 | }, 42 | 43 | // Define required scripts. 44 | getScripts: function() { 45 | return ["moment.js"]; 46 | }, 47 | 48 | // Define required translations. 49 | getTranslations: function() { 50 | // The translations for the defaut modules are defined in the core translation files. 51 | // Therefor we can just return false. Otherwise we should have returned a dictionairy. 52 | // If you're trying to build your own module including translations, check out the documentation. 53 | return false; 54 | }, 55 | 56 | // Override start method. 57 | start: function() { 58 | Log.log("Starting module: " + this.name); 59 | 60 | // Set locale. 61 | moment.locale(config.language); 62 | 63 | for (var c in this.config.calendars) { 64 | var calendar = this.config.calendars[c]; 65 | calendar.url = calendar.url.replace("webcal://", "http://"); 66 | this.addCalendar(calendar.url); 67 | } 68 | 69 | this.calendarData = {}; 70 | this.loaded = false; 71 | }, 72 | 73 | // Override socket notification handler. 74 | socketNotificationReceived: function(notification, payload) { 75 | if (notification === "CALENDAR_EVENTS") { 76 | if (this.hasCalendarURL(payload.url)) { 77 | this.calendarData[payload.url] = payload.events; 78 | this.loaded = true; 79 | } 80 | } else if (notification === "FETCH_ERROR") { 81 | Log.error("Calendar Error. Could not fetch calendar: " + payload.url); 82 | } else if (notification === "INCORRECT_URL") { 83 | Log.error("Calendar Error. Incorrect url: " + payload.url); 84 | } else { 85 | Log.log("Calendar received an unknown socket notification: " + notification); 86 | } 87 | 88 | this.updateDom(this.config.animationSpeed); 89 | }, 90 | 91 | // Override dom generator. 92 | getDom: function() { 93 | 94 | var events = this.createEventList(); 95 | var wrapper = document.createElement("table"); 96 | wrapper.className = "small"; 97 | 98 | if (events.length === 0) { 99 | wrapper.innerHTML = (this.loaded) ? this.translate("EMPTY") : this.translate("LOADING"); 100 | wrapper.className = "small dimmed"; 101 | return wrapper; 102 | } 103 | 104 | for (var e in events) { 105 | var event = events[e]; 106 | 107 | var eventWrapper = document.createElement("tr"); 108 | eventWrapper.className = "normal"; 109 | 110 | if (this.config.displaySymbol) { 111 | var symbolWrapper = document.createElement("td"); 112 | symbolWrapper.className = "symbol"; 113 | var symbol = document.createElement("span"); 114 | symbol.className = "fa fa-" + this.symbolForUrl(event.url); 115 | symbolWrapper.appendChild(symbol); 116 | eventWrapper.appendChild(symbolWrapper); 117 | } 118 | 119 | var titleWrapper = document.createElement("td"), 120 | repeatingCountTitle = ''; 121 | 122 | 123 | if (this.config.displayRepeatingCountTitle) { 124 | 125 | repeatingCountTitle = this.countTitleForUrl(event.url); 126 | 127 | if(repeatingCountTitle !== '') { 128 | var thisYear = new Date().getFullYear(), 129 | yearDiff = thisYear - event.firstYear; 130 | 131 | repeatingCountTitle = ', '+ yearDiff + '. ' + repeatingCountTitle; 132 | } 133 | } 134 | 135 | titleWrapper.innerHTML = this.titleTransform(event.title) + repeatingCountTitle; 136 | titleWrapper.className = "title bright"; 137 | eventWrapper.appendChild(titleWrapper); 138 | 139 | var timeWrapper = document.createElement("td"); 140 | //console.log(event.today); 141 | var now = new Date(); 142 | // Define second, minute, hour, and day variables 143 | var one_second = 1000; // 1,000 milliseconds 144 | var one_minute = one_second * 60; 145 | var one_hour = one_minute * 60; 146 | var one_day = one_hour * 24; 147 | if (event.fullDayEvent) { 148 | if (event.today) { 149 | timeWrapper.innerHTML = this.translate("TODAY"); 150 | } else if (event.startDate - now < one_day && event.startDate - now > 0) { 151 | timeWrapper.innerHTML = this.translate("TOMORROW"); 152 | } else { 153 | /* Check to see if the user displays absolute or relative dates with their events 154 | * Also check to see if an event is happening within an 'urgency' time frameElement 155 | * For example, if the user set an .urgency of 7 days, those events that fall within that 156 | * time frame will be displayed with 'in xxx' time format or moment.fromNow() 157 | * 158 | * Note: this needs to be put in its own function, as the whole thing repeats again verbatim 159 | */ 160 | if (this.config.timeFormat === "absolute") { 161 | if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) { 162 | // This event falls within the config.urgency period that the user has set 163 | timeWrapper.innerHTML = moment(event.startDate, "x").fromNow(); 164 | } else { 165 | timeWrapper.innerHTML = moment(event.startDate, "x").format("dddd"); /// THIS IS THE ONE 166 | } 167 | } else { 168 | timeWrapper.innerHTML = moment(event.startDate, "x").fromNow(); 169 | } 170 | } 171 | } else { 172 | if (event.startDate >= new Date()) { 173 | if (event.startDate - now < 6 * one_day) { 174 | // This event is within the next 48 hours (2 days) 175 | if (event.startDate - now < 6 * one_hour) { 176 | // If event is within 6 hour, display 'in xxx' time format or moment.fromNow() 177 | timeWrapper.innerHTML = moment(event.startDate, "x").calendar(); 178 | } else { 179 | // Otherwise just say 'Today/Tomorrow at such-n-such time' 180 | timeWrapper.innerHTML = moment(event.startDate, "x").calendar(); //within a week 181 | } 182 | } else { 183 | /* Check to see if the user displays absolute or relative dates with their events 184 | * Also check to see if an event is happening within an 'urgency' time frameElement 185 | * For example, if the user set an .urgency of 7 days, those events that fall within that 186 | * time frame will be displayed with 'in xxx' time format or moment.fromNow() 187 | * 188 | * Note: this needs to be put in its own function, as the whole thing repeats again verbatim 189 | */ 190 | if (this.config.timeFormat === "absolute") { 191 | if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) { 192 | // This event falls within the config.urgency period that the user has set 193 | timeWrapper.innerHTML = moment(event.startDate, "x").fromNow(); 194 | } else { 195 | timeWrapper.innerHTML = moment(event.startDate, "x").format("MMM Do"); //outside of a week 196 | } 197 | } else { 198 | timeWrapper.innerHTML = moment(event.startDate, "x").fromNow(); 199 | } 200 | } 201 | } else { 202 | timeWrapper.innerHTML = this.translate("RUNNING") + ' ' + moment(event.endDate,"x").fromNow(true); 203 | } 204 | } 205 | //timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll'); 206 | //console.log(event); 207 | timeWrapper.className = "time light"; 208 | eventWrapper.appendChild(timeWrapper); 209 | 210 | wrapper.appendChild(eventWrapper); 211 | 212 | // Create fade effect. 213 | if (this.config.fade && this.config.fadePoint < 1) { 214 | if (this.config.fadePoint < 0) { 215 | this.config.fadePoint = 0; 216 | } 217 | var startingPoint = events.length * this.config.fadePoint; 218 | var steps = events.length - startingPoint; 219 | if (e >= startingPoint) { 220 | var currentStep = e - startingPoint; 221 | eventWrapper.style.opacity = 1 - (1 / steps * currentStep); 222 | } 223 | } 224 | } 225 | 226 | return wrapper; 227 | }, 228 | 229 | /* hasCalendarURL(url) 230 | * Check if this config contains the calendar url. 231 | * 232 | * argument url sting - Url to look for. 233 | * 234 | * return bool - Has calendar url 235 | */ 236 | hasCalendarURL: function(url) { 237 | for (var c in this.config.calendars) { 238 | var calendar = this.config.calendars[c]; 239 | if (calendar.url === url) { 240 | return true; 241 | } 242 | } 243 | 244 | return false; 245 | }, 246 | 247 | /* createEventList() 248 | * Creates the sorted list of all events. 249 | * 250 | * return array - Array with events. 251 | */ 252 | createEventList: function() { 253 | var events = []; 254 | var today = moment().startOf("day"); 255 | for (var c in this.calendarData) { 256 | var calendar = this.calendarData[c]; 257 | for (var e in calendar) { 258 | var event = calendar[e]; 259 | event.url = c; 260 | event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000); 261 | events.push(event); 262 | } 263 | } 264 | 265 | events.sort(function(a, b) { 266 | return a.startDate - b.startDate; 267 | }); 268 | 269 | return events.slice(0, this.config.maximumEntries); 270 | }, 271 | 272 | /* createEventList(url) 273 | * Requests node helper to add calendar url. 274 | * 275 | * argument url sting - Url to add. 276 | */ 277 | addCalendar: function(url) { 278 | this.sendSocketNotification("ADD_CALENDAR", { 279 | url: url, 280 | maximumEntries: this.config.maximumEntries, 281 | maximumNumberOfDays: this.config.maximumNumberOfDays, 282 | fetchInterval: this.config.fetchInterval 283 | }); 284 | }, 285 | 286 | /* symbolForUrl(url) 287 | * Retrieves the symbol for a specific url. 288 | * 289 | * argument url sting - Url to look for. 290 | * 291 | * return string - The Symbol 292 | */ 293 | symbolForUrl: function(url) { 294 | for (var c in this.config.calendars) { 295 | var calendar = this.config.calendars[c]; 296 | if (calendar.url === url && typeof calendar.symbol === "string") { 297 | return calendar.symbol; 298 | } 299 | } 300 | 301 | return this.config.defaultSymbol; 302 | }, 303 | /* countTitleForUrl(url) 304 | * Retrieves the name for a specific url. 305 | * 306 | * argument url sting - Url to look for. 307 | * 308 | * return string - The Symbol 309 | */ 310 | countTitleForUrl: function(url) { 311 | for (var c in this.config.calendars) { 312 | var calendar = this.config.calendars[c]; 313 | if (calendar.url === url && typeof calendar.repeatingCountTitle === "string") { 314 | return calendar.repeatingCountTitle; 315 | } 316 | } 317 | 318 | return this.config.defaultRepeatingCountTitle; 319 | }, 320 | 321 | /* shorten(string, maxLength) 322 | * Shortens a sting if it's longer than maxLenthg. 323 | * Adds an ellipsis to the end. 324 | * 325 | * argument string string - The string to shorten. 326 | * argument maxLength number - The max lenth of the string. 327 | * 328 | * return string - The shortened string. 329 | */ 330 | shorten: function(string, maxLength) { 331 | if (string.length > maxLength) { 332 | return string.slice(0,maxLength) + "…"; 333 | } 334 | 335 | return string; 336 | }, 337 | 338 | /* titleTransform(title) 339 | * Transforms the title of an event for usage. 340 | * Replaces parts of the text as defined in config.titleReplace. 341 | * Shortens title based on config.maxTitleLength 342 | * 343 | * argument title string - The title to transform. 344 | * 345 | * return string - The transformed title. 346 | */ 347 | titleTransform: function(title) { 348 | for (var needle in this.config.titleReplace) { 349 | var replacement = this.config.titleReplace[needle]; 350 | title = title.replace(needle, replacement); 351 | } 352 | 353 | title = this.shorten(title, this.config.maxTitleLength); 354 | return title; 355 | } 356 | }); 357 | --------------------------------------------------------------------------------