mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-07-02 22:08:42 +00:00
Merge branch 'master' of https://github.com/MystaraTheGreat/MagicMirror
This commit is contained in:
commit
b72556b9a9
6
.github/ISSUE_TEMPLATE.md
vendored
6
.github/ISSUE_TEMPLATE.md
vendored
@ -6,6 +6,8 @@ If you're not sure if it's a real bug or if it's just you, please open a topic o
|
||||
|
||||
Problems installing or configuring your MagicMirror? Check out: [https://forum.magicmirror.builders/category/10/troubleshooting](https://forum.magicmirror.builders/category/10/troubleshooting)
|
||||
|
||||
A common problem is that your config file could be invalid. Please run in your MagicMirror directory: `npm run config:check` and see if it reports an error.
|
||||
|
||||
## I found a bug in the MagicMirror installer
|
||||
|
||||
If you are facing an issue or found a bug while trying to install MagicMirror via the installer please report it in the respective GitHub repository:
|
||||
@ -23,9 +25,9 @@ If you are facing an issue or found a bug while running MagicMirror inside a Doc
|
||||
Please make sure to only submit reproducible issues. You can safely remove everything above the dividing line.
|
||||
When submitting a new issue, please supply the following information:
|
||||
|
||||
**Platform**: Place your platform here... give us your web browser/Electron version _and_ your hardware (Raspberry Pi 2/3, Windows, Mac, Linux, System V UNIX).
|
||||
**Platform**: Place your platform here... give us your web browser/Electron version _and_ your hardware (Raspberry Pi 2/3/4, Windows, Mac, Linux, System V UNIX).
|
||||
|
||||
**Node Version**: Make sure it's version 8 or later.
|
||||
**Node Version**: Make sure it's version 10 or later.
|
||||
|
||||
**MagicMirror Version**: Please let us now which version of MagicMirror you are running. It can be found in the `package.log` file.
|
||||
|
||||
|
24
.github/workflows/codecov-test-suites.yml
vendored
Normal file
24
.github/workflows/codecov-test-suites.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# This workflow runs the automated test and uploads the coverage results to codecov.io
|
||||
|
||||
name: "Run Codecov Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
pull_request:
|
||||
branches: [ master, develop ]
|
||||
|
||||
jobs:
|
||||
run-and-upload-coverage-report:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: |
|
||||
Xvfb :99 -screen 0 1024x768x16 &
|
||||
export DISPLAY=:99
|
||||
npm ci
|
||||
npm run test:coverage
|
||||
- uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./coverage/lcov.info
|
||||
fail_ci_if_error: true
|
4
.github/workflows/enforce-changelog.yml
vendored
4
.github/workflows/enforce-changelog.yml
vendored
@ -1,10 +1,12 @@
|
||||
# This workflow enforces the update of a changelog file on every pull request
|
||||
|
||||
name: "Enforce Changelog"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
# Enforces the update of a changelog file on every pull request
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
5
.github/workflows/node-ci.js.yml
vendored
5
.github/workflows/node-ci.js.yml
vendored
@ -1,7 +1,7 @@
|
||||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||
|
||||
name: Automated Tests
|
||||
name: "Run Automated Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -11,13 +11,10 @@ on:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
|
48
CHANGELOG.md
48
CHANGELOG.md
@ -5,11 +5,54 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror²
|
||||
|
||||
## [2.14.1] - 2021-03-07
|
||||
## [2.15.0] - Unreleased (Develop Branch)
|
||||
|
||||
_This release is scheduled to be released on 2021-04-01._
|
||||
|
||||
### Added
|
||||
|
||||
- @MystaraTheGreat added hiddenOnStartup flag to module config (#2475)
|
||||
- Added GitHub workflows for automated testing and changelog enforcement.
|
||||
- Added CodeCov badge to Readme.
|
||||
- Added CURRENTWEATHER_TYPE notification to currentweather and weather module, use it in compliments module.
|
||||
- Added `start:dev` command to the npm scripts for starting electron with devTools open.
|
||||
- Added logging when using deprecated modules weatherforecast or currentweather.
|
||||
- Portuguese translations for "MODULE_CONFIG_CHANGED" and PRECIP.
|
||||
- Respect parameter ColoredSymbolOnly also for custom events
|
||||
- Added a new parameter to hide time portion on relative times
|
||||
- `module.show` has now the option for a callback on error.
|
||||
- Added locale to sample config file
|
||||
- Added support for self-signed certificates for the default calendar module (#466)
|
||||
- Added hiddenOnStartup flag to module config (#2475)
|
||||
|
||||
### Updated
|
||||
|
||||
- Updated markdown files.
|
||||
- Cleaned up old code on server side.
|
||||
- Convert `-0` to `0` when displaying temperature.
|
||||
- Code cleanup for FEELS like and added {DEGREE} placeholder for FEELSLIKE for each language
|
||||
- Converted newsfeed module to use templates.
|
||||
- Update documentation and help screen about invalid config files.
|
||||
- Moving weather provider specific code and configuration into each provider and making hourly part of the interface.
|
||||
- Bump electron to v11 and enable contextIsolation.
|
||||
- Dont update the DOM when a module is not displayed.
|
||||
- Cleaned up jsdoc and tests.
|
||||
- Exposed logger as node module for easier access for 3rd party modules
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed danger.js library.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added default log levels to stop calendar log spamming.
|
||||
- Fix socket.io cors errors, see [breaking change since socket.io v3](https://socket.io/docs/v3/handling-cors/)
|
||||
- Fix Issue with weather forecast icons due to fixed day start and end time (#2221)
|
||||
- Fix empty directory for each module's main javascript file in the inspector
|
||||
- Fix Issue with weather forecast icons unit tests with different timezones (#2221)
|
||||
- Fix issue with unencoded characters in translated strings when using nunjuck template (`Loading …` as an example)
|
||||
- Fix socket.io backward compatibility with socket v2 clients
|
||||
- 3rd party module language loading if language is English
|
||||
- Fix e2e tests after spectron update
|
||||
|
||||
## [2.14.0] - 2021-01-01
|
||||
|
||||
@ -31,7 +74,6 @@ Special thanks to the following contributors: @Alvinger, @AndyPoms, @ashishtank,
|
||||
- Calendar: new options "limitDays" and "coloredEvents".
|
||||
- Added new option "limitDays" - limit the number of discreet days displayed.
|
||||
- Added new option "customEvents" - use custom symbol/color based on keyword in event title.
|
||||
- Added GitHub workflows for automated testing and changelog enforcement.
|
||||
|
||||
### Updated
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# The MIT License (MIT)
|
||||
|
||||
Copyright © 2016-2020 Michael Teeuw
|
||||
Copyright © 2016-2021 Michael Teeuw
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
@ -1,9 +1,10 @@
|
||||

|
||||
|
||||
<p align="center">
|
||||
<p style="text-align: center">
|
||||
<a href="https://david-dm.org/MichMich/MagicMirror"><img src="https://david-dm.org/MichMich/MagicMirror.svg" alt="Dependency Status"></a>
|
||||
<a href="https://david-dm.org/MichMich/MagicMirror#info=devDependencies"><img src="https://david-dm.org/MichMich/MagicMirror/dev-status.svg" alt="devDependency Status"></a>
|
||||
<a href="https://bestpractices.coreinfrastructure.org/projects/347"><img src="https://bestpractices.coreinfrastructure.org/projects/347/badge"></a>
|
||||
<a href="https://bestpractices.coreinfrastructure.org/projects/347"><img src="https://bestpractices.coreinfrastructure.org/projects/347/badge" alt="CLI Best Practices"></a>
|
||||
<a href="https://codecov.io/gh/MichMich/MagicMirror"><img src="https://codecov.io/gh/MichMich/MagicMirror/branch/master/graph/badge.svg?token=LEG1KitZR6"/></a>
|
||||
<a href="https://choosealicense.com/licenses/mit"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
|
||||
<a href="https://github.com/MichMich/MagicMirror/actions?query=workflow%3A%22Automated+Tests%22"><img src="https://github.com/MichMich/MagicMirror/workflows/Automated%20Tests/badge.svg" alt="Tests"></a>
|
||||
</p>
|
||||
@ -38,7 +39,6 @@ If we receive enough donations we might even be able to free up some working hou
|
||||
|
||||
To donate, please follow [this](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G5D8E9MR5DTD2&source=url) link.
|
||||
|
||||
<p align="center">
|
||||
<br>
|
||||
<p style="text-align: center">
|
||||
<a href="https://forum.magicmirror.builders/topic/728/magicmirror-is-voted-number-1-in-the-magpi-top-50"><img src="https://magicmirror.builders/img/magpi-best-watermark-custom.png" width="150" alt="MagPi Top 50"></a>
|
||||
</p>
|
||||
|
@ -14,7 +14,6 @@
|
||||
*
|
||||
* @param {string} key key to look for at the command line
|
||||
* @param {string} defaultValue value if no key is given at the command line
|
||||
*
|
||||
* @returns {string} the value of the parameter
|
||||
*/
|
||||
function getCommandLineParameter(key, defaultValue = undefined) {
|
||||
@ -36,7 +35,6 @@
|
||||
* Gets the config from the specified server url
|
||||
*
|
||||
* @param {string} url location where the server is running.
|
||||
*
|
||||
* @returns {Promise} the config
|
||||
*/
|
||||
function getServerConfig(url) {
|
||||
@ -66,7 +64,7 @@
|
||||
/**
|
||||
* Print a message to the console in case of errors
|
||||
*
|
||||
* @param {string} [message] error message to print
|
||||
* @param {string} message error message to print
|
||||
* @param {number} code error code for the exit call
|
||||
*/
|
||||
function fail(message, code = 1) {
|
||||
|
@ -28,6 +28,7 @@ var config = {
|
||||
httpsCertificate: "", // HTTPS Certificate path, only require when useHttps is true
|
||||
|
||||
language: "en",
|
||||
locale: "en-US",
|
||||
logLevel: ["INFO", "LOG", "WARN", "ERROR"], // Add "DEBUG" for even more logging
|
||||
timeFormat: 24,
|
||||
units: "metric",
|
||||
@ -66,22 +67,26 @@ var config = {
|
||||
position: "lower_third"
|
||||
},
|
||||
{
|
||||
module: "currentweather",
|
||||
module: "weather",
|
||||
position: "top_right",
|
||||
config: {
|
||||
weatherProvider: "openweathermap",
|
||||
type: "current",
|
||||
location: "New York",
|
||||
locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
|
||||
appid: "YOUR_OPENWEATHER_API_KEY"
|
||||
apiKey: "YOUR_OPENWEATHER_API_KEY"
|
||||
}
|
||||
},
|
||||
{
|
||||
module: "weatherforecast",
|
||||
module: "weather",
|
||||
position: "top_right",
|
||||
header: "Weather Forecast",
|
||||
config: {
|
||||
weatherProvider: "openweathermap",
|
||||
type: "forecast",
|
||||
location: "New York",
|
||||
locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
|
||||
appid: "YOUR_OPENWEATHER_API_KEY"
|
||||
apiKey: "YOUR_OPENWEATHER_API_KEY"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1,17 +0,0 @@
|
||||
import { danger, fail, warn } from "danger";
|
||||
|
||||
// Check if the CHANGELOG.md file has been edited
|
||||
// Fail the build and post a comment reminding submitters to do so if it wasn't changed
|
||||
if (!danger.git.modified_files.includes("CHANGELOG.md")) {
|
||||
warn("Please include an updated `CHANGELOG.md` file.<br>This way we can keep track of all the contributions.");
|
||||
}
|
||||
|
||||
// Check if the PR request is send to the master branch.
|
||||
// This should only be done by MichMich.
|
||||
if (danger.github.pr.base.ref === "master" && danger.github.pr.user.login !== "MichMich") {
|
||||
// Check if the PR body or title includes the text: #accepted.
|
||||
// If not, the PR will fail.
|
||||
if ((danger.github.pr.body + danger.github.pr.title).includes("#accepted")) {
|
||||
fail("Please send all your pull requests to the `develop` branch.<br>Pull requests on the `master` branch will not be accepted.");
|
||||
}
|
||||
}
|
132
js/app.js
132
js/app.js
@ -4,22 +4,23 @@
|
||||
* By Michael Teeuw https://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*/
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var Log = require(__dirname + "/logger.js");
|
||||
var Server = require(__dirname + "/server.js");
|
||||
var Utils = require(__dirname + "/utils.js");
|
||||
var defaultModules = require(__dirname + "/../modules/default/defaultmodules.js");
|
||||
|
||||
// Alias modules mentioned in package.js under _moduleAliases.
|
||||
require("module-alias/register");
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const Log = require("logger");
|
||||
const Server = require(`${__dirname}/server`);
|
||||
const Utils = require(`${__dirname}/utils`);
|
||||
const defaultModules = require(`${__dirname}/../modules/default/defaultmodules`);
|
||||
|
||||
// Get version number.
|
||||
global.version = JSON.parse(fs.readFileSync("package.json", "utf8")).version;
|
||||
global.version = require(`${__dirname}/../package.json`).version;
|
||||
Log.log("Starting MagicMirror: v" + global.version);
|
||||
|
||||
// global absolute root path
|
||||
global.root_path = path.resolve(__dirname + "/../");
|
||||
global.root_path = path.resolve(`${__dirname}/../`);
|
||||
|
||||
if (process.env.MM_CONFIG_FILE) {
|
||||
global.configuration_file = process.env.MM_CONFIG_FILE;
|
||||
@ -45,43 +46,40 @@ process.on("uncaughtException", function (err) {
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
var App = function () {
|
||||
var nodeHelpers = [];
|
||||
function App() {
|
||||
let nodeHelpers = [];
|
||||
|
||||
/**
|
||||
* Loads the config file. Combines it with the defaults, and runs the
|
||||
* Loads the config file. Combines it with the defaults, and runs the
|
||||
* callback with the found config as argument.
|
||||
*
|
||||
* @param {Function} callback Function to be called after loading the config
|
||||
*/
|
||||
var loadConfig = function (callback) {
|
||||
function loadConfig(callback) {
|
||||
Log.log("Loading config ...");
|
||||
var defaults = require(__dirname + "/defaults.js");
|
||||
const defaults = require(`${__dirname}/defaults`);
|
||||
|
||||
// For this check proposed to TestSuite
|
||||
// https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8
|
||||
var configFilename = path.resolve(global.root_path + "/config/config.js");
|
||||
if (typeof global.configuration_file !== "undefined") {
|
||||
configFilename = path.resolve(global.configuration_file);
|
||||
}
|
||||
const configFilename = path.resolve(global.configuration_file || `${global.root_path}/config/config.js`);
|
||||
|
||||
try {
|
||||
fs.accessSync(configFilename, fs.F_OK);
|
||||
var c = require(configFilename);
|
||||
const c = require(configFilename);
|
||||
checkDeprecatedOptions(c);
|
||||
var config = Object.assign(defaults, c);
|
||||
const config = Object.assign(defaults, c);
|
||||
callback(config);
|
||||
} catch (e) {
|
||||
if (e.code === "ENOENT") {
|
||||
Log.error(Utils.colors.error("WARNING! Could not find config file. Please create one. Starting with default configuration."));
|
||||
} else if (e instanceof ReferenceError || e instanceof SyntaxError) {
|
||||
Log.error(Utils.colors.error("WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: " + e.stack));
|
||||
Log.error(Utils.colors.error(`WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: ${e.stack}`));
|
||||
} else {
|
||||
Log.error(Utils.colors.error("WARNING! Could not load config file. Starting with default configuration. Error found: " + e));
|
||||
Log.error(Utils.colors.error(`WARNING! Could not load config file. Starting with default configuration. Error found: ${e}`));
|
||||
}
|
||||
callback(defaults);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the config for deprecated options and throws a warning in the logs
|
||||
@ -89,21 +87,15 @@ var App = function () {
|
||||
*
|
||||
* @param {object} userConfig The user config
|
||||
*/
|
||||
var checkDeprecatedOptions = function (userConfig) {
|
||||
var deprecated = require(global.root_path + "/js/deprecated.js");
|
||||
var deprecatedOptions = deprecated.configs;
|
||||
function checkDeprecatedOptions(userConfig) {
|
||||
const deprecated = require(`${global.root_path}/js/deprecated`);
|
||||
const deprecatedOptions = deprecated.configs;
|
||||
|
||||
var usedDeprecated = [];
|
||||
|
||||
deprecatedOptions.forEach(function (option) {
|
||||
if (userConfig.hasOwnProperty(option)) {
|
||||
usedDeprecated.push(option);
|
||||
}
|
||||
});
|
||||
const usedDeprecated = deprecatedOptions.filter((option) => userConfig.hasOwnProperty(option));
|
||||
if (usedDeprecated.length > 0) {
|
||||
Log.warn(Utils.colors.warn("WARNING! Your config is using deprecated options: " + usedDeprecated.join(", ") + ". Check README and CHANGELOG for more up-to-date ways of getting the same functionality."));
|
||||
Log.warn(Utils.colors.warn(`WARNING! Your config is using deprecated options: ${usedDeprecated.join(", ")}. Check README and CHANGELOG for more up-to-date ways of getting the same functionality.`));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specific module.
|
||||
@ -111,35 +103,35 @@ var App = function () {
|
||||
* @param {string} module The name of the module (including subpath).
|
||||
* @param {Function} callback Function to be called after loading
|
||||
*/
|
||||
var loadModule = function (module, callback) {
|
||||
var elements = module.split("/");
|
||||
var moduleName = elements[elements.length - 1];
|
||||
var moduleFolder = __dirname + "/../modules/" + module;
|
||||
function loadModule(module, callback) {
|
||||
const elements = module.split("/");
|
||||
const moduleName = elements[elements.length - 1];
|
||||
let moduleFolder = `${__dirname}/../modules/${module}`;
|
||||
|
||||
if (defaultModules.indexOf(moduleName) !== -1) {
|
||||
moduleFolder = __dirname + "/../modules/default/" + module;
|
||||
if (defaultModules.includes(moduleName)) {
|
||||
moduleFolder = `${__dirname}/../modules/default/${module}`;
|
||||
}
|
||||
|
||||
var helperPath = moduleFolder + "/node_helper.js";
|
||||
const helperPath = `${moduleFolder}/node_helper.js`;
|
||||
|
||||
var loadModule = true;
|
||||
let loadHelper = true;
|
||||
try {
|
||||
fs.accessSync(helperPath, fs.R_OK);
|
||||
} catch (e) {
|
||||
loadModule = false;
|
||||
Log.log("No helper found for module: " + moduleName + ".");
|
||||
loadHelper = false;
|
||||
Log.log(`No helper found for module: ${moduleName}.`);
|
||||
}
|
||||
|
||||
if (loadModule) {
|
||||
var Module = require(helperPath);
|
||||
var m = new Module();
|
||||
if (loadHelper) {
|
||||
const Module = require(helperPath);
|
||||
let m = new Module();
|
||||
|
||||
if (m.requiresVersion) {
|
||||
Log.log("Check MagicMirror version for node helper '" + moduleName + "' - Minimum version: " + m.requiresVersion + " - Current version: " + global.version);
|
||||
Log.log(`Check MagicMirror version for node helper '${moduleName}' - Minimum version: ${m.requiresVersion} - Current version: ${global.version}`);
|
||||
if (cmpVersions(global.version, m.requiresVersion) >= 0) {
|
||||
Log.log("Version is ok!");
|
||||
} else {
|
||||
Log.log("Version is incorrect. Skip module: '" + moduleName + "'");
|
||||
Log.warn(`Version is incorrect. Skip module: '${moduleName}'`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -152,7 +144,7 @@ var App = function () {
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all modules.
|
||||
@ -160,12 +152,15 @@ var App = function () {
|
||||
* @param {Module[]} modules All modules to be loaded
|
||||
* @param {Function} callback Function to be called after loading
|
||||
*/
|
||||
var loadModules = function (modules, callback) {
|
||||
function loadModules(modules, callback) {
|
||||
Log.log("Loading module helpers ...");
|
||||
|
||||
var loadNextModule = function () {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function loadNextModule() {
|
||||
if (modules.length > 0) {
|
||||
var nextModule = modules[0];
|
||||
const nextModule = modules[0];
|
||||
loadModule(nextModule, function () {
|
||||
modules = modules.slice(1);
|
||||
loadNextModule();
|
||||
@ -175,10 +170,10 @@ var App = function () {
|
||||
Log.log("All module helpers loaded.");
|
||||
callback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
loadNextModule();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two semantic version numbers and return the difference.
|
||||
@ -190,11 +185,11 @@ var App = function () {
|
||||
* number if a is smaller and 0 if they are the same
|
||||
*/
|
||||
function cmpVersions(a, b) {
|
||||
var i, diff;
|
||||
var regExStrip0 = /(\.0+)+$/;
|
||||
var segmentsA = a.replace(regExStrip0, "").split(".");
|
||||
var segmentsB = b.replace(regExStrip0, "").split(".");
|
||||
var l = Math.min(segmentsA.length, segmentsB.length);
|
||||
let i, diff;
|
||||
const regExStrip0 = /(\.0+)+$/;
|
||||
const segmentsA = a.replace(regExStrip0, "").split(".");
|
||||
const segmentsB = b.replace(regExStrip0, "").split(".");
|
||||
const l = Math.min(segmentsA.length, segmentsB.length);
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
|
||||
@ -219,21 +214,19 @@ var App = function () {
|
||||
|
||||
Log.setLogLevel(config.logLevel);
|
||||
|
||||
var modules = [];
|
||||
let modules = [];
|
||||
|
||||
for (var m in config.modules) {
|
||||
var module = config.modules[m];
|
||||
if (modules.indexOf(module.module) === -1 && !module.disabled) {
|
||||
for (const module of config.modules) {
|
||||
if (!modules.includes(module.module) && !module.disabled) {
|
||||
modules.push(module.module);
|
||||
}
|
||||
}
|
||||
|
||||
loadModules(modules, function () {
|
||||
var server = new Server(config, function (app, io) {
|
||||
const server = new Server(config, function (app, io) {
|
||||
Log.log("Server started ...");
|
||||
|
||||
for (var h in nodeHelpers) {
|
||||
var nodeHelper = nodeHelpers[h];
|
||||
for (let nodeHelper of nodeHelpers) {
|
||||
nodeHelper.setExpressApp(app);
|
||||
nodeHelper.setSocketIO(io);
|
||||
nodeHelper.start();
|
||||
@ -256,8 +249,7 @@ var App = function () {
|
||||
* Added to fix #1056
|
||||
*/
|
||||
this.stop = function () {
|
||||
for (var h in nodeHelpers) {
|
||||
var nodeHelper = nodeHelpers[h];
|
||||
for (const nodeHelper of nodeHelpers) {
|
||||
if (typeof nodeHelper.stop === "function") {
|
||||
nodeHelper.stop();
|
||||
}
|
||||
@ -292,6 +284,6 @@ var App = function () {
|
||||
this.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = new App();
|
||||
|
@ -11,9 +11,9 @@ const linter = new Linter();
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
const rootPath = path.resolve(__dirname + "/../");
|
||||
const Log = require(rootPath + "/js/logger.js");
|
||||
const Utils = require(rootPath + "/js/utils.js");
|
||||
const rootPath = path.resolve(`${__dirname}/../`);
|
||||
const Log = require(`${rootPath}/js/logger.js`);
|
||||
const Utils = require(`${rootPath}/js/utils.js`);
|
||||
|
||||
/**
|
||||
* Returns a string with path of configuration file.
|
||||
@ -23,11 +23,7 @@ const Utils = require(rootPath + "/js/utils.js");
|
||||
*/
|
||||
function getConfigFile() {
|
||||
// FIXME: This function should be in core. Do you want refactor me ;) ?, be good!
|
||||
let configFileName = path.resolve(rootPath + "/config/config.js");
|
||||
if (process.env.MM_CONFIG_FILE) {
|
||||
configFileName = path.resolve(process.env.MM_CONFIG_FILE);
|
||||
}
|
||||
return configFileName;
|
||||
return path.resolve(process.env.MM_CONFIG_FILE || `${rootPath}/config/config.js`);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,21 +50,18 @@ function checkConfigFile() {
|
||||
Log.info(Utils.colors.info("Checking file... "), configFileName);
|
||||
|
||||
// I'm not sure if all ever is utf-8
|
||||
fs.readFile(configFileName, "utf-8", function (err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
const configFile = fs.readFileSync(configFileName, "utf-8");
|
||||
|
||||
const errors = linter.verify(configFile);
|
||||
if (errors.length === 0) {
|
||||
Log.info(Utils.colors.pass("Your configuration file doesn't contain syntax errors :)"));
|
||||
} else {
|
||||
Log.error(Utils.colors.error("Your configuration file contains syntax errors :("));
|
||||
|
||||
for (const error of errors) {
|
||||
Log.error(`Line ${error.line} column ${error.column}: ${error.message}`);
|
||||
}
|
||||
const messages = linter.verify(data);
|
||||
if (messages.length === 0) {
|
||||
Log.info(Utils.colors.pass("Your configuration file doesn't contain syntax errors :)"));
|
||||
} else {
|
||||
Log.error(Utils.colors.error("Your configuration file contains syntax errors :("));
|
||||
// In case the there errors show messages and return
|
||||
messages.forEach((error) => {
|
||||
Log.error("Line", error.line, "col", error.column, error.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
checkConfigFile();
|
||||
|
@ -20,6 +20,7 @@ var defaults = {
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||
|
||||
language: "en",
|
||||
logLevel: ["INFO", "LOG", "WARN", "ERROR"],
|
||||
timeFormat: 24,
|
||||
units: "metric",
|
||||
zoom: 1,
|
||||
@ -42,7 +43,7 @@ var defaults = {
|
||||
module: "helloworld",
|
||||
position: "middle_center",
|
||||
config: {
|
||||
text: "Please create a config file."
|
||||
text: "Please create a config file or check the existing one for errors."
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -58,7 +59,7 @@ var defaults = {
|
||||
position: "middle_center",
|
||||
classes: "xsmall",
|
||||
config: {
|
||||
text: "If you get this message while your config file is already<br>created, your config file probably contains an error.<br>Use a JavaScript linter to validate your file."
|
||||
text: "If you get this message while your config file is already created,<br>" + "it probably contains an error. To validate your config file run in your MagicMirror directory<br>" + "<pre>npm run config:check</pre>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -6,11 +6,6 @@
|
||||
* Olex S. original idea this deprecated option
|
||||
*/
|
||||
|
||||
var deprecated = {
|
||||
module.exports = {
|
||||
configs: ["kioskmode"]
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = deprecated;
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
const electron = require("electron");
|
||||
const core = require("./app.js");
|
||||
const Log = require("./logger.js");
|
||||
const Log = require("logger");
|
||||
|
||||
// Config
|
||||
var config = process.env.config ? JSON.parse(process.env.config) : {};
|
||||
let config = process.env.config ? JSON.parse(process.env.config) : {};
|
||||
// Module to control application life.
|
||||
const app = electron.app;
|
||||
// Module to create native browser window.
|
||||
@ -20,13 +20,14 @@ let mainWindow;
|
||||
*/
|
||||
function createWindow() {
|
||||
app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required");
|
||||
var electronOptionsDefaults = {
|
||||
let electronOptionsDefaults = {
|
||||
width: 800,
|
||||
height: 600,
|
||||
x: 0,
|
||||
y: 0,
|
||||
darkTheme: true,
|
||||
webPreferences: {
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
zoomFactor: config.zoom
|
||||
},
|
||||
@ -42,7 +43,7 @@ function createWindow() {
|
||||
electronOptionsDefaults.autoHideMenuBar = true;
|
||||
}
|
||||
|
||||
var electronOptions = Object.assign({}, electronOptionsDefaults, config.electronOptions);
|
||||
const electronOptions = Object.assign({}, electronOptionsDefaults, config.electronOptions);
|
||||
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow(electronOptions);
|
||||
@ -50,14 +51,14 @@ function createWindow() {
|
||||
// and load the index.html of the app.
|
||||
// If config.address is not defined or is an empty string (listening on all interfaces), connect to localhost
|
||||
|
||||
var prefix;
|
||||
let prefix;
|
||||
if (config["tls"] !== null && config["tls"]) {
|
||||
prefix = "https://";
|
||||
} else {
|
||||
prefix = "http://";
|
||||
}
|
||||
|
||||
var address = (config.address === void 0) | (config.address === "") ? (config.address = "localhost") : config.address;
|
||||
let address = (config.address === void 0) | (config.address === "") ? (config.address = "localhost") : config.address;
|
||||
mainWindow.loadURL(`${prefix}${address}:${config.port}`);
|
||||
|
||||
// Open the DevTools if run with "npm start dev"
|
||||
@ -125,7 +126,7 @@ app.on("before-quit", (event) => {
|
||||
|
||||
// Start the core application if server is run on localhost
|
||||
// This starts all node helpers and starts the webserver.
|
||||
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) > -1) {
|
||||
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].includes(config.address)) {
|
||||
core.start(function (c) {
|
||||
config = c;
|
||||
});
|
||||
|
@ -125,7 +125,7 @@ var Loader = (function () {
|
||||
* @param {Function} callback Function called when done.
|
||||
*/
|
||||
var loadModule = function (module, callback) {
|
||||
var url = module.path + "/" + module.file;
|
||||
var url = module.path + module.file;
|
||||
|
||||
var afterLoad = function () {
|
||||
var moduleObject = Module.create(module.name);
|
||||
|
@ -295,6 +295,9 @@ var MM = (function () {
|
||||
// Otherwise cancel show action.
|
||||
if (module.lockStrings.length !== 0 && options.force !== true) {
|
||||
Log.log("Will not show " + module.name + ". LockStrings active: " + module.lockStrings.join(","));
|
||||
if (typeof options.onError === "function") {
|
||||
options.onError(new Error("LOCK_STRING_ACTIVE"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -440,7 +443,6 @@ var MM = (function () {
|
||||
* Removes a module instance from the collection.
|
||||
*
|
||||
* @param {object} module The module instance to remove from the collection.
|
||||
*
|
||||
* @returns {Module[]} Filtered collection of modules.
|
||||
*/
|
||||
var exceptModule = function (module) {
|
||||
@ -547,6 +549,11 @@ var MM = (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!module.data.position) {
|
||||
Log.warn("module tries to update the DOM without being displayed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Further implementation is done in the private method.
|
||||
updateDom(module, speed);
|
||||
},
|
||||
|
53
js/module.js
53
js/module.js
@ -176,7 +176,7 @@ var Module = Class.extend({
|
||||
});
|
||||
|
||||
this._nunjucksEnvironment.addFilter("translate", function (str, variables) {
|
||||
return self.translate(str, variables);
|
||||
return nunjucks.runtime.markSafe(self.translate(str, variables));
|
||||
});
|
||||
|
||||
return this._nunjucksEnvironment;
|
||||
@ -311,33 +311,33 @@ var Module = Class.extend({
|
||||
*
|
||||
* @param {Function} callback Function called when done.
|
||||
*/
|
||||
loadTranslations: function (callback) {
|
||||
var self = this;
|
||||
var translations = this.getTranslations();
|
||||
var lang = config.language.toLowerCase();
|
||||
loadTranslations(callback) {
|
||||
const translations = this.getTranslations() || {};
|
||||
const language = config.language.toLowerCase();
|
||||
|
||||
// The variable `first` will contain the first
|
||||
// defined translation after the following line.
|
||||
for (var first in translations) {
|
||||
break;
|
||||
}
|
||||
const languages = Object.keys(translations);
|
||||
const fallbackLanguage = languages[0];
|
||||
|
||||
if (translations) {
|
||||
var translationFile = translations[lang] || undefined;
|
||||
var translationsFallbackFile = translations[first];
|
||||
|
||||
// If a translation file is set, load it and then also load the fallback translation file.
|
||||
// Otherwise only load the fallback translation file.
|
||||
if (translationFile !== undefined && translationFile !== translationsFallbackFile) {
|
||||
Translator.load(self, translationFile, false, function () {
|
||||
Translator.load(self, translationsFallbackFile, true, callback);
|
||||
});
|
||||
} else {
|
||||
Translator.load(self, translationsFallbackFile, true, callback);
|
||||
}
|
||||
} else {
|
||||
if (languages.length === 0) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
const translationFile = translations[language];
|
||||
const translationsFallbackFile = translations[fallbackLanguage];
|
||||
|
||||
if (!translationFile) {
|
||||
Translator.load(this, translationsFallbackFile, true, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
Translator.load(this, translationFile, false, () => {
|
||||
if (translationFile !== translationsFallbackFile) {
|
||||
Translator.load(this, translationsFallbackFile, true, callback);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -428,12 +428,11 @@ var Module = Class.extend({
|
||||
callback = callback || function () {};
|
||||
options = options || {};
|
||||
|
||||
var self = this;
|
||||
MM.showModule(
|
||||
this,
|
||||
speed,
|
||||
function () {
|
||||
self.resume();
|
||||
() => {
|
||||
this.resume();
|
||||
callback();
|
||||
},
|
||||
options
|
||||
|
@ -5,21 +5,21 @@
|
||||
* MIT Licensed.
|
||||
*/
|
||||
const Class = require("./class.js");
|
||||
const Log = require("./logger.js");
|
||||
const Log = require("logger");
|
||||
const express = require("express");
|
||||
|
||||
var NodeHelper = Class.extend({
|
||||
init: function () {
|
||||
const NodeHelper = Class.extend({
|
||||
init() {
|
||||
Log.log("Initializing new module helper ...");
|
||||
},
|
||||
|
||||
loaded: function (callback) {
|
||||
Log.log("Module helper loaded: " + this.name);
|
||||
loaded(callback) {
|
||||
Log.log(`Module helper loaded: ${this.name}`);
|
||||
callback();
|
||||
},
|
||||
|
||||
start: function () {
|
||||
Log.log("Starting module helper: " + this.name);
|
||||
start() {
|
||||
Log.log(`Starting module helper: ${this.name}`);
|
||||
},
|
||||
|
||||
/* stop()
|
||||
@ -28,8 +28,8 @@ var NodeHelper = Class.extend({
|
||||
* gracefully exit the module.
|
||||
*
|
||||
*/
|
||||
stop: function () {
|
||||
Log.log("Stopping module helper: " + this.name);
|
||||
stop() {
|
||||
Log.log(`Stopping module helper: ${this.name}`);
|
||||
},
|
||||
|
||||
/* socketNotificationReceived(notification, payload)
|
||||
@ -38,8 +38,8 @@ var NodeHelper = Class.extend({
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
*/
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
|
||||
socketNotificationReceived(notification, payload) {
|
||||
Log.log(`${this.name} received a socket notification: ${notification} - Payload: ${payload}`);
|
||||
},
|
||||
|
||||
/* setName(name)
|
||||
@ -47,7 +47,7 @@ var NodeHelper = Class.extend({
|
||||
*
|
||||
* argument name string - Module name.
|
||||
*/
|
||||
setName: function (name) {
|
||||
setName(name) {
|
||||
this.name = name;
|
||||
},
|
||||
|
||||
@ -56,7 +56,7 @@ var NodeHelper = Class.extend({
|
||||
*
|
||||
* argument path string - Module path.
|
||||
*/
|
||||
setPath: function (path) {
|
||||
setPath(path) {
|
||||
this.path = path;
|
||||
},
|
||||
|
||||
@ -66,7 +66,7 @@ var NodeHelper = Class.extend({
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
*/
|
||||
sendSocketNotification: function (notification, payload) {
|
||||
sendSocketNotification(notification, payload) {
|
||||
this.io.of(this.name).emit(notification, payload);
|
||||
},
|
||||
|
||||
@ -76,11 +76,10 @@ var NodeHelper = Class.extend({
|
||||
*
|
||||
* argument app Express app - The Express app object.
|
||||
*/
|
||||
setExpressApp: function (app) {
|
||||
setExpressApp(app) {
|
||||
this.expressApp = app;
|
||||
|
||||
var publicPath = this.path + "/public";
|
||||
app.use("/" + this.name, express.static(publicPath));
|
||||
app.use(`/${this.name}`, express.static(`${this.path}/public`));
|
||||
},
|
||||
|
||||
/* setSocketIO(io)
|
||||
@ -89,27 +88,25 @@ var NodeHelper = Class.extend({
|
||||
*
|
||||
* argument io Socket.io - The Socket io object.
|
||||
*/
|
||||
setSocketIO: function (io) {
|
||||
var self = this;
|
||||
self.io = io;
|
||||
setSocketIO(io) {
|
||||
this.io = io;
|
||||
|
||||
Log.log("Connecting socket for: " + this.name);
|
||||
var namespace = this.name;
|
||||
io.of(namespace).on("connection", function (socket) {
|
||||
Log.log(`Connecting socket for: ${this.name}`);
|
||||
|
||||
io.of(this.name).on("connection", (socket) => {
|
||||
// add a catch all event.
|
||||
var onevent = socket.onevent;
|
||||
const onevent = socket.onevent;
|
||||
socket.onevent = function (packet) {
|
||||
var args = packet.data || [];
|
||||
const args = packet.data || [];
|
||||
onevent.call(this, packet); // original call
|
||||
packet.data = ["*"].concat(args);
|
||||
onevent.call(this, packet); // additional call to catch-all
|
||||
};
|
||||
|
||||
// register catch all.
|
||||
socket.on("*", function (notification, payload) {
|
||||
socket.on("*", (notification, payload) => {
|
||||
if (notification !== "*") {
|
||||
//Log.log('received message in namespace: ' + namespace);
|
||||
self.socketNotificationReceived(notification, payload);
|
||||
this.socketNotificationReceived(notification, payload);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -120,7 +117,4 @@ NodeHelper.create = function (moduleDefinition) {
|
||||
return NodeHelper.extend(moduleDefinition);
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = NodeHelper;
|
||||
}
|
||||
module.exports = NodeHelper;
|
||||
|
61
js/server.js
61
js/server.js
@ -4,25 +4,29 @@
|
||||
* By Michael Teeuw https://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*/
|
||||
var express = require("express");
|
||||
var app = require("express")();
|
||||
var path = require("path");
|
||||
var ipfilter = require("express-ipfilter").IpFilter;
|
||||
var fs = require("fs");
|
||||
var helmet = require("helmet");
|
||||
const express = require("express");
|
||||
const app = require("express")();
|
||||
const path = require("path");
|
||||
const ipfilter = require("express-ipfilter").IpFilter;
|
||||
const fs = require("fs");
|
||||
const helmet = require("helmet");
|
||||
|
||||
var Log = require("./logger.js");
|
||||
var Utils = require("./utils.js");
|
||||
const Log = require("logger");
|
||||
const Utils = require("./utils.js");
|
||||
|
||||
var Server = function (config, callback) {
|
||||
var port = config.port;
|
||||
if (process.env.MM_PORT) {
|
||||
port = process.env.MM_PORT;
|
||||
}
|
||||
/**
|
||||
* Server
|
||||
*
|
||||
* @param {object} config The MM config
|
||||
* @param {Function} callback Function called when done.
|
||||
* @class
|
||||
*/
|
||||
function Server(config, callback) {
|
||||
const port = process.env.MM_PORT || config.port;
|
||||
|
||||
var server = null;
|
||||
let server = null;
|
||||
if (config.useHttps) {
|
||||
var options = {
|
||||
const options = {
|
||||
key: fs.readFileSync(config.httpsPrivateKey),
|
||||
cert: fs.readFileSync(config.httpsCertificate)
|
||||
};
|
||||
@ -30,18 +34,24 @@ var Server = function (config, callback) {
|
||||
} else {
|
||||
server = require("http").Server(app);
|
||||
}
|
||||
var io = require("socket.io")(server);
|
||||
const io = require("socket.io")(server, {
|
||||
cors: {
|
||||
origin: /.*$/,
|
||||
credentials: true
|
||||
},
|
||||
allowEIO3: true
|
||||
});
|
||||
|
||||
Log.log("Starting server on port " + port + " ... ");
|
||||
Log.log(`Starting server on port ${port} ... `);
|
||||
|
||||
server.listen(port, config.address ? config.address : "localhost");
|
||||
server.listen(port, config.address || "localhost");
|
||||
|
||||
if (config.ipWhitelist instanceof Array && config.ipWhitelist.length === 0) {
|
||||
Log.warn(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs"));
|
||||
}
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
var result = ipfilter(config.ipWhitelist, { mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false })(req, res, function (err) {
|
||||
ipfilter(config.ipWhitelist, { mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false })(req, res, function (err) {
|
||||
if (err === undefined) {
|
||||
return next();
|
||||
}
|
||||
@ -52,10 +62,9 @@ var Server = function (config, callback) {
|
||||
app.use(helmet({ contentSecurityPolicy: false }));
|
||||
|
||||
app.use("/js", express.static(__dirname));
|
||||
var directories = ["/config", "/css", "/fonts", "/modules", "/vendor", "/translations", "/tests/configs"];
|
||||
var directory;
|
||||
for (var i in directories) {
|
||||
directory = directories[i];
|
||||
|
||||
const directories = ["/config", "/css", "/fonts", "/modules", "/vendor", "/translations", "/tests/configs"];
|
||||
for (const directory of directories) {
|
||||
app.use(directory, express.static(path.resolve(global.root_path + directory)));
|
||||
}
|
||||
|
||||
@ -68,10 +77,10 @@ var Server = function (config, callback) {
|
||||
});
|
||||
|
||||
app.get("/", function (req, res) {
|
||||
var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), { encoding: "utf8" });
|
||||
let html = fs.readFileSync(path.resolve(`${global.root_path}/index.html`), { encoding: "utf8" });
|
||||
html = html.replace("#VERSION#", global.version);
|
||||
|
||||
var configFile = "config/config.js";
|
||||
let configFile = "config/config.js";
|
||||
if (typeof global.configuration_file !== "undefined") {
|
||||
configFile = global.configuration_file;
|
||||
}
|
||||
@ -83,6 +92,6 @@ var Server = function (config, callback) {
|
||||
if (typeof callback === "function") {
|
||||
callback(app, io);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Server;
|
||||
|
@ -103,26 +103,19 @@ var Translator = (function () {
|
||||
* @param {boolean} isFallback Flag to indicate fallback translations.
|
||||
* @param {Function} callback Function called when done.
|
||||
*/
|
||||
load: function (module, file, isFallback, callback) {
|
||||
if (!isFallback) {
|
||||
Log.log(module.name + " - Load translation: " + file);
|
||||
} else {
|
||||
Log.log(module.name + " - Load translation fallback: " + file);
|
||||
load(module, file, isFallback, callback) {
|
||||
Log.log(`${module.name} - Load translation${isFallback && " fallback"}: ${file}`);
|
||||
|
||||
if (this.translationsFallback[module.name]) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
if (!this.translationsFallback[module.name]) {
|
||||
loadJSON(module.file(file), function (json) {
|
||||
if (!isFallback) {
|
||||
self.translations[module.name] = json;
|
||||
} else {
|
||||
self.translationsFallback[module.name] = json;
|
||||
}
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
loadJSON(module.file(file), (json) => {
|
||||
const property = isFallback ? "translationsFallback" : "translations";
|
||||
this[property][module.name] = json;
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -4,9 +4,9 @@
|
||||
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
|
||||
* MIT Licensed.
|
||||
*/
|
||||
var colors = require("colors/safe");
|
||||
const colors = require("colors/safe");
|
||||
|
||||
var Utils = {
|
||||
module.exports = {
|
||||
colors: {
|
||||
warn: colors.yellow,
|
||||
error: colors.red,
|
||||
@ -14,7 +14,3 @@ var Utils = {
|
||||
pass: colors.green
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = Utils;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ Module.register("calendar", {
|
||||
fadePoint: 0.25, // Start on 1/4th of the list.
|
||||
hidePrivate: false,
|
||||
hideOngoing: false,
|
||||
hideTime: false,
|
||||
colored: false,
|
||||
coloredSymbolOnly: false,
|
||||
customEvents: [], // Array of {keyword: "", symbol: "", color: ""} where Keyword is a regexp and symbol/color are to be applied for matched
|
||||
@ -57,7 +58,8 @@ Module.register("calendar", {
|
||||
excludedEvents: [],
|
||||
sliceMultiDayEvents: false,
|
||||
broadcastPastEvents: false,
|
||||
nextDaysRelative: false
|
||||
nextDaysRelative: false,
|
||||
selfSignedCert: false
|
||||
},
|
||||
|
||||
requiresVersion: "2.1.0",
|
||||
@ -100,7 +102,8 @@ Module.register("calendar", {
|
||||
var calendarConfig = {
|
||||
maximumEntries: calendar.maximumEntries,
|
||||
maximumNumberOfDays: calendar.maximumNumberOfDays,
|
||||
broadcastPastEvents: calendar.broadcastPastEvents
|
||||
broadcastPastEvents: calendar.broadcastPastEvents,
|
||||
selfSignedCert: calendar.selfSignedCert
|
||||
};
|
||||
if (calendar.symbolClass === "undefined" || calendar.symbolClass === null) {
|
||||
calendarConfig.symbolClass = "";
|
||||
@ -277,8 +280,11 @@ Module.register("calendar", {
|
||||
if (typeof this.config.customEvents[ev].color !== "undefined" && this.config.customEvents[ev].color !== "") {
|
||||
needle = new RegExp(this.config.customEvents[ev].keyword, "gi");
|
||||
if (needle.test(event.title)) {
|
||||
eventWrapper.style.cssText = "color:" + this.config.customEvents[ev].color;
|
||||
titleWrapper.style.cssText = "color:" + this.config.customEvents[ev].color;
|
||||
// Respect parameter ColoredSymbolOnly also for custom events
|
||||
if (!this.config.coloredSymbolOnly) {
|
||||
eventWrapper.style.cssText = "color:" + this.config.customEvents[ev].color;
|
||||
titleWrapper.style.cssText = "color:" + this.config.customEvents[ev].color;
|
||||
}
|
||||
if (this.config.displaySymbol) {
|
||||
symbolWrapper.style.cssText = "color:" + this.config.customEvents[ev].color;
|
||||
}
|
||||
@ -363,7 +369,17 @@ Module.register("calendar", {
|
||||
// Show relative times
|
||||
if (event.startDate >= now) {
|
||||
// Use relative time
|
||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar());
|
||||
if (!this.config.hideTime) {
|
||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar());
|
||||
} else {
|
||||
timeWrapper.innerHTML = this.capFirst(
|
||||
moment(event.startDate, "x").calendar(null, {
|
||||
sameDay: "[" + this.translate("TODAY") + "]",
|
||||
nextDay: "[" + this.translate("TOMORROW") + "]",
|
||||
nextWeek: "dddd"
|
||||
})
|
||||
);
|
||||
}
|
||||
if (event.startDate - now < this.config.getRelative * oneHour) {
|
||||
// If event is within getRelative hours, display 'in xxx' time format or moment.fromNow()
|
||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
|
||||
@ -592,7 +608,8 @@ Module.register("calendar", {
|
||||
titleClass: calendarConfig.titleClass,
|
||||
timeClass: calendarConfig.timeClass,
|
||||
auth: auth,
|
||||
broadcastPastEvents: calendarConfig.broadcastPastEvents || this.config.broadcastPastEvents
|
||||
broadcastPastEvents: calendarConfig.broadcastPastEvents || this.config.broadcastPastEvents,
|
||||
selfSignedCert: calendarConfig.selfSignedCert || this.config.selfSignedCert
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* By Michael Teeuw https://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*/
|
||||
const Log = require("../../../js/logger.js");
|
||||
const Log = require("logger");
|
||||
const ical = require("node-ical");
|
||||
const request = require("request");
|
||||
|
||||
@ -25,9 +25,10 @@ const moment = require("moment");
|
||||
* @param {number} maximumNumberOfDays The maximum number of days an event should be in the future.
|
||||
* @param {object} auth The object containing options for authentication against the calendar.
|
||||
* @param {boolean} includePastEvents If true events from the past maximumNumberOfDays will be fetched too
|
||||
* @param {boolean} selfSignedCert If true, the server certificate is not verified against the list of supplied CAs.
|
||||
* @class
|
||||
*/
|
||||
const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, includePastEvents) {
|
||||
const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, includePastEvents, selfSignedCert) {
|
||||
const self = this;
|
||||
|
||||
let reloadTimer = null;
|
||||
@ -51,6 +52,13 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
|
||||
gzip: true
|
||||
};
|
||||
|
||||
if (selfSignedCert) {
|
||||
var agentOptions = {
|
||||
rejectUnauthorized: false
|
||||
};
|
||||
opts.agentOptions = agentOptions;
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
if (auth.method === "bearer") {
|
||||
opts.auth = {
|
||||
|
@ -7,7 +7,7 @@
|
||||
const NodeHelper = require("node_helper");
|
||||
const validUrl = require("valid-url");
|
||||
const CalendarFetcher = require("./calendarfetcher.js");
|
||||
const Log = require("../../../js/logger");
|
||||
const Log = require("logger");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
// Override start method.
|
||||
@ -19,7 +19,7 @@ module.exports = NodeHelper.create({
|
||||
// Override socketNotificationReceived method.
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
if (notification === "ADD_CALENDAR") {
|
||||
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.id);
|
||||
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.selfSignedCert, payload.id);
|
||||
}
|
||||
},
|
||||
|
||||
@ -34,9 +34,10 @@ module.exports = NodeHelper.create({
|
||||
* @param {number} maximumNumberOfDays The maximum number of days an event should be in the future.
|
||||
* @param {object} auth The object containing options for authentication against the calendar.
|
||||
* @param {boolean} broadcastPastEvents If true events from the past maximumNumberOfDays will be included in event broadcasts
|
||||
* @param {boolean} selfSignedCert If true, the server certificate is not verified against the list of supplied CAs.
|
||||
* @param {string} identifier ID of the module
|
||||
*/
|
||||
createFetcher: function (url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, identifier) {
|
||||
createFetcher: function (url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, selfSignedCert, identifier) {
|
||||
var self = this;
|
||||
|
||||
if (!validUrl.isUri(url)) {
|
||||
@ -47,7 +48,7 @@ module.exports = NodeHelper.create({
|
||||
var fetcher;
|
||||
if (typeof self.fetchers[identifier + url] === "undefined") {
|
||||
Log.log("Create new calendar fetcher for url: " + url + " - Interval: " + fetchInterval);
|
||||
fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents);
|
||||
fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, selfSignedCert);
|
||||
|
||||
fetcher.onReceive(function (fetcher) {
|
||||
self.sendSocketNotification("CALENDAR_EVENTS", {
|
||||
|
@ -182,34 +182,14 @@ Module.register("compliments", {
|
||||
},
|
||||
|
||||
// From data currentweather set weather type
|
||||
setCurrentWeatherType: function (data) {
|
||||
var weatherIconTable = {
|
||||
"01d": "day_sunny",
|
||||
"02d": "day_cloudy",
|
||||
"03d": "cloudy",
|
||||
"04d": "cloudy_windy",
|
||||
"09d": "showers",
|
||||
"10d": "rain",
|
||||
"11d": "thunderstorm",
|
||||
"13d": "snow",
|
||||
"50d": "fog",
|
||||
"01n": "night_clear",
|
||||
"02n": "night_cloudy",
|
||||
"03n": "night_cloudy",
|
||||
"04n": "night_cloudy",
|
||||
"09n": "night_showers",
|
||||
"10n": "night_rain",
|
||||
"11n": "night_thunderstorm",
|
||||
"13n": "night_snow",
|
||||
"50n": "night_alt_cloudy_windy"
|
||||
};
|
||||
this.currentWeatherType = weatherIconTable[data.weather[0].icon];
|
||||
setCurrentWeatherType: function (type) {
|
||||
this.currentWeatherType = type;
|
||||
},
|
||||
|
||||
// Override notification handler.
|
||||
notificationReceived: function (notification, payload, sender) {
|
||||
if (notification === "CURRENTWEATHER_DATA") {
|
||||
this.setCurrentWeatherType(payload.data);
|
||||
if (notification === "CURRENTWEATHER_TYPE") {
|
||||
this.setCurrentWeatherType(payload.type);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Module: Current Weather
|
||||
|
||||
> :warning: **This module is deprecated in favor of the [weather](https://docs.magicmirror.builders/modules/weather.html) module.**
|
||||
|
||||
The `currentweather` module is one of the default modules of the MagicMirror.
|
||||
This module displays the current weather, including the windspeed, the sunset or sunrise time, the temperature and an icon to display the current conditions.
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
*
|
||||
* By Michael Teeuw https://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*
|
||||
* This module is deprecated. Any additional feature will no longer be merged.
|
||||
*/
|
||||
Module.register("currentweather", {
|
||||
// Default module config.
|
||||
@ -47,24 +49,24 @@ Module.register("currentweather", {
|
||||
roundTemp: false,
|
||||
|
||||
iconTable: {
|
||||
"01d": "wi-day-sunny",
|
||||
"02d": "wi-day-cloudy",
|
||||
"03d": "wi-cloudy",
|
||||
"04d": "wi-cloudy-windy",
|
||||
"09d": "wi-showers",
|
||||
"10d": "wi-rain",
|
||||
"11d": "wi-thunderstorm",
|
||||
"13d": "wi-snow",
|
||||
"50d": "wi-fog",
|
||||
"01n": "wi-night-clear",
|
||||
"02n": "wi-night-cloudy",
|
||||
"03n": "wi-night-cloudy",
|
||||
"04n": "wi-night-cloudy",
|
||||
"09n": "wi-night-showers",
|
||||
"10n": "wi-night-rain",
|
||||
"11n": "wi-night-thunderstorm",
|
||||
"13n": "wi-night-snow",
|
||||
"50n": "wi-night-alt-cloudy-windy"
|
||||
"01d": "day-sunny",
|
||||
"02d": "day-cloudy",
|
||||
"03d": "cloudy",
|
||||
"04d": "cloudy-windy",
|
||||
"09d": "showers",
|
||||
"10d": "rain",
|
||||
"11d": "thunderstorm",
|
||||
"13d": "snow",
|
||||
"50d": "fog",
|
||||
"01n": "night-clear",
|
||||
"02n": "night-cloudy",
|
||||
"03n": "night-cloudy",
|
||||
"04n": "night-cloudy",
|
||||
"09n": "night-showers",
|
||||
"10n": "night-rain",
|
||||
"11n": "night-thunderstorm",
|
||||
"13n": "night-snow",
|
||||
"50n": "night-alt-cloudy-windy"
|
||||
}
|
||||
},
|
||||
|
||||
@ -219,7 +221,7 @@ Module.register("currentweather", {
|
||||
|
||||
if (this.config.hideTemp === false) {
|
||||
var weatherIcon = document.createElement("span");
|
||||
weatherIcon.className = "wi weathericon " + this.weatherType;
|
||||
weatherIcon.className = "wi weathericon wi-" + this.weatherType;
|
||||
large.appendChild(weatherIcon);
|
||||
|
||||
var temperature = document.createElement("span");
|
||||
@ -258,13 +260,9 @@ Module.register("currentweather", {
|
||||
|
||||
var feelsLike = document.createElement("span");
|
||||
feelsLike.className = "dimmed";
|
||||
var feelsLikeHtml = this.translate("FEELS");
|
||||
if (feelsLikeHtml.indexOf("{DEGREE}") > -1) {
|
||||
feelsLikeHtml = this.translate("FEELS", {
|
||||
DEGREE: this.feelsLike + degreeLabel
|
||||
});
|
||||
} else feelsLikeHtml += " " + this.feelsLike + degreeLabel;
|
||||
feelsLike.innerHTML = feelsLikeHtml;
|
||||
feelsLike.innerHTML = this.translate("FEELS", {
|
||||
DEGREE: this.feelsLike + degreeLabel
|
||||
});
|
||||
small.appendChild(feelsLike);
|
||||
|
||||
wrapper.appendChild(small);
|
||||
@ -506,6 +504,7 @@ Module.register("currentweather", {
|
||||
this.loaded = true;
|
||||
this.updateDom(this.config.animationSpeed);
|
||||
this.sendNotification("CURRENTWEATHER_DATA", { data: data });
|
||||
this.sendNotification("CURRENTWEATHER_TYPE", { type: this.config.iconTable[data.weather[0].icon].replace("-", "_") });
|
||||
},
|
||||
|
||||
/* scheduleUpdate()
|
||||
@ -593,6 +592,7 @@ Module.register("currentweather", {
|
||||
*/
|
||||
roundValue: function (temperature) {
|
||||
var decimals = this.config.roundTemp ? 0 : 1;
|
||||
return parseFloat(temperature).toFixed(decimals);
|
||||
var roundValue = parseFloat(temperature).toFixed(decimals);
|
||||
return roundValue === "-0" ? 0 : roundValue;
|
||||
}
|
||||
});
|
||||
|
9
modules/default/currentweather/node_helper.js
Normal file
9
modules/default/currentweather/node_helper.js
Normal file
@ -0,0 +1,9 @@
|
||||
const NodeHelper = require("node_helper");
|
||||
const Log = require("logger");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
// Override start method.
|
||||
start: function () {
|
||||
Log.warn(`The module '${this.name}' is deprecated in favor of the 'weather'-module, please refer to the documentation for a migration path`);
|
||||
}
|
||||
});
|
3
modules/default/newsfeed/fullarticle.njk
Normal file
3
modules/default/newsfeed/fullarticle.njk
Normal file
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<iframe class="newsfeed-fullarticle" src="{{ url }}"></iframe>
|
||||
</div>
|
14
modules/default/newsfeed/newsfeed.css
Normal file
14
modules/default/newsfeed/newsfeed.css
Normal file
@ -0,0 +1,14 @@
|
||||
iframe.newsfeed-fullarticle {
|
||||
width: 100vw;
|
||||
/* very large height value to allow scrolling */
|
||||
height: 3000px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.region.bottom.bar.newsfeed-fullarticle {
|
||||
bottom: inherit;
|
||||
top: -90px;
|
||||
}
|
@ -44,6 +44,11 @@ Module.register("newsfeed", {
|
||||
return ["moment.js"];
|
||||
},
|
||||
|
||||
//Define required styles.
|
||||
getStyles: function () {
|
||||
return ["newsfeed.css"];
|
||||
},
|
||||
|
||||
// Define required translations.
|
||||
getTranslations: function () {
|
||||
// The translations for the default modules are defined in the core translation files.
|
||||
@ -75,6 +80,9 @@ Module.register("newsfeed", {
|
||||
this.generateFeed(payload);
|
||||
|
||||
if (!this.loaded) {
|
||||
if (this.config.hideLoading) {
|
||||
this.show();
|
||||
}
|
||||
this.scheduleUpdateInterval();
|
||||
}
|
||||
|
||||
@ -82,123 +90,43 @@ Module.register("newsfeed", {
|
||||
}
|
||||
},
|
||||
|
||||
// Override dom generator.
|
||||
getDom: function () {
|
||||
const wrapper = document.createElement("div");
|
||||
|
||||
//Override fetching of template name
|
||||
getTemplate: function () {
|
||||
if (this.config.feedUrl) {
|
||||
wrapper.className = "small bright";
|
||||
wrapper.innerHTML = this.translate("MODULE_CONFIG_CHANGED", { MODULE_NAME: "Newsfeed" });
|
||||
return wrapper;
|
||||
return "oldconfig.njk";
|
||||
} else if (this.config.showFullArticle) {
|
||||
return "fullarticle.njk";
|
||||
}
|
||||
return "newsfeed.njk";
|
||||
},
|
||||
|
||||
//Override template data and return whats used for the current template
|
||||
getTemplateData: function () {
|
||||
// this.config.showFullArticle is a run-time configuration, triggered by optional notifications
|
||||
if (this.config.showFullArticle) {
|
||||
return {
|
||||
url: this.getActiveItemURL()
|
||||
};
|
||||
}
|
||||
if (this.newsItems.length === 0) {
|
||||
return {
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
if (this.activeItem >= this.newsItems.length) {
|
||||
this.activeItem = 0;
|
||||
}
|
||||
const item = this.newsItems[this.activeItem];
|
||||
|
||||
if (this.newsItems.length > 0) {
|
||||
// this.config.showFullArticle is a run-time configuration, triggered by optional notifications
|
||||
if (!this.config.showFullArticle && (this.config.showSourceTitle || this.config.showPublishDate)) {
|
||||
const sourceAndTimestamp = document.createElement("div");
|
||||
sourceAndTimestamp.className = "newsfeed-source light small dimmed";
|
||||
|
||||
if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "") {
|
||||
sourceAndTimestamp.innerHTML = this.newsItems[this.activeItem].sourceTitle;
|
||||
}
|
||||
if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "" && this.config.showPublishDate) {
|
||||
sourceAndTimestamp.innerHTML += ", ";
|
||||
}
|
||||
if (this.config.showPublishDate) {
|
||||
sourceAndTimestamp.innerHTML += moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow();
|
||||
}
|
||||
if ((this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "") || this.config.showPublishDate) {
|
||||
sourceAndTimestamp.innerHTML += ":";
|
||||
}
|
||||
|
||||
wrapper.appendChild(sourceAndTimestamp);
|
||||
}
|
||||
|
||||
//Remove selected tags from the beginning of rss feed items (title or description)
|
||||
|
||||
if (this.config.removeStartTags === "title" || this.config.removeStartTags === "both") {
|
||||
for (let f = 0; f < this.config.startTags.length; f++) {
|
||||
if (this.newsItems[this.activeItem].title.slice(0, this.config.startTags[f].length) === this.config.startTags[f]) {
|
||||
this.newsItems[this.activeItem].title = this.newsItems[this.activeItem].title.slice(this.config.startTags[f].length, this.newsItems[this.activeItem].title.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.config.removeStartTags === "description" || this.config.removeStartTags === "both") {
|
||||
if (this.isShowingDescription) {
|
||||
for (let f = 0; f < this.config.startTags.length; f++) {
|
||||
if (this.newsItems[this.activeItem].description.slice(0, this.config.startTags[f].length) === this.config.startTags[f]) {
|
||||
this.newsItems[this.activeItem].description = this.newsItems[this.activeItem].description.slice(this.config.startTags[f].length, this.newsItems[this.activeItem].description.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove selected tags from the end of rss feed items (title or description)
|
||||
|
||||
if (this.config.removeEndTags) {
|
||||
for (let f = 0; f < this.config.endTags.length; f++) {
|
||||
if (this.newsItems[this.activeItem].title.slice(-this.config.endTags[f].length) === this.config.endTags[f]) {
|
||||
this.newsItems[this.activeItem].title = this.newsItems[this.activeItem].title.slice(0, -this.config.endTags[f].length);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isShowingDescription) {
|
||||
for (let f = 0; f < this.config.endTags.length; f++) {
|
||||
if (this.newsItems[this.activeItem].description.slice(-this.config.endTags[f].length) === this.config.endTags[f]) {
|
||||
this.newsItems[this.activeItem].description = this.newsItems[this.activeItem].description.slice(0, -this.config.endTags[f].length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.config.showFullArticle) {
|
||||
const title = document.createElement("div");
|
||||
title.className = "newsfeed-title bright medium light" + (!this.config.wrapTitle ? " no-wrap" : "");
|
||||
title.innerHTML = this.newsItems[this.activeItem].title;
|
||||
wrapper.appendChild(title);
|
||||
}
|
||||
|
||||
if (this.isShowingDescription) {
|
||||
const description = document.createElement("div");
|
||||
description.className = "newsfeed-desc small light" + (!this.config.wrapDescription ? " no-wrap" : "");
|
||||
const txtDesc = this.newsItems[this.activeItem].description;
|
||||
description.innerHTML = this.config.truncDescription ? (txtDesc.length > this.config.lengthDescription ? txtDesc.substring(0, this.config.lengthDescription) + "..." : txtDesc) : txtDesc;
|
||||
wrapper.appendChild(description);
|
||||
}
|
||||
|
||||
if (this.config.showFullArticle) {
|
||||
const fullArticle = document.createElement("iframe");
|
||||
fullArticle.className = "";
|
||||
fullArticle.style.width = "100vw";
|
||||
// very large height value to allow scrolling
|
||||
fullArticle.height = "3000";
|
||||
fullArticle.style.height = "3000";
|
||||
fullArticle.style.top = "0";
|
||||
fullArticle.style.left = "0";
|
||||
fullArticle.style.border = "none";
|
||||
fullArticle.src = this.getActiveItemURL();
|
||||
fullArticle.style.zIndex = 1;
|
||||
wrapper.appendChild(fullArticle);
|
||||
}
|
||||
|
||||
if (this.config.hideLoading) {
|
||||
this.show();
|
||||
}
|
||||
} else {
|
||||
if (this.config.hideLoading) {
|
||||
this.hide();
|
||||
} else {
|
||||
wrapper.innerHTML = this.translate("LOADING");
|
||||
wrapper.className = "small dimmed";
|
||||
}
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
return {
|
||||
loaded: true,
|
||||
config: this.config,
|
||||
sourceTitle: item.sourceTitle,
|
||||
publishDate: moment(new Date(item.pubdate)).fromNow(),
|
||||
title: item.title,
|
||||
description: item.description
|
||||
};
|
||||
},
|
||||
|
||||
getActiveItemURL: function () {
|
||||
@ -257,6 +185,45 @@ Module.register("newsfeed", {
|
||||
}, this);
|
||||
}
|
||||
|
||||
newsItems.forEach((item) => {
|
||||
//Remove selected tags from the beginning of rss feed items (title or description)
|
||||
if (this.config.removeStartTags === "title" || this.config.removeStartTags === "both") {
|
||||
for (let f = 0; f < this.config.startTags.length; f++) {
|
||||
if (item.title.slice(0, this.config.startTags[f].length) === this.config.startTags[f]) {
|
||||
item.title = item.title.slice(this.config.startTags[f].length, item.title.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.config.removeStartTags === "description" || this.config.removeStartTags === "both") {
|
||||
if (this.isShowingDescription) {
|
||||
for (let f = 0; f < this.config.startTags.length; f++) {
|
||||
if (item.description.slice(0, this.config.startTags[f].length) === this.config.startTags[f]) {
|
||||
item.description = item.description.slice(this.config.startTags[f].length, item.description.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove selected tags from the end of rss feed items (title or description)
|
||||
|
||||
if (this.config.removeEndTags) {
|
||||
for (let f = 0; f < this.config.endTags.length; f++) {
|
||||
if (item.title.slice(-this.config.endTags[f].length) === this.config.endTags[f]) {
|
||||
item.title = item.title.slice(0, -this.config.endTags[f].length);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isShowingDescription) {
|
||||
for (let f = 0; f < this.config.endTags.length; f++) {
|
||||
if (item.description.slice(-this.config.endTags[f].length) === this.config.endTags[f]) {
|
||||
item.description = item.description.slice(0, -this.config.endTags[f].length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// get updated news items and broadcast them
|
||||
var updatedItems = [];
|
||||
newsItems.forEach((value) => {
|
||||
@ -335,8 +302,7 @@ Module.register("newsfeed", {
|
||||
this.config.showFullArticle = false;
|
||||
this.scrollPosition = 0;
|
||||
// reset bottom bar alignment
|
||||
document.getElementsByClassName("region bottom bar")[0].style.bottom = "0";
|
||||
document.getElementsByClassName("region bottom bar")[0].style.top = "inherit";
|
||||
document.getElementsByClassName("region bottom bar")[0].classList.remove("newsfeed-fullarticle");
|
||||
if (!this.timer) {
|
||||
this.scheduleUpdateInterval();
|
||||
}
|
||||
@ -344,7 +310,9 @@ Module.register("newsfeed", {
|
||||
|
||||
notificationReceived: function (notification, payload, sender) {
|
||||
const before = this.activeItem;
|
||||
if (notification === "ARTICLE_NEXT") {
|
||||
if (notification === "MODULE_DOM_CREATED" && this.config.hideLoading) {
|
||||
this.hide();
|
||||
} else if (notification === "ARTICLE_NEXT") {
|
||||
this.activeItem++;
|
||||
if (this.activeItem >= this.newsItems.length) {
|
||||
this.activeItem = 0;
|
||||
@ -406,8 +374,7 @@ Module.register("newsfeed", {
|
||||
this.config.showFullArticle = !this.isShowingDescription;
|
||||
// make bottom bar align to top to allow scrolling
|
||||
if (this.config.showFullArticle === true) {
|
||||
document.getElementsByClassName("region bottom bar")[0].style.bottom = "inherit";
|
||||
document.getElementsByClassName("region bottom bar")[0].style.top = "-90px";
|
||||
document.getElementsByClassName("region bottom bar")[0].classList.add("newsfeed-fullarticle");
|
||||
}
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
|
28
modules/default/newsfeed/newsfeed.njk
Normal file
28
modules/default/newsfeed/newsfeed.njk
Normal file
@ -0,0 +1,28 @@
|
||||
{% if loaded %}
|
||||
<div>
|
||||
{% if (config.showSourceTitle and sourceTitle) or config.showPublishDate %}
|
||||
<div class="newsfeed-source light small dimmed">
|
||||
{% if sourceTitle and config.showSourceTitle %}
|
||||
{{ sourceTitle }}{% if config.showPublishDate %}, {% else %}: {% endif %}
|
||||
{% endif %}
|
||||
{% if config.showPublishDate %}
|
||||
{{ publishDate }}:
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="newsfeed-title bright medium light{{ ' no-wrap' if config.wrapTitle }}">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="newsfeed-desc small light{{ ' no-wrap' if config.wrapDescription }}">
|
||||
{% if config.truncDescription %}
|
||||
{{ description | truncate(config.lengthDescription) }}
|
||||
{% else %}
|
||||
{{ description }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="small dimmed">
|
||||
{{ "LOADING" | translate | safe }}
|
||||
</div>
|
||||
{% endif %}
|
@ -4,7 +4,7 @@
|
||||
* By Michael Teeuw https://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*/
|
||||
const Log = require("../../../js/logger.js");
|
||||
const Log = require("logger");
|
||||
const FeedMe = require("feedme");
|
||||
const request = require("request");
|
||||
const iconv = require("iconv-lite");
|
||||
|
@ -8,7 +8,7 @@
|
||||
const NodeHelper = require("node_helper");
|
||||
const validUrl = require("valid-url");
|
||||
const NewsfeedFetcher = require("./newsfeedfetcher.js");
|
||||
const Log = require("../../../js/logger");
|
||||
const Log = require("logger");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
// Override start method.
|
||||
|
3
modules/default/newsfeed/oldconfig.njk
Normal file
3
modules/default/newsfeed/oldconfig.njk
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="small bright">
|
||||
{{ "MODULE_CONFIG_CHANGED" | translate({MODULE_NAME: "Newsfeed"}) | safe }}
|
||||
</div>
|
@ -3,7 +3,7 @@ const simpleGits = [];
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const defaultModules = require(__dirname + "/../defaultmodules.js");
|
||||
const Log = require(__dirname + "/../../../js/logger.js");
|
||||
const Log = require("logger");
|
||||
const NodeHelper = require("node_helper");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
|
@ -1,7 +1,4 @@
|
||||
{% if current or weatherData %}
|
||||
{% if weatherData %}
|
||||
{% set current = weatherData.current %}
|
||||
{% endif %}
|
||||
{% if current %}
|
||||
{% if not config.onlyTemp %}
|
||||
<div class="normal medium">
|
||||
<span class="wi wi-strong-wind dimmed"></span>
|
||||
@ -66,13 +63,10 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if (config.showFeelsLike or config.showPrecipitationAmount) and not config.onlyTemp %}
|
||||
<div class="normal medium">
|
||||
<div class="normal medium feelslike">
|
||||
{% if config.showFeelsLike %}
|
||||
<span class="dimmed">
|
||||
{{ "FEELS" | translate({DEGREE: current.feelsLike() | roundValue | unit("temperature") | decimalSymbol }) }}
|
||||
{% if not config.feelsLikeWithDegree %}
|
||||
{{ current.feelsLike() | roundValue | unit("temperature") | decimalSymbol }}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if config.showPrecipitationAmount %}
|
||||
@ -84,7 +78,7 @@
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="dimmed light small">
|
||||
{{ "LOADING" | translate | safe }}
|
||||
{{ "LOADING" | translate }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
@ -1,10 +1,5 @@
|
||||
{% if forecast or weatherData %}
|
||||
{% if weatherData %}
|
||||
{% set forecast = weatherData.days %}
|
||||
{% set numSteps = forecast | calcNumEntries %}
|
||||
{% else %}
|
||||
{% set numSteps = forecast | calcNumSteps %}
|
||||
{% endif %}
|
||||
{% if forecast %}
|
||||
{% set numSteps = forecast | calcNumSteps %}
|
||||
{% set currentStep = 0 %}
|
||||
<table class="{{ config.tableClass }}">
|
||||
{% set forecast = forecast.slice(0, numSteps) %}
|
||||
@ -35,7 +30,7 @@
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="dimmed light small">
|
||||
{{ "LOADING" | translate | safe }}
|
||||
{{ "LOADING" | translate }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
{% if hourly or weatherData %}
|
||||
{% if weatherData %}
|
||||
{% set hourly = weatherData.hours %}
|
||||
{% endif %}
|
||||
{% if hourly %}
|
||||
{% set numSteps = hourly | calcNumEntries %}
|
||||
{% set currentStep = 0 %}
|
||||
<table class="{{ config.tableClass }}">
|
||||
@ -24,9 +21,9 @@
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="dimmed light small">
|
||||
{{ "LOADING" | translate | safe }}
|
||||
{{ "LOADING" | translate }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Uncomment the line below to see the contents of the `hourly` object. -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{weatherData | dump}}</div> -->
|
||||
<!-- <div style="word-wrap:break-word" class="xsmall dimmed">{{hourly | dump}}</div> -->
|
||||
|
@ -29,16 +29,23 @@ WeatherProvider.register("yourprovider", {
|
||||
|
||||
#### `fetchCurrentWeather()`
|
||||
|
||||
This method is called when the weather module tries to fetch the current weather of your provider. The implementation of this method is required.
|
||||
This method is called when the weather module tries to fetch the current weather of your provider. The implementation of this method is required for current weather support.
|
||||
The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise.
|
||||
After the response is processed, the current weather information (as a [WeatherObject](#weatherobject)) needs to be set with `this.setCurrentWeather(currentWeather);`.
|
||||
It will then automatically refresh the module DOM with the new data.
|
||||
|
||||
#### `fetchWeatherForecast()`
|
||||
|
||||
This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required.
|
||||
This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required for forecast support.
|
||||
The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise.
|
||||
After the response is processed, the weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setCurrentWeather(forecast);`.
|
||||
After the response is processed, the weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setWeatherForecast(forecast);`.
|
||||
It will then automatically refresh the module DOM with the new data.
|
||||
|
||||
#### `fetchWeatherHourly()`
|
||||
|
||||
This method is called when the weather module tries to fetch the weather of your provider. The implementation of this method is required for hourly support.
|
||||
The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise.
|
||||
After the response is processed, the hourly weather forecast information (as an array of [WeatherObject](#weatherobject)s) needs to be set with `this.setWeatherHourly(forecast);`.
|
||||
It will then automatically refresh the module DOM with the new data.
|
||||
|
||||
### Weather Provider instance methods
|
||||
@ -63,6 +70,10 @@ This returns a WeatherDay object for the current weather.
|
||||
|
||||
This returns an array of WeatherDay objects for the weather forecast.
|
||||
|
||||
#### `weatherHourly()`
|
||||
|
||||
This returns an array of WeatherDay objects for the hourly weather forecast.
|
||||
|
||||
#### `fetchedLocation()`
|
||||
|
||||
This returns the name of the fetched location or an empty string.
|
||||
@ -75,6 +86,10 @@ Set the currentWeather and notify the delegate that new information is available
|
||||
|
||||
Set the weatherForecastArray and notify the delegate that new information is available.
|
||||
|
||||
#### `setWeatherHourly(weatherHourlyArray)`
|
||||
|
||||
Set the weatherHourlyArray and notify the delegate that new information is available.
|
||||
|
||||
#### `setFetchedLocation(name)`
|
||||
|
||||
Set the fetched location name.
|
||||
|
@ -15,6 +15,15 @@ WeatherProvider.register("darksky", {
|
||||
// Not strictly required, but helps for debugging.
|
||||
providerName: "Dark Sky",
|
||||
|
||||
// Set the default config properties that is specific to this provider
|
||||
defaults: {
|
||||
apiBase: "https://cors-anywhere.herokuapp.com/https://api.darksky.net",
|
||||
weatherEndpoint: "/forecast",
|
||||
apiKey: "",
|
||||
lat: 0,
|
||||
lon: 0
|
||||
},
|
||||
|
||||
units: {
|
||||
imperial: "us",
|
||||
metric: "si"
|
||||
|
@ -14,6 +14,18 @@ WeatherProvider.register("openweathermap", {
|
||||
// But for debugging (and future alerts) it would be nice to have the real name.
|
||||
providerName: "OpenWeatherMap",
|
||||
|
||||
// Set the default config properties that is specific to this provider
|
||||
defaults: {
|
||||
apiVersion: "2.5",
|
||||
apiBase: "https://api.openweathermap.org/data/",
|
||||
weatherEndpoint: "",
|
||||
locationID: false,
|
||||
location: false,
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
apiKey: ""
|
||||
},
|
||||
|
||||
// Overwrite the fetchCurrentWeather method.
|
||||
fetchCurrentWeather() {
|
||||
this.fetchData(this.getUrl())
|
||||
@ -56,8 +68,8 @@ WeatherProvider.register("openweathermap", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
// Overwrite the fetchWeatherData method.
|
||||
fetchWeatherData() {
|
||||
// Overwrite the fetchWeatherHourly method.
|
||||
fetchWeatherHourly() {
|
||||
this.fetchData(this.getUrl())
|
||||
.then((data) => {
|
||||
if (!data) {
|
||||
@ -69,7 +81,7 @@ WeatherProvider.register("openweathermap", {
|
||||
this.setFetchedLocation(`(${data.lat},${data.lon})`);
|
||||
|
||||
const weatherData = this.generateWeatherObjectsFromOnecall(data);
|
||||
this.setWeatherData(weatherData);
|
||||
this.setWeatherHourly(weatherData.hours);
|
||||
})
|
||||
.catch(function (request) {
|
||||
Log.error("Could not load data ... ", request);
|
||||
@ -77,6 +89,31 @@ WeatherProvider.register("openweathermap", {
|
||||
.finally(() => this.updateAvailable());
|
||||
},
|
||||
|
||||
/**
|
||||
* Overrides method for setting config to check if endpoint is correct for hourly
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
setConfig(config) {
|
||||
this.config = config;
|
||||
if (!this.config.weatherEndpoint) {
|
||||
switch (this.config.type) {
|
||||
case "hourly":
|
||||
this.config.weatherEndpoint = "/onecall";
|
||||
break;
|
||||
case "daily":
|
||||
case "forecast":
|
||||
this.config.weatherEndpoint = "/forecast";
|
||||
break;
|
||||
case "current":
|
||||
this.config.weatherEndpoint = "/weather";
|
||||
break;
|
||||
default:
|
||||
Log.error("weatherEndpoint not configured and could not resolve it based on type");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** OpenWeatherMap Specific Methods - These are not part of the default provider methods */
|
||||
/*
|
||||
* Gets the complete url for the request
|
||||
|
@ -14,6 +14,13 @@
|
||||
WeatherProvider.register("smhi", {
|
||||
providerName: "SMHI",
|
||||
|
||||
// Set the default config properties that is specific to this provider
|
||||
defaults: {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
precipitationValue: "pmedian"
|
||||
},
|
||||
|
||||
/**
|
||||
* Implements method in interface for fetching current weather
|
||||
*/
|
||||
@ -55,7 +62,7 @@ WeatherProvider.register("smhi", {
|
||||
this.config = config;
|
||||
if (!config.precipitationValue || ["pmin", "pmean", "pmedian", "pmax"].indexOf(config.precipitationValue) == -1) {
|
||||
console.log("invalid or not set: " + config.precipitationValue);
|
||||
config.precipitationValue = "pmedian";
|
||||
config.precipitationValue = this.defaults.precipitationValue;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,6 +14,13 @@ WeatherProvider.register("ukmetoffice", {
|
||||
// But for debugging (and future alerts) it would be nice to have the real name.
|
||||
providerName: "UK Met Office",
|
||||
|
||||
// Set the default config properties that is specific to this provider
|
||||
defaults: {
|
||||
apiBase: "http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/",
|
||||
locationID: false,
|
||||
apiKey: ""
|
||||
},
|
||||
|
||||
units: {
|
||||
imperial: "us",
|
||||
metric: "si"
|
||||
|
@ -44,6 +44,16 @@ WeatherProvider.register("ukmetofficedatahub", {
|
||||
// Set the name of the provider.
|
||||
providerName: "UK Met Office (DataHub)",
|
||||
|
||||
// Set the default config properties that is specific to this provider
|
||||
defaults: {
|
||||
apiBase: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/",
|
||||
apiKey: "",
|
||||
apiSecret: "",
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
windUnits: "mph"
|
||||
},
|
||||
|
||||
// Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
|
||||
getUrl(forecastType) {
|
||||
let queryStrings = "?";
|
||||
|
@ -14,6 +14,15 @@ WeatherProvider.register("weatherbit", {
|
||||
// Not strictly required, but helps for debugging.
|
||||
providerName: "Weatherbit",
|
||||
|
||||
// Set the default config properties that is specific to this provider
|
||||
defaults: {
|
||||
apiBase: "https://api.weatherbit.io/v2.0",
|
||||
weatherEndpoint: "/current",
|
||||
apiKey: "",
|
||||
lat: 0,
|
||||
lon: 0
|
||||
},
|
||||
|
||||
units: {
|
||||
imperial: "I",
|
||||
metric: "M"
|
||||
|
@ -19,6 +19,14 @@ WeatherProvider.register("weathergov", {
|
||||
// But for debugging (and future alerts) it would be nice to have the real name.
|
||||
providerName: "Weather.gov",
|
||||
|
||||
// Set the default config properties that is specific to this provider
|
||||
defaults: {
|
||||
apiBase: "https://api.weatherbit.io/v2.0",
|
||||
weatherEndpoint: "/forecast",
|
||||
lat: 0,
|
||||
lon: 0
|
||||
},
|
||||
|
||||
// Flag all needed URLs availability
|
||||
configURLs: false,
|
||||
|
||||
|
@ -12,10 +12,6 @@ Module.register("weather", {
|
||||
weatherProvider: "openweathermap",
|
||||
roundTemp: false,
|
||||
type: "current", // current, forecast, daily (equivalent to forecast), hourly (only with OpenWeatherMap /onecall endpoint)
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
location: false,
|
||||
locationID: false,
|
||||
units: config.units,
|
||||
useKmh: false,
|
||||
tempUnits: config.units,
|
||||
@ -40,20 +36,13 @@ Module.register("weather", {
|
||||
fade: true,
|
||||
fadePoint: 0.25, // Start on 1/4th of the list.
|
||||
initialLoadDelay: 0, // 0 seconds delay
|
||||
retryDelay: 2500,
|
||||
apiKey: "",
|
||||
apiSecret: "",
|
||||
apiVersion: "2.5",
|
||||
apiBase: "https://api.openweathermap.org/data/", // TODO: this should not be part of the weather.js file, but should be contained in the openweatherprovider
|
||||
weatherEndpoint: "/weather",
|
||||
appendLocationNameToHeader: true,
|
||||
calendarClass: "calendar",
|
||||
tableClass: "small",
|
||||
onlyTemp: false,
|
||||
showPrecipitationAmount: false,
|
||||
colored: false,
|
||||
showFeelsLike: true,
|
||||
feelsLikeWithDegree: false
|
||||
showFeelsLike: true
|
||||
},
|
||||
|
||||
// Module properties.
|
||||
@ -89,8 +78,6 @@ Module.register("weather", {
|
||||
// Let the weather provider know we are starting.
|
||||
this.weatherProvider.start();
|
||||
|
||||
this.config.feelsLikeWithDegree = this.translate("FEELS").indexOf("{DEGREE}") > -1;
|
||||
|
||||
// Add custom filters
|
||||
this.addFilters();
|
||||
|
||||
@ -133,8 +120,9 @@ Module.register("weather", {
|
||||
case "daily":
|
||||
case "forecast":
|
||||
return `forecast.njk`;
|
||||
//Make the invalid values use the "Loading..." from forecast
|
||||
default:
|
||||
return `${this.config.type.toLowerCase()}.njk`;
|
||||
return `forecast.njk`;
|
||||
}
|
||||
},
|
||||
|
||||
@ -144,7 +132,7 @@ Module.register("weather", {
|
||||
config: this.config,
|
||||
current: this.weatherProvider.currentWeather(),
|
||||
forecast: this.weatherProvider.weatherForecast(),
|
||||
weatherData: this.weatherProvider.weatherData(),
|
||||
hourly: this.weatherProvider.weatherHourly(),
|
||||
indoor: {
|
||||
humidity: this.indoorHumidity,
|
||||
temperature: this.indoorTemperature
|
||||
@ -157,6 +145,10 @@ Module.register("weather", {
|
||||
Log.log("New weather information available.");
|
||||
this.updateDom(0);
|
||||
this.scheduleUpdate();
|
||||
|
||||
if (this.weatherProvider.currentWeather()) {
|
||||
this.sendNotification("CURRENTWEATHER_TYPE", { type: this.weatherProvider.currentWeather().weatherType.replace("-", "_") });
|
||||
}
|
||||
},
|
||||
|
||||
scheduleUpdate: function (delay = null) {
|
||||
@ -166,19 +158,27 @@ Module.register("weather", {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.config.weatherEndpoint === "/onecall") {
|
||||
this.weatherProvider.fetchWeatherData();
|
||||
} else if (this.config.type === "forecast") {
|
||||
this.weatherProvider.fetchWeatherForecast();
|
||||
} else {
|
||||
this.weatherProvider.fetchCurrentWeather();
|
||||
switch (this.config.type.toLowerCase()) {
|
||||
case "current":
|
||||
this.weatherProvider.fetchCurrentWeather();
|
||||
break;
|
||||
case "hourly":
|
||||
this.weatherProvider.fetchWeatherHourly();
|
||||
break;
|
||||
case "daily":
|
||||
case "forecast":
|
||||
this.weatherProvider.fetchWeatherForecast();
|
||||
break;
|
||||
default:
|
||||
Log.error(`Invalid type ${this.config.type} configured (must be one of 'current', 'hourly', 'daily' or 'forecast')`);
|
||||
}
|
||||
}, nextLoad);
|
||||
},
|
||||
|
||||
roundValue: function (temperature) {
|
||||
var decimals = this.config.roundTemp ? 0 : 1;
|
||||
return parseFloat(temperature).toFixed(decimals);
|
||||
var roundValue = parseFloat(temperature).toFixed(decimals);
|
||||
return roundValue === "-0" ? 0 : roundValue;
|
||||
},
|
||||
|
||||
addFilters() {
|
||||
|
@ -11,12 +11,13 @@
|
||||
var WeatherProvider = Class.extend({
|
||||
// Weather Provider Properties
|
||||
providerName: null,
|
||||
defaults: {},
|
||||
|
||||
// The following properties have accessor methods.
|
||||
// Try to not access them directly.
|
||||
currentWeatherObject: null,
|
||||
weatherForecastArray: null,
|
||||
weatherDataObject: null,
|
||||
weatherHourlyArray: null,
|
||||
fetchedLocationName: null,
|
||||
|
||||
// The following properties will be set automatically.
|
||||
@ -57,10 +58,10 @@ var WeatherProvider = Class.extend({
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherForecast method.`);
|
||||
},
|
||||
|
||||
// This method should start the API request to fetch the weather forecast.
|
||||
// This method should start the API request to fetch the weather hourly.
|
||||
// This method should definitely be overwritten in the provider.
|
||||
fetchWeatherData: function () {
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherData method.`);
|
||||
fetchWeatherHourly: function () {
|
||||
Log.warn(`Weather provider: ${this.providerName} does not subclass the fetchWeatherHourly method.`);
|
||||
},
|
||||
|
||||
// This returns a WeatherDay object for the current weather.
|
||||
@ -74,8 +75,8 @@ var WeatherProvider = Class.extend({
|
||||
},
|
||||
|
||||
// This returns an object containing WeatherDay object(s) depending on the type of call.
|
||||
weatherData: function () {
|
||||
return this.weatherDataObject;
|
||||
weatherHourly: function () {
|
||||
return this.weatherHourlyArray;
|
||||
},
|
||||
|
||||
// This returns the name of the fetched location or an empty string.
|
||||
@ -95,9 +96,9 @@ var WeatherProvider = Class.extend({
|
||||
this.weatherForecastArray = weatherForecastArray;
|
||||
},
|
||||
|
||||
// Set the weatherDataObject and notify the delegate that new information is available.
|
||||
setWeatherData: function (weatherDataObject) {
|
||||
this.weatherDataObject = weatherDataObject;
|
||||
// Set the weatherHourlyArray and notify the delegate that new information is available.
|
||||
setWeatherHourly: function (weatherHourlyArray) {
|
||||
this.weatherHourlyArray = weatherHourlyArray;
|
||||
},
|
||||
|
||||
// Set the fetched location name.
|
||||
@ -154,10 +155,11 @@ WeatherProvider.register = function (providerIdentifier, providerDetails) {
|
||||
WeatherProvider.initialize = function (providerIdentifier, delegate) {
|
||||
providerIdentifier = providerIdentifier.toLowerCase();
|
||||
|
||||
var provider = new WeatherProvider.providers[providerIdentifier]();
|
||||
const provider = new WeatherProvider.providers[providerIdentifier]();
|
||||
const config = Object.assign({}, provider.defaults, delegate.config);
|
||||
|
||||
provider.delegate = delegate;
|
||||
provider.setConfig(delegate.config);
|
||||
provider.setConfig(config);
|
||||
|
||||
provider.providerIdentifier = providerIdentifier;
|
||||
if (!provider.providerName) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Module: Weather Forecast
|
||||
|
||||
> :warning: **This module is deprecated in favor of the [weather](https://docs.magicmirror.builders/modules/weather.html) module.**
|
||||
|
||||
The `weatherforecast` module is one of the default modules of the MagicMirror.
|
||||
This module displays the weather forecast for the coming week, including an an icon to display the current conditions, the minimum temperature and the maximum temperature.
|
||||
|
||||
|
9
modules/default/weatherforecast/node_helper.js
Normal file
9
modules/default/weatherforecast/node_helper.js
Normal file
@ -0,0 +1,9 @@
|
||||
const NodeHelper = require("node_helper");
|
||||
const Log = require("logger");
|
||||
|
||||
module.exports = NodeHelper.create({
|
||||
// Override start method.
|
||||
start: function () {
|
||||
Log.warn(`The module '${this.name}' is deprecated in favor of the 'weather'-module, please refer to the documentation for a migration path`);
|
||||
}
|
||||
});
|
@ -3,6 +3,8 @@
|
||||
*
|
||||
* By Michael Teeuw https://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*
|
||||
* This module is deprecated. Any additional feature will no longer be merged.
|
||||
*/
|
||||
Module.register("weatherforecast", {
|
||||
// Default module config.
|
||||
@ -351,6 +353,13 @@ Module.register("weatherforecast", {
|
||||
this.forecast = [];
|
||||
var lastDay = null;
|
||||
var forecastData = {};
|
||||
var dayStarts = 8;
|
||||
var dayEnds = 17;
|
||||
|
||||
if (data.city && data.city.sunrise && data.city.sunset) {
|
||||
dayStarts = new Date(moment.unix(data.city.sunrise).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours();
|
||||
dayEnds = new Date(moment.unix(data.city.sunset).locale("en").format("YYYY/MM/DD HH:mm:ss")).getHours();
|
||||
}
|
||||
|
||||
// Handle different structs between forecast16 and onecall endpoints
|
||||
var forecastList = null;
|
||||
@ -371,10 +380,10 @@ Module.register("weatherforecast", {
|
||||
var hour;
|
||||
if (forecast.dt_txt) {
|
||||
day = moment(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss").format("ddd");
|
||||
hour = moment(forecast.dt_txt, "YYYY-MM-DD hh:mm:ss").toDate().getHours();
|
||||
hour = new Date(moment(forecast.dt_txt).locale("en").format("YYYY-MM-DD HH:mm:ss")).getHours();
|
||||
} else {
|
||||
day = moment(forecast.dt, "X").format("ddd");
|
||||
hour = moment(forecast.dt, "X").toDate().getHours();
|
||||
hour = new Date(moment(forecast.dt, "X")).getHours();
|
||||
}
|
||||
|
||||
if (day !== lastDay) {
|
||||
@ -400,7 +409,7 @@ Module.register("weatherforecast", {
|
||||
|
||||
// Since we don't want an icon from the start of the day (in the middle of the night)
|
||||
// we update the icon as long as it's somewhere during the day.
|
||||
if (hour >= 8 && hour <= 17) {
|
||||
if (hour > dayStarts && hour < dayEnds) {
|
||||
forecastData.icon = this.config.iconTable[forecast.weather[0].icon];
|
||||
}
|
||||
}
|
||||
@ -462,7 +471,8 @@ Module.register("weatherforecast", {
|
||||
*/
|
||||
roundValue: function (temperature) {
|
||||
var decimals = this.config.roundTemp ? 0 : 1;
|
||||
return parseFloat(temperature).toFixed(decimals);
|
||||
var roundValue = parseFloat(temperature).toFixed(decimals);
|
||||
return roundValue === "-0" ? 0 : roundValue;
|
||||
},
|
||||
|
||||
/* processRain(forecast, allForecasts)
|
||||
|
5745
package-lock.json
generated
5745
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
@ -1,25 +1,26 @@
|
||||
{
|
||||
"name": "magicmirror",
|
||||
"version": "2.14.0",
|
||||
"version": "2.15.0-develop",
|
||||
"description": "The open source modular smart mirror platform.",
|
||||
"main": "js/electron.js",
|
||||
"scripts": {
|
||||
"start": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js",
|
||||
"start:dev": "DISPLAY=\"${DISPLAY:=:0}\" ./node_modules/.bin/electron js/electron.js dev",
|
||||
"server": "node ./serveronly",
|
||||
"install": "echo \"Installing vendor files ...\n\" && cd vendor && npm install --loglevel=error",
|
||||
"install-fonts": "echo \"Installing fonts ...\n\" && cd fonts && npm install --loglevel=error",
|
||||
"postinstall": "npm run install-fonts && echo \"MagicMirror installation finished successfully! \n\"",
|
||||
"test": "NODE_ENV=test mocha tests --recursive",
|
||||
"test:coverage": "NODE_ENV=test nyc mocha tests --recursive --timeout=3000",
|
||||
"test:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text mocha tests --recursive --timeout=3000",
|
||||
"test:e2e": "NODE_ENV=test mocha tests/e2e --recursive",
|
||||
"test:unit": "NODE_ENV=test mocha tests/unit --recursive",
|
||||
"test:prettier": "prettier --check **/*.{js,css,json,md,yml}",
|
||||
"test:js": "eslint *.js js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --quiet",
|
||||
"test:js": "eslint js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --quiet",
|
||||
"test:css": "stylelint css/main.css modules/default/**/*.css --config .stylelintrc.json",
|
||||
"test:calendar": "node ./modules/default/calendar/debug.js",
|
||||
"config:check": "node js/check_config.js",
|
||||
"lint:prettier": "prettier --write **/*.{js,css,json,md,yml}",
|
||||
"lint:js": "eslint *.js js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --fix",
|
||||
"lint:js": "eslint js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --fix",
|
||||
"lint:css": "stylelint css/main.css modules/default/**/*.css --config .stylelintrc.json --fix"
|
||||
},
|
||||
"repository": {
|
||||
@ -42,53 +43,57 @@
|
||||
},
|
||||
"homepage": "https://magicmirror.builders",
|
||||
"devDependencies": {
|
||||
"chai": "^4.2.0",
|
||||
"chai": "^4.3.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"danger": "^10.5.4",
|
||||
"eslint-config-prettier": "^7.0.0",
|
||||
"eslint-plugin-jsdoc": "^30.7.8",
|
||||
"eslint-plugin-prettier": "^3.2.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-plugin-jsdoc": "^32.2.0",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"express-basic-auth": "^1.2.0",
|
||||
"husky": "^4.3.5",
|
||||
"husky": "^4.3.8",
|
||||
"jsdom": "^16.4.0",
|
||||
"lodash": "^4.17.20",
|
||||
"mocha": "^8.2.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mocha": "^8.3.0",
|
||||
"mocha-each": "^2.0.1",
|
||||
"mocha-logger": "^1.0.7",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.2.1",
|
||||
"pretty-quick": "^3.1.0",
|
||||
"spectron": "^10.0.1",
|
||||
"stylelint": "^13.8.0",
|
||||
"sinon": "^9.2.4",
|
||||
"spectron": "^13.0.0",
|
||||
"stylelint": "^13.11.0",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"stylelint-prettier": "^1.1.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"electron": "^8.5.3"
|
||||
"electron": "^11.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"colors": "^1.4.0",
|
||||
"console-stamp": "^3.0.0-rc4.2",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint": "^7.20.0",
|
||||
"express": "^4.17.1",
|
||||
"express-ipfilter": "^1.1.2",
|
||||
"feedme": "^2.0.2",
|
||||
"helmet": "^4.2.0",
|
||||
"helmet": "^4.4.1",
|
||||
"ical": "^0.8.0",
|
||||
"iconv-lite": "^0.6.2",
|
||||
"module-alias": "^2.2.2",
|
||||
"moment": "^2.29.1",
|
||||
"node-ical": "^0.12.7",
|
||||
"node-ical": "^0.12.8",
|
||||
"request": "^2.88.2",
|
||||
"rrule": "^2.6.6",
|
||||
"rrule": "^2.6.8",
|
||||
"rrule-alt": "^2.2.8",
|
||||
"simple-git": "^2.31.0",
|
||||
"socket.io": "^3.0.4",
|
||||
"simple-git": "^2.35.2",
|
||||
"socket.io": "^3.1.2",
|
||||
"valid-url": "^1.0.9"
|
||||
},
|
||||
"_moduleAliases": {
|
||||
"node_helper": "js/node_helper.js"
|
||||
"node_helper": "js/node_helper.js",
|
||||
"logger": "js/logger.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
@ -1,5 +1,5 @@
|
||||
const app = require("../js/app.js");
|
||||
const Log = require("../js/logger.js");
|
||||
const Log = require("logger");
|
||||
|
||||
app.start(function (config) {
|
||||
var bindAddress = config.address ? config.address : "localhost";
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
@ -25,7 +26,7 @@ var config = {
|
||||
calendars: [
|
||||
{
|
||||
maximumNumberOfDays: 10000,
|
||||
url: "http://localhost:8011/tests/configs/data/calendar_test.ics",
|
||||
url: "http://localhost:8080/tests/configs/data/calendar_test.ics",
|
||||
auth: {
|
||||
user: "MagicMirror",
|
||||
pass: "CallMeADog"
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
@ -25,7 +26,7 @@ var config = {
|
||||
calendars: [
|
||||
{
|
||||
maximumNumberOfDays: 10000,
|
||||
url: "http://localhost:8010/tests/configs/data/calendar_test.ics",
|
||||
url: "http://localhost:8080/tests/configs/data/calendar_test.ics",
|
||||
auth: {
|
||||
user: "MagicMirror",
|
||||
pass: "CallMeADog",
|
||||
|
44
tests/configs/modules/calendar/changed-port.js
Normal file
44
tests/configs/modules/calendar/changed-port.js
Normal file
@ -0,0 +1,44 @@
|
||||
/* Magic Mirror Test config default calendar with auth by default
|
||||
*
|
||||
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
|
||||
* MIT Licensed.
|
||||
*/
|
||||
|
||||
var config = {
|
||||
port: 8080,
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||
|
||||
language: "en",
|
||||
timeFormat: 12,
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
modules: [
|
||||
{
|
||||
module: "calendar",
|
||||
position: "bottom_bar",
|
||||
config: {
|
||||
calendars: [
|
||||
{
|
||||
maximumNumberOfDays: 10000,
|
||||
url: "http://localhost:8010/tests/configs/data/calendar_test.ics",
|
||||
auth: {
|
||||
user: "MagicMirror",
|
||||
pass: "CallMeADog"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = config;
|
||||
}
|
@ -11,7 +11,8 @@ let config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -15,7 +15,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
@ -25,7 +26,7 @@ var config = {
|
||||
calendars: [
|
||||
{
|
||||
maximumNumberOfDays: 10000,
|
||||
url: "http://localhost:8012/tests/configs/data/calendar_test.ics",
|
||||
url: "http://localhost:8080/tests/configs/data/calendar_test.ics",
|
||||
user: "MagicMirror",
|
||||
pass: "CallMeADog"
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -11,7 +11,8 @@ let config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -16,7 +16,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,8 @@ let config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,8 @@ var config = {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -15,7 +15,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
49
tests/configs/modules/weather/currentweather_compliments.js
Normal file
49
tests/configs/modules/weather/currentweather_compliments.js
Normal file
@ -0,0 +1,49 @@
|
||||
/* Magic Mirror Test config current weather compliments
|
||||
*
|
||||
* By rejas https://github.com/rejas
|
||||
*
|
||||
* MIT Licensed.
|
||||
*/
|
||||
|
||||
let config = {
|
||||
port: 8080,
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||
|
||||
language: "en",
|
||||
timeFormat: 24,
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
fullscreen: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
modules: [
|
||||
{
|
||||
module: "compliments",
|
||||
position: "top_bar",
|
||||
config: {
|
||||
compliments: {
|
||||
snow: ["snow"]
|
||||
},
|
||||
updateInterval: 4000
|
||||
}
|
||||
},
|
||||
{
|
||||
module: "weather",
|
||||
position: "bottom_bar",
|
||||
config: {
|
||||
location: "Munich",
|
||||
apiKey: "fake key",
|
||||
initialLoadDelay: 3000
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = config;
|
||||
}
|
@ -14,7 +14,8 @@ let config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,8 @@ let config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,8 @@ let config = {
|
||||
units: "imperial",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,8 @@ let config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,8 @@ let config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,8 @@ var config = {
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -31,26 +31,18 @@ describe("Electron app environment", function () {
|
||||
return helpers.stopApplication(app);
|
||||
});
|
||||
|
||||
it("should open a browserwindow", function () {
|
||||
return (
|
||||
app.client
|
||||
.waitUntilWindowLoaded()
|
||||
// .browserWindow.focus()
|
||||
.getWindowCount()
|
||||
.should.eventually.equal(1)
|
||||
.browserWindow.isMinimized()
|
||||
.should.eventually.be.false.browserWindow.isDevToolsOpened()
|
||||
.should.eventually.be.false.browserWindow.isVisible()
|
||||
.should.eventually.be.true.browserWindow.isFocused()
|
||||
.should.eventually.be.true.browserWindow.getBounds()
|
||||
.should.eventually.have.property("width")
|
||||
.and.be.above(0)
|
||||
.browserWindow.getBounds()
|
||||
.should.eventually.have.property("height")
|
||||
.and.be.above(0)
|
||||
.browserWindow.getTitle()
|
||||
.should.eventually.equal("MagicMirror²")
|
||||
);
|
||||
it("should open a browserwindow", async function () {
|
||||
await app.client.waitUntilWindowLoaded();
|
||||
app.browserWindow.focus();
|
||||
expect(await app.client.getWindowCount()).to.equal(1);
|
||||
expect(await app.browserWindow.isMinimized()).to.be.false;
|
||||
expect(await app.browserWindow.isDevToolsOpened()).to.be.false;
|
||||
expect(await app.browserWindow.isVisible()).to.be.true;
|
||||
expect(await app.browserWindow.isFocused()).to.be.true;
|
||||
const bounds = await app.browserWindow.getBounds();
|
||||
expect(bounds.width).to.be.above(0);
|
||||
expect(bounds.height).to.be.above(0);
|
||||
expect(await app.browserWindow.getTitle()).to.equal("MagicMirror²");
|
||||
});
|
||||
|
||||
it("get request from http://localhost:8080 should return 200", function (done) {
|
||||
|
@ -20,7 +20,7 @@ global.before(function () {
|
||||
});
|
||||
|
||||
exports.getElectronPath = function () {
|
||||
var electronPath = path.join(__dirname, "..", "..", "node_modules", ".bin", "electron");
|
||||
let electronPath = path.join(__dirname, "..", "..", "node_modules", ".bin", "electron");
|
||||
if (process.platform === "win32") {
|
||||
electronPath += ".cmd";
|
||||
}
|
||||
@ -42,9 +42,9 @@ exports.startApplication = function (options) {
|
||||
options.startTimeout = 30000;
|
||||
}
|
||||
|
||||
var app = new Application(options);
|
||||
const app = new Application(options);
|
||||
return app.start().then(function () {
|
||||
assert.equal(app.isRunning(), true);
|
||||
assert.strictEqual(app.isRunning(), true);
|
||||
chaiAsPromised.transferPromiseness = app.transferPromiseness;
|
||||
return app;
|
||||
});
|
||||
@ -56,6 +56,6 @@ exports.stopApplication = function (app) {
|
||||
}
|
||||
|
||||
return app.stop().then(function () {
|
||||
assert.equal(app.isRunning(), false);
|
||||
assert.strictEqual(app.isRunning(), false);
|
||||
});
|
||||
};
|
||||
|
@ -76,11 +76,11 @@ describe("Calendar module", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Basic auth", function () {
|
||||
describe("Changed port", function () {
|
||||
before(function () {
|
||||
serverBasicAuth.listen(8010);
|
||||
// Set config sample for use in test
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/basic-auth.js";
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/changed-port.js";
|
||||
});
|
||||
|
||||
after(function (done) {
|
||||
@ -92,17 +92,23 @@ describe("Calendar module", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Basic auth", function () {
|
||||
before(function () {
|
||||
// Set config sample for use in test
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/basic-auth.js";
|
||||
});
|
||||
|
||||
it("should return TestEvents", function () {
|
||||
return app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Basic auth by default", function () {
|
||||
before(function () {
|
||||
serverBasicAuth.listen(8011);
|
||||
// Set config sample for use in test
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/auth-default.js";
|
||||
});
|
||||
|
||||
after(function (done) {
|
||||
serverBasicAuth.close(done());
|
||||
});
|
||||
|
||||
it("should return TestEvents", function () {
|
||||
return app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
|
||||
});
|
||||
@ -110,15 +116,10 @@ describe("Calendar module", function () {
|
||||
|
||||
describe("Basic auth backward compatibility configuration: DEPRECATED", function () {
|
||||
before(function () {
|
||||
serverBasicAuth.listen(8012);
|
||||
// Set config sample for use in test
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/calendar/old-basic-auth.js";
|
||||
});
|
||||
|
||||
after(function (done) {
|
||||
serverBasicAuth.close(done());
|
||||
});
|
||||
|
||||
it("should return TestEvents", function () {
|
||||
return app.client.waitUntilTextExists(".calendar", "TestEvent", 10000);
|
||||
});
|
||||
|
@ -30,14 +30,16 @@ describe("Clock set to spanish language module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_24hr.js";
|
||||
});
|
||||
|
||||
it("shows date with correct format", function () {
|
||||
it("shows date with correct format", async function () {
|
||||
const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .date").should.eventually.match(dateRegex);
|
||||
const elem = await app.client.$(".clock .date");
|
||||
return elem.getText(".clock .date").should.eventually.match(dateRegex);
|
||||
});
|
||||
|
||||
it("shows time in 24hr format", function () {
|
||||
it("shows time in 24hr format", async function () {
|
||||
const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .time").should.eventually.match(timeRegex);
|
||||
const elem = await app.client.$(".clock .time");
|
||||
return elem.getText(".clock .time").should.eventually.match(timeRegex);
|
||||
});
|
||||
});
|
||||
|
||||
@ -47,14 +49,16 @@ describe("Clock set to spanish language module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_12hr.js";
|
||||
});
|
||||
|
||||
it("shows date with correct format", function () {
|
||||
it("shows date with correct format", async function () {
|
||||
const dateRegex = /^(?:lunes|martes|miércoles|jueves|viernes|sábado|domingo), \d{1,2} de (?:enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre) de \d{4}$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .date").should.eventually.match(dateRegex);
|
||||
const elem = await app.client.$(".clock .date");
|
||||
return elem.getText(".clock .date").should.eventually.match(dateRegex);
|
||||
});
|
||||
|
||||
it("shows time in 12hr format", function () {
|
||||
it("shows time in 12hr format", async function () {
|
||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .time").should.eventually.match(timeRegex);
|
||||
const elem = await app.client.$(".clock .time");
|
||||
return elem.getText(".clock .time").should.eventually.match(timeRegex);
|
||||
});
|
||||
});
|
||||
|
||||
@ -64,9 +68,10 @@ describe("Clock set to spanish language module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_showPeriodUpper.js";
|
||||
});
|
||||
|
||||
it("shows 12hr time with upper case AM/PM", function () {
|
||||
it("shows 12hr time with upper case AM/PM", async function () {
|
||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .time").should.eventually.match(timeRegex);
|
||||
const elem = await app.client.$(".clock .time");
|
||||
return elem.getText(".clock .time").should.eventually.match(timeRegex);
|
||||
});
|
||||
});
|
||||
|
||||
@ -76,9 +81,10 @@ describe("Clock set to spanish language module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/es/clock_showWeek.js";
|
||||
});
|
||||
|
||||
it("shows week with correct format", function () {
|
||||
it("shows week with correct format", async function () {
|
||||
const weekRegex = /^Semana [0-9]{1,2}$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .week").should.eventually.match(weekRegex);
|
||||
const elem = await app.client.$(".clock .week");
|
||||
elem.getText(".clock .week").should.eventually.match(weekRegex);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -32,14 +32,16 @@ describe("Clock module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_24hr.js";
|
||||
});
|
||||
|
||||
it("should show the date in the correct format", function () {
|
||||
it("should show the date in the correct format", async function () {
|
||||
const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .date").should.eventually.match(dateRegex);
|
||||
const elem = await app.client.$(".clock .date");
|
||||
return elem.getText(".clock .date").should.eventually.match(dateRegex);
|
||||
});
|
||||
|
||||
it("should show the time in 24hr format", function () {
|
||||
it("should show the time in 24hr format", async function () {
|
||||
const timeRegex = /^(?:2[0-3]|[01]\d):[0-5]\d[0-5]\d$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .time").should.eventually.match(timeRegex);
|
||||
const elem = await app.client.$(".clock .time");
|
||||
return elem.getText(".clock .time").should.eventually.match(timeRegex);
|
||||
});
|
||||
});
|
||||
|
||||
@ -49,14 +51,16 @@ describe("Clock module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_12hr.js";
|
||||
});
|
||||
|
||||
it("should show the date in the correct format", function () {
|
||||
it("should show the date in the correct format", async function () {
|
||||
const dateRegex = /^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (?:January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}, \d{4}$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .date").should.eventually.match(dateRegex);
|
||||
const elem = await app.client.$(".clock .date");
|
||||
return elem.getText(".clock .date").should.eventually.match(dateRegex);
|
||||
});
|
||||
|
||||
it("should show the time in 12hr format", function () {
|
||||
it("should show the time in 12hr format", async function () {
|
||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[ap]m$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .time").should.eventually.match(timeRegex);
|
||||
const elem = await app.client.$(".clock .time");
|
||||
return elem.getText(".clock .time").should.eventually.match(timeRegex);
|
||||
});
|
||||
});
|
||||
|
||||
@ -66,9 +70,10 @@ describe("Clock module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_showPeriodUpper.js";
|
||||
});
|
||||
|
||||
it("should show 12hr time with upper case AM/PM", function () {
|
||||
it("should show 12hr time with upper case AM/PM", async function () {
|
||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[0-5]\d[AP]M$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .time").should.eventually.match(timeRegex);
|
||||
const elem = await app.client.$(".clock .time");
|
||||
return elem.getText(".clock .time").should.eventually.match(timeRegex);
|
||||
});
|
||||
});
|
||||
|
||||
@ -78,9 +83,10 @@ describe("Clock module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_displaySeconds_false.js";
|
||||
});
|
||||
|
||||
it("should show 12hr time without seconds am/pm", function () {
|
||||
it("should show 12hr time without seconds am/pm", async function () {
|
||||
const timeRegex = /^(?:1[0-2]|[1-9]):[0-5]\d[ap]m$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .time").should.eventually.match(timeRegex);
|
||||
const elem = await app.client.$(".clock .time");
|
||||
return elem.getText(".clock .time").should.eventually.match(timeRegex);
|
||||
});
|
||||
});
|
||||
|
||||
@ -90,15 +96,17 @@ describe("Clock module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/clock/clock_showWeek.js";
|
||||
});
|
||||
|
||||
it("should show the week in the correct format", function () {
|
||||
it("should show the week in the correct format", async function () {
|
||||
const weekRegex = /^Week [0-9]{1,2}$/;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .week").should.eventually.match(weekRegex);
|
||||
const elem = await app.client.$(".clock .week");
|
||||
return elem.getText(".clock .week").should.eventually.match(weekRegex);
|
||||
});
|
||||
|
||||
it("should show the week with the correct number of week of year", function () {
|
||||
it("should show the week with the correct number of week of year", async function () {
|
||||
const currentWeekNumber = moment().week();
|
||||
const weekToShow = "Week " + currentWeekNumber;
|
||||
return app.client.waitUntilWindowLoaded().getText(".clock .week").should.eventually.equal(weekToShow);
|
||||
const elem = await app.client.$(".clock .week");
|
||||
return elem.getText(".clock .week").should.eventually.equal(weekToShow);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -31,42 +31,36 @@ describe("Compliments module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_parts_day.js";
|
||||
});
|
||||
|
||||
it("if Morning compliments for that part of day", function () {
|
||||
it("if Morning compliments for that part of day", async function () {
|
||||
var hour = new Date().getHours();
|
||||
if (hour >= 3 && hour < 12) {
|
||||
// if morning check
|
||||
return app.client
|
||||
.waitUntilWindowLoaded()
|
||||
.getText(".compliments")
|
||||
.then(function (text) {
|
||||
expect(text).to.be.oneOf(["Hi", "Good Morning", "Morning test"]);
|
||||
});
|
||||
const elem = await app.client.$(".compliments");
|
||||
return elem.getText(".compliments").then(function (text) {
|
||||
expect(text).to.be.oneOf(["Hi", "Good Morning", "Morning test"]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("if Afternoon show Compliments for that part of day", function () {
|
||||
it("if Afternoon show Compliments for that part of day", async function () {
|
||||
var hour = new Date().getHours();
|
||||
if (hour >= 12 && hour < 17) {
|
||||
// if morning check
|
||||
return app.client
|
||||
.waitUntilWindowLoaded()
|
||||
.getText(".compliments")
|
||||
.then(function (text) {
|
||||
expect(text).to.be.oneOf(["Hello", "Good Afternoon", "Afternoon test"]);
|
||||
});
|
||||
const elem = await app.client.$(".compliments");
|
||||
return elem.getText(".compliments").then(function (text) {
|
||||
expect(text).to.be.oneOf(["Hello", "Good Afternoon", "Afternoon test"]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("if Evening show Compliments for that part of day", function () {
|
||||
it("if Evening show Compliments for that part of day", async function () {
|
||||
var hour = new Date().getHours();
|
||||
if (!(hour >= 3 && hour < 12) && !(hour >= 12 && hour < 17)) {
|
||||
// if evening check
|
||||
return app.client
|
||||
.waitUntilWindowLoaded()
|
||||
.getText(".compliments")
|
||||
.then(function (text) {
|
||||
expect(text).to.be.oneOf(["Hello There", "Good Evening", "Evening test"]);
|
||||
});
|
||||
const elem = await app.client.$(".compliments");
|
||||
return elem.getText(".compliments").then(function (text) {
|
||||
expect(text).to.be.oneOf(["Hello There", "Good Evening", "Evening test"]);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -78,13 +72,11 @@ describe("Compliments module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_anytime.js";
|
||||
});
|
||||
|
||||
it("Show anytime because if configure empty parts of day compliments and set anytime compliments", function () {
|
||||
return app.client
|
||||
.waitUntilWindowLoaded()
|
||||
.getText(".compliments")
|
||||
.then(function (text) {
|
||||
expect(text).to.be.oneOf(["Anytime here"]);
|
||||
});
|
||||
it("Show anytime because if configure empty parts of day compliments and set anytime compliments", async function () {
|
||||
const elem = await app.client.$(".compliments");
|
||||
return elem.getText(".compliments").then(function (text) {
|
||||
expect(text).to.be.oneOf(["Anytime here"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -94,13 +86,11 @@ describe("Compliments module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_only_anytime.js";
|
||||
});
|
||||
|
||||
it("Show anytime compliments", function () {
|
||||
return app.client
|
||||
.waitUntilWindowLoaded()
|
||||
.getText(".compliments")
|
||||
.then(function (text) {
|
||||
expect(text).to.be.oneOf(["Anytime here"]);
|
||||
});
|
||||
it("Show anytime compliments", async function () {
|
||||
const elem = await app.client.$(".compliments");
|
||||
return elem.getText(".compliments").then(function (text) {
|
||||
expect(text).to.be.oneOf(["Anytime here"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -112,13 +102,11 @@ describe("Compliments module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/compliments/compliments_date.js";
|
||||
});
|
||||
|
||||
it("Show happy new year compliment on new years day", function () {
|
||||
return app.client
|
||||
.waitUntilWindowLoaded()
|
||||
.getText(".compliments")
|
||||
.then(function (text) {
|
||||
expect(text).to.be.oneOf(["Happy new year!"]);
|
||||
});
|
||||
it("Show happy new year compliment on new years day", async function () {
|
||||
const elem = await app.client.$(".compliments");
|
||||
return elem.getText(".compliments").then(function (text) {
|
||||
expect(text).to.be.oneOf(["Happy new year!"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -30,8 +30,9 @@ describe("Test helloworld module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/helloworld/helloworld.js";
|
||||
});
|
||||
|
||||
it("Test message helloworld module", function () {
|
||||
return app.client.waitUntilWindowLoaded().getText(".helloworld").should.eventually.equal("Test HelloWorld Module");
|
||||
it("Test message helloworld module", async function () {
|
||||
const elem = await app.client.$("helloworld");
|
||||
return elem.getText(".helloworld").should.eventually.equal("Test HelloWorld Module");
|
||||
});
|
||||
});
|
||||
|
||||
@ -41,8 +42,9 @@ describe("Test helloworld module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/helloworld/helloworld_default.js";
|
||||
});
|
||||
|
||||
it("Test message helloworld module", function () {
|
||||
return app.client.waitUntilWindowLoaded().getText(".helloworld").should.eventually.equal("Hello World!");
|
||||
it("Test message helloworld module", async function () {
|
||||
const elem = await app.client.$("helloworld");
|
||||
return elem.getText(".helloworld").should.eventually.equal("Hello World!");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user