mirror of
				https://github.com/MichMich/MagicMirror.git
				synced 2025-10-31 10:48:10 +00:00 
			
		
		
		
	Merge branch 'develop' of https://github.com/MichMich/MagicMirror into develop
This commit is contained in:
		| @@ -7,6 +7,7 @@ | ||||
| 		"curly": "error", | ||||
| 		"camelcase": ["error", {"properties": "never"}], | ||||
|         "no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }], | ||||
| 		"no-multi-spaces": "error", | ||||
| 		"no-trailing-spaces": ["error", {"ignoreComments": false }], | ||||
| 		"no-irregular-whitespace": ["error"] | ||||
| 	}, | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| dist: trusty | ||||
| language: node_js | ||||
| node_js: | ||||
|  - "10" | ||||
|   - 10 | ||||
|   - lts/* | ||||
|   - node | ||||
| before_install: | ||||
|   - npm i -g npm | ||||
| before_script: | ||||
| @@ -12,9 +14,9 @@ before_script: | ||||
|   - "sh -e /etc/init.d/xvfb start" | ||||
|   - sleep 5 | ||||
| script: | ||||
|   - npm run test:lint | ||||
|   - npm run test:e2e | ||||
|   - npm run test:unit | ||||
| - grunt | ||||
| after_script: | ||||
|   - npm list | ||||
| cache: | ||||
|   | ||||
							
								
								
									
										17
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -12,19 +12,29 @@ This project adheres to [Semantic Versioning](http://semver.org/). | ||||
| ### Deleted | ||||
| - Remove installers. | ||||
| - Remove externalized scripts. | ||||
| - Remove jshint dependency, instead eslint checks your config file now | ||||
|  | ||||
| ### Added | ||||
| - Brazilian translation for "FEELS". | ||||
| - Ukrainian translation. | ||||
| - Finnish translation for "PRECIP", "UPDATE_INFO_MULTIPLE" and "UPDATE_INFO_SINGLE". | ||||
| - Added the ability to hide the temp label and weather icon in the `currentweather` module to allow showing only information such as wind and sunset/rise. | ||||
| - The `clock` module now optionally displays sun and moon data, including rise/set times, remaining daylight, and percent of moon illumination. | ||||
| - Added Hebrew translation. | ||||
| - Add HTTPS support and update config.js.sample | ||||
| - Run tests on long term support and latest stable version of nodejs | ||||
| - Added the ability to configure a list of modules that shouldn't be update checked. | ||||
| - Run linters on git commits | ||||
|  | ||||
| ### Fixed | ||||
| - Force declaration of public ip adress in config file (ISSUE #1852) | ||||
| - Force declaration of public ip address in config file (ISSUE #1852) | ||||
| - Fixes `run-start.sh`: If running in docker-container, don't check the environment, just start electron (ISSUE #1859) | ||||
| - Fix calendar time offset for recurring events crossing Daylight Savings Time (ISSUE #1798) | ||||
| - Fix regression in currentweather module causing 'undefined' to show up when config.hideTemp is false | ||||
| - Fix FEELS translation for Croatian | ||||
| - Fixed weather tests [#1840](https://github.com/MichMich/MagicMirror/issues/1840) | ||||
| - Fixed Socket.io can't be used with Reverse Proxy in serveronly mode [#1934](https://github.com/MichMich/MagicMirror/issues/1934) | ||||
| - Fix update checking skipping 3rd party modules the first time | ||||
|  | ||||
| ### Changed | ||||
| - Remove documentation from core repository and link to new dedicated docs site: [docs.magicmirror.builders](https://docs.magicmirror.builders). | ||||
| @@ -33,6 +43,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). | ||||
|   - To start using electron, use `npm run start`. | ||||
|   - To start in server only mode, use `npm run server`. | ||||
| - Remove redundant logging from modules. | ||||
| - Timestamp in log output now also contains the date | ||||
| - Turkish translation. | ||||
| - Option to configure the size of the currentweather module. | ||||
|  | ||||
| ## [2.10.1] - 2020-01-10 | ||||
|  | ||||
| @@ -572,7 +585,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we | ||||
| - Added option `remoteFile` to compliments module to load compliment array from filesystem. | ||||
| - Added option `zoom` to scale the whole mirror display with a given factor. | ||||
| - Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer. | ||||
| - Added abilty set the classes option to compliments module for style and text size of compliments. | ||||
| - Added ability set the classes option to compliments module for style and text size of compliments. | ||||
| - Added ability to configure electronOptions | ||||
| - Calendar module: option to hide private events | ||||
| - Add root_path for global vars | ||||
|   | ||||
							
								
								
									
										10
									
								
								Gruntfile.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Gruntfile.js
									
									
									
									
									
								
							| @@ -1,10 +1,10 @@ | ||||
| module.exports = function(grunt) { | ||||
| 	require("time-grunt")(grunt); | ||||
| 	var fix = (grunt.option("env") || "lint") === "lint"; | ||||
| 	grunt.initConfig({ | ||||
| 		pkg: grunt.file.readJSON("package.json"), | ||||
| 		eslint: { | ||||
| 			options: { | ||||
| 				fix: "true", | ||||
| 				fix: fix, | ||||
| 				configFile: ".eslintrc.json" | ||||
| 			}, | ||||
| 			target: [ | ||||
| @@ -20,13 +20,13 @@ module.exports = function(grunt) { | ||||
| 				"!modules/default/alert/classie.js", | ||||
| 				"config/*", | ||||
| 				"translations/translations.js", | ||||
| 				"vendor/vendor.js", | ||||
| 				"modules/node_modules/node_helper/index.js" | ||||
| 				"vendor/vendor.js" | ||||
| 			] | ||||
| 		}, | ||||
| 		stylelint: { | ||||
| 			simple: { | ||||
| 				options: { | ||||
| 					fix: fix, | ||||
| 					configFile: ".stylelintrc.json" | ||||
| 				}, | ||||
| 				src: [ | ||||
| @@ -44,7 +44,6 @@ module.exports = function(grunt) { | ||||
| 					"package.json", | ||||
| 					".eslintrc.json", | ||||
| 					".stylelintrc.json", | ||||
| 					"installers/pm2_MagicMirror.json", | ||||
| 					"translations/*.json", | ||||
| 					"modules/default/*/translations/*.json", | ||||
| 					"vendor/package.json" | ||||
| @@ -102,5 +101,6 @@ module.exports = function(grunt) { | ||||
| 	grunt.loadNpmTasks("grunt-jsonlint"); | ||||
| 	grunt.loadNpmTasks("grunt-yamllint"); | ||||
| 	grunt.loadNpmTasks("grunt-markdownlint"); | ||||
|  | ||||
| 	grunt.registerTask("default", ["eslint", "stylelint", "jsonlint", "markdownlint", "yamllint"]); | ||||
| }; | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| /* jshint esversion: 6 */ | ||||
|  | ||||
| "use strict"; | ||||
|  | ||||
| // Use separate scope to prevent global scope pollution | ||||
|   | ||||
| @@ -21,6 +21,10 @@ var config = { | ||||
| 	                                                       // or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format : | ||||
| 	                                                       // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"], | ||||
|  | ||||
| 	useHttps: false, 		// Support HTTPS or not, default "false" will use HTTP | ||||
| 	httpsPrivateKey: "", 	// HTTPS private key path, only require when useHttps is true | ||||
| 	httpsCertificate: "", 	// HTTPS Certificate path, only require when useHttps is true | ||||
|  | ||||
| 	language: "en", | ||||
| 	timeFormat: 24, | ||||
| 	units: "metric", | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
| 		<div class="region bottom right"><div class="container"></div></div> | ||||
| 	</div> | ||||
| 	<div class="region fullscreen above"><div class="container"></div></div> | ||||
| 	<script type="text/javascript" src="/socket.io/socket.io.js"></script> | ||||
| 	<script type="text/javascript" src="socket.io/socket.io.js"></script> | ||||
| 	<script type="text/javascript" src="vendor/node_modules/nunjucks/browser/nunjucks.min.js"></script> | ||||
| 	<script type="text/javascript" src="js/defaults.js"></script> | ||||
| 	<script type="text/javascript" src="#CONFIG_FILE#"></script> | ||||
|   | ||||
| @@ -14,7 +14,7 @@ var path = require("path"); | ||||
| require("module-alias/register"); | ||||
|  | ||||
| // add timestamps in front of log messages | ||||
| require("console-stamp")(console, "HH:MM:ss.l"); | ||||
| require("console-stamp")(console, "yyyy-mm-dd HH:MM:ss.l"); | ||||
|  | ||||
| // Get version number. | ||||
| global.version = JSON.parse(fs.readFileSync("package.json", "utf8")).version; | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| /* jshint esversion: 6 */ | ||||
|  | ||||
| "use strict"; | ||||
|  | ||||
| const electron = require("electron"); | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| /* global  Log, Loader, Module, config, defaults */ | ||||
| /* jshint -W020, esversion: 6 */ | ||||
|  | ||||
| /* Magic Mirror | ||||
|  * Main System | ||||
| @@ -306,7 +305,9 @@ var MM = (function() { | ||||
| 			module.showHideTimer = setTimeout(function() { | ||||
| 				if (typeof callback === "function") { callback(); } | ||||
| 			}, speed); | ||||
|  | ||||
| 		} else { | ||||
| 			// invoke callback | ||||
| 			if (typeof callback === "function") { callback(); } | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -417,8 +417,11 @@ var Module = Class.extend({ | ||||
| 		callback = callback || function () { }; | ||||
| 		options = options || {}; | ||||
|  | ||||
| 		this.resume(); | ||||
| 		MM.showModule(this, speed, callback, options); | ||||
| 		var self = this; | ||||
| 		MM.showModule(this, speed, function () { | ||||
| 			self.resume(); | ||||
| 			callback; | ||||
| 		}, options); | ||||
| 	} | ||||
| }); | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								js/server.js
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								js/server.js
									
									
									
									
									
								
							| @@ -7,8 +7,6 @@ | ||||
|  | ||||
| var express = require("express"); | ||||
| var app = require("express")(); | ||||
| var server = require("http").Server(app); | ||||
| var io = require("socket.io")(server); | ||||
| var path = require("path"); | ||||
| var ipfilter = require("express-ipfilter").IpFilter; | ||||
| var fs = require("fs"); | ||||
| @@ -22,6 +20,18 @@ var Server = function(config, callback) { | ||||
| 		port = process.env.MM_PORT; | ||||
| 	} | ||||
|  | ||||
| 	var server = null; | ||||
| 	if(config.useHttps){ | ||||
| 		var options = { | ||||
| 			key: fs.readFileSync(config.httpsPrivateKey), | ||||
| 			cert: fs.readFileSync(config.httpsCertificate) | ||||
| 		}; | ||||
| 		server = require("https").Server(options, app); | ||||
| 	}else{ | ||||
| 		server = require("http").Server(app); | ||||
| 	} | ||||
| 	var io = require("socket.io")(server); | ||||
|  | ||||
| 	console.log("Starting server on port " + port + " ... "); | ||||
|  | ||||
| 	server.listen(port, config.address ? config.address : "localhost"); | ||||
|   | ||||
| @@ -8,7 +8,9 @@ var MMSocket = function(moduleName) { | ||||
| 	self.moduleName = moduleName; | ||||
|  | ||||
| 	// Private Methods | ||||
| 	self.socket = io("/" + self.moduleName); | ||||
| 	self.socket = io("/" + self.moduleName, { | ||||
| 		path: window.location.pathname + "socket.io" | ||||
| 	}); | ||||
| 	var notificationCallback = function() {}; | ||||
|  | ||||
| 	var onevent = self.socket.onevent; | ||||
|   | ||||
| @@ -152,9 +152,9 @@ Module.register("clock",{ | ||||
| 		} | ||||
|  | ||||
| 		function formatTime(config, time) { | ||||
| 			var formatString = hourSymbol + ':mm'; | ||||
| 			var formatString = hourSymbol + ":mm"; | ||||
| 			if (config.showPeriod && config.timeFormat !== 24) { | ||||
| 				formatString += config.showPeriodUpper ? 'A' : 'a'; | ||||
| 				formatString += config.showPeriodUpper ? "A" : "a"; | ||||
| 			} | ||||
| 			return moment(time).format(formatString); | ||||
| 		} | ||||
| @@ -167,23 +167,31 @@ Module.register("clock",{ | ||||
| 			} else if (now.isBefore(sunTimes.sunset)) { | ||||
| 				nextEvent = sunTimes.sunset; | ||||
| 			} else { | ||||
| 				const tomorrowSunTimes = SunCalc.getTimes(now.clone().add(1, 'day'), this.config.lat, this.config.lon); | ||||
| 				const tomorrowSunTimes = SunCalc.getTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon); | ||||
| 				nextEvent = tomorrowSunTimes.sunrise; | ||||
| 			} | ||||
| 			const untilNextEvent = moment.duration(moment(nextEvent).diff(now)); | ||||
| 			const untilNextEventString = untilNextEvent.hours() + 'h ' + untilNextEvent.minutes() + 'm'; | ||||
| 			sunWrapper.innerHTML = '<span class="' + (isVisible ? 'bright' : '') + '"><i class="fa fa-sun-o" aria-hidden="true"></i> ' + untilNextEventString + '</span>' + | ||||
| 				'<span><i class="fa fa-arrow-up" aria-hidden="true"></i>' + formatTime(this.config, sunTimes.sunrise) + '</span>' + | ||||
| 				'<span><i class="fa fa-arrow-down" aria-hidden="true"></i>' + formatTime(this.config, sunTimes.sunset) + '</span>'; | ||||
| 			const untilNextEventString = untilNextEvent.hours() + "h " + untilNextEvent.minutes() + "m"; | ||||
| 			sunWrapper.innerHTML = "<span class=\"" + (isVisible ? "bright" : "") + "\"><i class=\"fa fa-sun-o\" aria-hidden=\"true\"></i> " + untilNextEventString + "</span>" + | ||||
| 				"<span><i class=\"fa fa-arrow-up\" aria-hidden=\"true\"></i>" + formatTime(this.config, sunTimes.sunrise) + "</span>" + | ||||
| 				"<span><i class=\"fa fa-arrow-down\" aria-hidden=\"true\"></i>" + formatTime(this.config, sunTimes.sunset) + "</span>"; | ||||
| 		} | ||||
| 		if (this.config.showMoonTimes) { | ||||
| 			const moonIllumination = SunCalc.getMoonIllumination(now.toDate()); | ||||
| 			const moonTimes = SunCalc.getMoonTimes(now, this.config.lat, this.config.lon); | ||||
| 			const isVisible = now.isBetween(moonTimes.rise, moonTimes.set); | ||||
| 			const illuminatedFractionString = moonIllumination.fraction.toLocaleString(undefined, {style: 'percent'}); | ||||
| 			moonWrapper.innerHTML = '<span class="' + (isVisible ? 'bright' : '') + '"><i class="fa fa-moon-o" aria-hidden="true"></i> ' + illuminatedFractionString + '</span>' + | ||||
| 				'<span><i class="fa fa-arrow-up" aria-hidden="true"></i> ' + formatTime(this.config, moonTimes.rise) + '</span>'+ | ||||
| 				'<span><i class="fa fa-arrow-down" aria-hidden="true"></i> ' + formatTime(this.config, moonTimes.set) + '</span>'; | ||||
| 			const moonRise = moonTimes.rise; | ||||
| 			var moonSet; | ||||
| 			if (moment(moonTimes.set).isAfter(moonTimes.rise)) { | ||||
| 				moonSet = moonTimes.set; | ||||
| 			} else { | ||||
| 				const nextMoonTimes = SunCalc.getMoonTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon); | ||||
| 				moonSet = nextMoonTimes.set; | ||||
| 			} | ||||
| 			const isVisible = now.isBetween(moonRise, moonSet) || moonTimes.alwaysUp === true; | ||||
| 			const illuminatedFractionString = Math.round(moonIllumination.fraction * 100) + "%"; | ||||
| 			moonWrapper.innerHTML = "<span class=\"" + (isVisible ? "bright" : "") + "\"><i class=\"fa fa-moon-o\" aria-hidden=\"true\"></i> " + illuminatedFractionString + "</span>" + | ||||
| 				"<span><i class=\"fa fa-arrow-up\" aria-hidden=\"true\"></i> " + (moonRise ? formatTime(this.config, moonRise) : "...") + "</span>"+ | ||||
| 				"<span><i class=\"fa fa-arrow-down\" aria-hidden=\"true\"></i> " + (moonSet ? formatTime(this.config, moonSet) : "...") + "</span>"; | ||||
| 		} | ||||
|  | ||||
| 		/**************************************************************** | ||||
|   | ||||
| @@ -42,6 +42,7 @@ Module.register("currentweather",{ | ||||
|  | ||||
| 		appendLocationNameToHeader: true, | ||||
| 		calendarClass: "calendar", | ||||
| 		tableClass: "large", | ||||
|  | ||||
| 		onlyTemp: false, | ||||
| 		hideTemp: false, | ||||
| @@ -175,6 +176,7 @@ Module.register("currentweather",{ | ||||
| 	// Override dom generator. | ||||
| 	getDom: function() { | ||||
| 		var wrapper = document.createElement("div"); | ||||
| 		wrapper.className = this.config.tableClass; | ||||
|  | ||||
| 		if (this.config.appid === "") { | ||||
| 			wrapper.innerHTML = "Please set the correct openweather <i>appid</i> in the config for module: " + this.name + "."; | ||||
| @@ -193,7 +195,7 @@ Module.register("currentweather",{ | ||||
| 		} | ||||
|  | ||||
| 		var large = document.createElement("div"); | ||||
| 		large.className = "large light"; | ||||
| 		large.className = "light"; | ||||
|  | ||||
| 		var degreeLabel = ""; | ||||
| 		if (this.config.units === "metric" || this.config.units === "imperial") { | ||||
| @@ -217,7 +219,7 @@ Module.register("currentweather",{ | ||||
| 			this.config.decimalSymbol = "."; | ||||
| 		} | ||||
|  | ||||
| 		if (this.config.hideTemp === true) { | ||||
| 		if (this.config.hideTemp === false) { | ||||
| 			var weatherIcon = document.createElement("span"); | ||||
| 			weatherIcon.className = "wi weathericon " + this.weatherType; | ||||
| 			large.appendChild(weatherIcon); | ||||
|   | ||||
| @@ -18,37 +18,30 @@ module.exports = NodeHelper.create({ | ||||
| 	configureModules: function(modules) { | ||||
|  | ||||
| 		// Push MagicMirror itself , biggest chance it'll show up last in UI and isn't overwritten | ||||
| 		// others will be added in front, asynchronously | ||||
| 		// others will be added in front | ||||
| 		// this method returns promises so we can't wait for every one to resolve before continuing | ||||
| 		simpleGits.push({"module": "default", "git": SimpleGit(path.normalize(__dirname + "/../../../"))}); | ||||
|  | ||||
| 		var promises = []; | ||||
|  | ||||
| 		for (moduleName in modules) { | ||||
| 			if (defaultModules.indexOf(moduleName) < 0) { | ||||
| 			if (!this.ignoreUpdateChecking(moduleName)) { | ||||
| 				// Default modules are included in the main MagicMirror repo | ||||
| 				var moduleFolder = path.normalize(__dirname + "/../../" + moduleName); | ||||
|  | ||||
| 				var stat; | ||||
| 				try { | ||||
| 					//console.log("checking git for module="+moduleName) | ||||
| 					stat = fs.statSync(path.join(moduleFolder, ".git")); | ||||
| 					let stat = fs.statSync(path.join(moduleFolder, ".git")); | ||||
| 					promises.push(this.resolveRemote(moduleName, moduleFolder)); | ||||
| 				} catch(err) { | ||||
| 					// Error when directory .git doesn't exist | ||||
| 					// This module is not managed with git, skip | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 				var res = function(mn, mf) { | ||||
| 					var git = SimpleGit(mf); | ||||
| 					git.getRemotes(true, function(err, remotes) { | ||||
| 						if (remotes.length < 1 || remotes[0].name.length < 1) { | ||||
| 							// No valid remote for folder, skip | ||||
| 							return; | ||||
| 						} | ||||
| 						// Folder has .git and has at least one git remote, watch this folder | ||||
| 						simpleGits.unshift({"module": mn, "git": git}); | ||||
| 					}); | ||||
| 				}(moduleName, moduleFolder); | ||||
| 			} | ||||
| 		} | ||||
| 		return Promise.all(promises); | ||||
| 	}, | ||||
|  | ||||
| 	socketNotificationReceived: function (notification, payload) { | ||||
| @@ -56,21 +49,35 @@ module.exports = NodeHelper.create({ | ||||
| 			this.config = payload; | ||||
| 		} else if(notification === "MODULES") { | ||||
| 			// if this is the 1st time thru the update check process | ||||
| 			if(this.updateProcessStarted==false ){ | ||||
| 			if (!this.updateProcessStarted) { | ||||
| 				this.updateProcessStarted = true; | ||||
| 				this.configureModules(payload); | ||||
| 				this.preformFetch(); | ||||
| 				this.configureModules(payload).then(() => this.performFetch()); | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	preformFetch() { | ||||
| 	resolveRemote: function(moduleName, moduleFolder) { | ||||
| 		return new Promise((resolve, reject) => { | ||||
| 			var git = SimpleGit(moduleFolder); | ||||
| 			git.getRemotes(true, (err, remotes) => { | ||||
| 				if (remotes.length < 1 || remotes[0].name.length < 1) { | ||||
| 					// No valid remote for folder, skip | ||||
| 					return resolve(); | ||||
| 				} | ||||
| 				// Folder has .git and has at least one git remote, watch this folder | ||||
| 				simpleGits.unshift({"module": moduleName, "git": git}); | ||||
| 				resolve(); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}, | ||||
|  | ||||
| 	performFetch: function() { | ||||
| 		var self = this; | ||||
| 		simpleGits.forEach(function(sg) { | ||||
| 			sg.git.fetch().status(function(err, data) { | ||||
| 		simpleGits.forEach((sg) => { | ||||
| 			sg.git.fetch().status((err, data) => { | ||||
| 				data.module = sg.module; | ||||
| 				if (!err) { | ||||
| 					sg.git.log({"-1": null}, function(err, data2) { | ||||
| 					sg.git.log({"-1": null}, (err, data2) => { | ||||
| 						if (!err && data2.latest && "hash" in data2.latest) { | ||||
| 							data.hash = data2.latest.hash; | ||||
| 							self.sendSocketNotification("STATUS", data); | ||||
| @@ -91,8 +98,23 @@ module.exports = NodeHelper.create({ | ||||
| 		var self = this; | ||||
| 		clearTimeout(this.updateTimer); | ||||
| 		this.updateTimer = setTimeout(function() { | ||||
| 			self.preformFetch(); | ||||
| 			self.performFetch(); | ||||
| 		}, delay); | ||||
| 	}, | ||||
|  | ||||
| 	ignoreUpdateChecking: function(moduleName) { | ||||
| 		// Should not check for updates for default modules | ||||
| 		if (defaultModules.indexOf(moduleName) >= 0) { | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		// Should not check for updates for ignored modules | ||||
| 		if (this.config.ignoreModules.indexOf(moduleName) >= 0) { | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		// The rest of the modules that passes should check for updates | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| }); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ Module.register("updatenotification", { | ||||
| 	defaults: { | ||||
| 		updateInterval: 10 * 60 * 1000, // every 10 minutes | ||||
| 		refreshInterval: 24 * 60 * 60 * 1000, // one day | ||||
| 		ignoreModules: [] | ||||
| 	}, | ||||
|  | ||||
| 	suspended: false, | ||||
|   | ||||
							
								
								
									
										684
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										684
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -12,8 +12,9 @@ | ||||
|     "test": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests --recursive", | ||||
|     "test:unit": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests/unit --recursive", | ||||
|     "test:e2e": "NODE_ENV=test ./node_modules/mocha/bin/mocha tests/e2e --recursive", | ||||
|     "test:lint": "grunt --env=test", | ||||
|     "config:check": "node tests/configs/check_config.js", | ||||
|     "lint": "grunt" | ||||
|     "lint": "grunt --env=lint" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
| @@ -47,7 +48,6 @@ | ||||
|     "grunt-yamllint": "latest", | ||||
|     "http-auth": "^3.2.3", | ||||
|     "jsdom": "^11.6.2", | ||||
|     "jshint": "^2.10.2", | ||||
|     "mocha": "^7.0.0", | ||||
|     "mocha-each": "^1.1.0", | ||||
|     "mocha-logger": "^1.0.6", | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| var app = require("../js/app.js"); | ||||
| app.start(function(config) { | ||||
| 	var bindAddress = config.address ? config.address : "localhost"; | ||||
| 	console.log("\nReady to go! Please point your browser to: http://" + bindAddress + ":" + config.port); | ||||
| 	var httpType = config.useHttps ? "https" : "http"; | ||||
| 	console.log("\nReady to go! Please point your browser to: " + httpType + "://" + bindAddress + ":" + config.port); | ||||
| }); | ||||
|   | ||||
| @@ -9,7 +9,10 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| var v = require("jshint"); | ||||
| const Linter = require("eslint").Linter; | ||||
| const linter = new Linter(); | ||||
| const config = require(__dirname + "/../../.eslintrc.json"); | ||||
|  | ||||
| var path = require("path"); | ||||
| var fs = require("fs"); | ||||
| var Utils = require(__dirname + "/../../js/utils.js"); | ||||
| @@ -50,16 +53,15 @@ function checkConfigFile() { | ||||
| 	// I'm not sure if all ever is utf-8 | ||||
| 	fs.readFile(configFileName, "utf-8", function (err, data) { | ||||
| 		if (err) { throw err; } | ||||
| 		v.JSHINT(data); // Parser by jshint | ||||
|  | ||||
| 		if (v.JSHINT.errors.length === 0) { | ||||
| 		const messages = linter.verify(data, config); | ||||
| 		if (messages.length === 0) { | ||||
| 			console.log("Your configuration file doesn't contain syntax errors :)"); | ||||
| 			return true; | ||||
| 		} else { | ||||
| 			errors = v.JSHINT.data().errors; | ||||
| 			errors = messages; | ||||
| 			for (var idx in errors) { | ||||
| 				error = errors[idx]; | ||||
| 				console.log("Line", error.line, "col", error.character, error.reason); | ||||
| 				console.log("Line", error.line, "col", error.column, error.message); | ||||
| 			} | ||||
| 		} | ||||
| 	}); | ||||
|   | ||||
| @@ -8,14 +8,7 @@ const helpers = require("../global-setup"); | ||||
|  | ||||
| const {generateWeather, generateWeatherForecast} = require("./mocks"); | ||||
|  | ||||
| const wait = () => new Promise(res => setTimeout(res, 3000)); | ||||
|  | ||||
| // See issue: https://github.com/MichMich/MagicMirror/issues/1840 | ||||
| // Skipping the weather tests for now since these seem to give issues. | ||||
| // Please send a PR if you know how to fix these. Thanks! | ||||
|  		 | ||||
|  | ||||
| describe.skip("Weather module", function() { | ||||
| describe("Weather module", function() { | ||||
|  | ||||
| 	let app; | ||||
|  | ||||
| @@ -49,7 +42,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render wind speed and wind direction", async function() { | ||||
| 				const weather = generateWeather(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				return app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(2)", "6 WSW", 10000); | ||||
| 			}); | ||||
| @@ -59,7 +52,7 @@ describe.skip("Weather module", function() { | ||||
| 				const sunset = moment().startOf("day").unix(); | ||||
|  | ||||
| 				const weather = generateWeather({sys: {sunrise, sunset}}); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitForExist(".weather .normal.medium span.wi.dimmed.wi-sunrise", 10000); | ||||
|  | ||||
| @@ -71,7 +64,7 @@ describe.skip("Weather module", function() { | ||||
| 				const sunset = moment().endOf("day").unix(); | ||||
|  | ||||
| 				const weather = generateWeather({sys: {sunrise, sunset}}); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitForExist(".weather .normal.medium span.wi.dimmed.wi-sunset", 10000); | ||||
|  | ||||
| @@ -80,7 +73,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render temperature with icon", async function() { | ||||
| 				const weather = generateWeather(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitForExist(".weather .large.light span.wi.weathericon.wi-snow", 10000); | ||||
|  | ||||
| @@ -89,7 +82,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render feels like temperature", async function() { | ||||
| 				const weather = generateWeather(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				return app.client.waitUntilTextExists(".weather .normal.medium span.dimmed", "Feels like -5.6°", 10000); | ||||
| 			}); | ||||
| @@ -102,14 +95,14 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render useBeaufort = false", async function() { | ||||
| 				const weather = generateWeather(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				return app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(2)", "12", 10000); | ||||
| 			}); | ||||
|  | ||||
| 			it("should render showWindDirectionAsArrow = true", async function() { | ||||
| 				const weather = generateWeather(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitForExist(".weather .normal.medium sup i.fa-long-arrow-up", 10000); | ||||
| 				const element = await app.client.getHTML(".weather .normal.medium sup i.fa-long-arrow-up"); | ||||
| @@ -119,7 +112,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render showHumidity = true", async function() { | ||||
| 				const weather = generateWeather(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(3)", "93", 10000); | ||||
| 				return app.client.waitForExist(".weather .normal.medium sup i.wi-humidity", 10000); | ||||
| @@ -127,7 +120,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render degreeLabel = true", async function() { | ||||
| 				const weather = generateWeather(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitUntilTextExists(".weather .large.light span.bright", "1°C", 10000); | ||||
|  | ||||
| @@ -151,7 +144,7 @@ describe.skip("Weather module", function() { | ||||
| 						speed: 11.8 * 2.23694 | ||||
| 					}, | ||||
| 				}); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(2)", "6 WSW", 10000); | ||||
| 				await app.client.waitUntilTextExists(".weather .large.light span.bright", "34,7°", 10000); | ||||
| @@ -169,7 +162,7 @@ describe.skip("Weather module", function() { | ||||
| 						speed: 11.8 * 2.23694 | ||||
| 					}, | ||||
| 				}); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitUntilTextExists(".weather .normal.medium span:nth-child(3)", "93,7", 10000); | ||||
| 				await app.client.waitUntilTextExists(".weather .large.light span.bright", "34,7°", 10000); | ||||
| @@ -192,7 +185,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render days", async function() { | ||||
| 				const weather = generateWeatherForecast(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				const days = ["Fri", "Sat", "Sun", "Mon", "Tue"]; | ||||
|  | ||||
| @@ -203,7 +196,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render icons", async function() { | ||||
| 				const weather = generateWeatherForecast(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				const icons = ["day-cloudy", "rain", "day-sunny", "day-sunny", "day-sunny"]; | ||||
|  | ||||
| @@ -214,7 +207,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render max temperatures", async function() { | ||||
| 				const weather = generateWeatherForecast(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				const temperatures = ["24.4°", "21.0°", "22.9°", "23.4°", "20.6°"]; | ||||
|  | ||||
| @@ -225,7 +218,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render min temperatures", async function() { | ||||
| 				const weather = generateWeatherForecast(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				const temperatures = ["15.3°", "13.6°", "13.8°", "13.9°", "10.9°"]; | ||||
|  | ||||
| @@ -236,7 +229,7 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render fading of rows", async function() { | ||||
| 				const weather = generateWeatherForecast(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				const opacities = [1, 1, 0.8, 0.5333333333333333, 0.2666666666666667]; | ||||
|  | ||||
| @@ -256,14 +249,14 @@ describe.skip("Weather module", function() { | ||||
|  | ||||
| 			it("should render custom table class", async function() { | ||||
| 				const weather = generateWeatherForecast(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitForExist(".weather table.myTableClass", 10000); | ||||
| 			}); | ||||
|  | ||||
| 			it("should render colored rows", async function() { | ||||
| 				const weather = generateWeatherForecast(); | ||||
| 				await setup([weather, template]); | ||||
| 				await setup({template, data: weather}); | ||||
|  | ||||
| 				await app.client.waitForExist(".weather table.myTableClass", 10000); | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								tests/node_modules/webdriverajaxstub/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								tests/node_modules/webdriverajaxstub/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ function plugin (wdInstance, requests) { | ||||
| 		throw new Error("You can't use WebdriverAjaxStub with this version of WebdriverIO"); | ||||
| 	} | ||||
|  | ||||
| 	function stub(requests, done) { | ||||
| 	function stub({template, data}, done) { | ||||
| 		window.XMLHttpRequest = function () { | ||||
| 			this.open = function (method, url) { | ||||
| 				this.method = method; | ||||
| @@ -13,7 +13,7 @@ function plugin (wdInstance, requests) { | ||||
| 			this.send = function () { | ||||
| 				this.status = 200; | ||||
| 				this.readyState = 4; | ||||
| 				const response = requests.shift() || []; | ||||
| 				const response = this.url.includes(".njk") ? template : data; | ||||
| 				this.response = response; | ||||
| 				this.responseText = response; | ||||
| 				this.onreadystatechange(); | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| /* eslint no-multi-spaces: 0 */ | ||||
| var expect = require("chai").expect; | ||||
|  | ||||
| describe("Functions module currentweather", function() { | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| /* eslint no-multi-spaces: 0 */ | ||||
| var expect = require("chai").expect; | ||||
|  | ||||
| describe("Functions module weatherforecast", function() { | ||||
|   | ||||
| @@ -31,5 +31,5 @@ | ||||
| 	"UPDATE_INFO_SINGLE": "Instalirana verzija {COMMIT_COUNT} commit kasni za branch-om {BRANCH_NAME}.", | ||||
| 	"UPDATE_INFO_MULTIPLE": "Instalirana verzija {COMMIT_COUNT} commit-ova kasni za branch-om {BRANCH_NAME}.", | ||||
| 	 | ||||
| 	"FEELS": "Osjeća" | ||||
| 	"FEELS": "Osjećaj" | ||||
| } | ||||
|   | ||||
| @@ -26,5 +26,8 @@ | ||||
| 	"UPDATE_NOTIFICATION": "Nova atualização para MagicMirror disponível.", | ||||
| 	"UPDATE_NOTIFICATION_MODULE": "Atualização para o módulo {MODULE_NAME} disponível.", | ||||
| 	"UPDATE_INFO_SINGLE": "Sua versão atual é a {COMMIT_COUNT} commit dentro do seguinte branch {BRANCH_NAME}.", | ||||
| 	"UPDATE_INFO_MULTIPLE": "Sua versão atual é a {COMMIT_COUNT} commits dentro do seguinte branch {BRANCH_NAME}." | ||||
| 	"UPDATE_INFO_MULTIPLE": "Sua versão atual é a {COMMIT_COUNT} commits dentro do seguinte branch {BRANCH_NAME}.", | ||||
| 	 | ||||
| 	"FEELS": "Percebida", | ||||
| 	"PRECIP": "PoP" | ||||
| } | ||||
|   | ||||
| @@ -3,9 +3,12 @@ | ||||
|  | ||||
| 	"TODAY": "Bugün", | ||||
| 	"TOMORROW": "Yarın", | ||||
| 	"DAYAFTERTOMORROW": "İki gün içinde", | ||||
| 	"RUNNING": "Biten", | ||||
| 	"EMPTY": "Yakında etkinlik yok.", | ||||
| 	 | ||||
| 	"WEEK": "Hafta {weekNumber}", | ||||
|  | ||||
| 	"N": "K", | ||||
| 	"NNE": "KKD", | ||||
| 	"NE": "KD", | ||||
| @@ -21,5 +24,14 @@ | ||||
| 	"W": "B", | ||||
| 	"WNW": "BKB", | ||||
| 	"NW": "KB", | ||||
| 	"NNW": "KKB" | ||||
| 	"NNW": "KKB", | ||||
| 	 | ||||
| 	"UPDATE_NOTIFICATION": "MagicMirror² güncellemesi mevcut.", | ||||
| 	"UPDATE_NOTIFICATION_MODULE": "{MODULE_NAME} modulü için güncelleme mevcut.", | ||||
| 	"UPDATE_INFO_SINGLE": "Sahip olduğunuz kurulum {BRANCH_NAME} branchinden {COMMIT_COUNT} commit geridedir.", | ||||
| 	"UPDATE_INFO_MULTIPLE": "Sahip olduğunuz kurulum {BRANCH_NAME} branchinden {COMMIT_COUNT} commit geridedir.", | ||||
| 	 | ||||
| 	"FEELS": "Hissedilen", | ||||
| 	"PRECIP": "Yağış" | ||||
|  | ||||
| } | ||||
|   | ||||
							
								
								
									
										25
									
								
								vendor/package-lock.json
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/package-lock.json
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -703,6 +703,7 @@ | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", | ||||
|       "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "is-glob": "^2.0.0" | ||||
|       } | ||||
| @@ -716,7 +717,8 @@ | ||||
|     "inherits": { | ||||
|       "version": "2.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", | ||||
|       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" | ||||
|       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "invert-kv": { | ||||
|       "version": "1.0.0", | ||||
| @@ -735,7 +737,8 @@ | ||||
|     "is-buffer": { | ||||
|       "version": "1.1.5", | ||||
|       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", | ||||
|       "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" | ||||
|       "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "is-dotfile": { | ||||
|       "version": "1.0.3", | ||||
| @@ -761,7 +764,8 @@ | ||||
|     "is-extglob": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", | ||||
|       "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" | ||||
|       "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "is-fullwidth-code-point": { | ||||
|       "version": "1.0.0", | ||||
| @@ -775,6 +779,7 @@ | ||||
|       "version": "2.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", | ||||
|       "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "is-extglob": "^1.0.0" | ||||
|       } | ||||
| @@ -803,7 +808,8 @@ | ||||
|     "isarray": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", | ||||
|       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" | ||||
|       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "isobject": { | ||||
|       "version": "2.1.0", | ||||
| @@ -818,6 +824,7 @@ | ||||
|       "version": "3.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", | ||||
|       "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "is-buffer": "^1.1.5" | ||||
|       } | ||||
| @@ -883,6 +890,7 @@ | ||||
|       "version": "2.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", | ||||
|       "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", | ||||
|       "optional": true, | ||||
|       "requires": { | ||||
|         "remove-trailing-separator": "^1.0.1" | ||||
|       } | ||||
| @@ -1031,12 +1039,14 @@ | ||||
|     "remove-trailing-separator": { | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", | ||||
|       "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" | ||||
|       "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "repeat-element": { | ||||
|       "version": "1.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", | ||||
|       "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" | ||||
|       "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "repeat-string": { | ||||
|       "version": "1.6.1", | ||||
| @@ -1047,7 +1057,8 @@ | ||||
|     "safe-buffer": { | ||||
|       "version": "5.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", | ||||
|       "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" | ||||
|       "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", | ||||
|       "optional": true | ||||
|     }, | ||||
|     "set-immediate-shim": { | ||||
|       "version": "1.0.1", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user