Merge branch 'develop' into calendar-module
15
.editorconfig
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
max_line_length = 250
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{js,json}]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = tab
|
@ -1,5 +1 @@
|
|||||||
vendor/*
|
modules/default/calendar/vendor/*
|
||||||
!/vendor/vendor.js
|
|
||||||
!/modules/default/**
|
|
||||||
!/modules/node_helper
|
|
||||||
!/modules/node_helper/**
|
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
{
|
{
|
||||||
"rules": {
|
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||||
"indent": ["error", "tab"],
|
"plugins": ["prettier"],
|
||||||
"quotes": ["error", "double"],
|
|
||||||
"semi": ["error"],
|
|
||||||
"max-len": ["error", 250],
|
|
||||||
"curly": "error",
|
|
||||||
"camelcase": ["error", {"properties": "never"}],
|
|
||||||
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }],
|
|
||||||
"no-multi-spaces": "error",
|
|
||||||
"no-trailing-spaces": ["error", {"ignoreComments": false }],
|
|
||||||
"no-irregular-whitespace": ["error"]
|
|
||||||
},
|
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"node": true,
|
"es6": true,
|
||||||
"es6": true
|
"mocha": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"config": true,
|
||||||
|
"Log": true,
|
||||||
|
"MM": true,
|
||||||
|
"Module": true,
|
||||||
|
"moment": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
@ -22,5 +20,11 @@
|
|||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"globalReturn": true
|
"globalReturn": true
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"rules": {
|
||||||
|
"prettier/prettier": "error",
|
||||||
|
"eqeqeq": "error",
|
||||||
|
"no-prototype-builtins": "off",
|
||||||
|
"no-unused-vars": "off"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
15
.github/CONTRIBUTING.md
vendored
@ -1,25 +1,24 @@
|
|||||||
Contribution Policy for MagicMirror²
|
# Contribution Policy for MagicMirror²
|
||||||
====================================
|
|
||||||
|
|
||||||
Thanks for contributing to MagicMirror²!
|
Thanks for contributing to MagicMirror²!
|
||||||
|
|
||||||
We hold our code to standard, and these standards are documented below.
|
We hold our code to standard, and these standards are documented below.
|
||||||
|
|
||||||
If you wish to run both linters, use `grunt` without any arguments.
|
If you wish to run our linters, use `npm run lint` without any arguments.
|
||||||
|
|
||||||
### JavaScript: Run ESLint
|
### JavaScript: Run ESLint
|
||||||
|
|
||||||
We use [ESLint](http://eslint.org) on our JavaScript files.
|
We use [ESLint](https://eslint.org) on our JavaScript files.
|
||||||
|
|
||||||
Our ESLint configuration is in our .eslintrc.json and .eslintignore files.
|
Our ESLint configuration is in our .eslintrc.json and .eslintignore files.
|
||||||
|
|
||||||
To run ESLint, use `grunt eslint`.
|
To run ESLint, use `npm run lint:js`.
|
||||||
|
|
||||||
### CSS: Run StyleLint
|
### CSS: Run StyleLint
|
||||||
|
|
||||||
We use [StyleLint](http://stylelint.io) to lint our CSS. Our configuration is in our .stylelintrc file.
|
We use [StyleLint](https://stylelint.io) to lint our CSS. Our configuration is in our .stylelintrc file.
|
||||||
|
|
||||||
To run StyleLint, use `grunt stylelint`.
|
To run StyleLint, use `npm run lint:style`.
|
||||||
|
|
||||||
### Submitting Issues
|
### Submitting Issues
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ Problems installing or configuring your MagicMirror? Check out: [https://forum.m
|
|||||||
|
|
||||||
When submitting a new issue, please supply the following information:
|
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, Windows, Mac, Linux, System V UNIX).
|
||||||
|
|
||||||
**Node Version**: Make sure it's version 0.12.13 or later.
|
**Node Version**: Make sure it's version 0.12.13 or later.
|
||||||
|
|
||||||
|
7
.github/ISSUE_TEMPLATE.md
vendored
@ -1,24 +1,29 @@
|
|||||||
## I'm not sure if this is a bug
|
## I'm not sure if this is a bug
|
||||||
|
|
||||||
If you're not sure if it's a real bug or if it's just you, please open a topic on the forum: [https://forum.magicmirror.builders/category/15/bug-hunt](https://forum.magicmirror.builders/category/15/bug-hunt)
|
If you're not sure if it's a real bug or if it's just you, please open a topic on the forum: [https://forum.magicmirror.builders/category/15/bug-hunt](https://forum.magicmirror.builders/category/15/bug-hunt)
|
||||||
|
|
||||||
## I'm having troubles installing or configuring MagicMirror
|
## I'm having troubles installing or configuring MagicMirror
|
||||||
|
|
||||||
Problems installing or configuring your MagicMirror? Check out: [https://forum.magicmirror.builders/category/10/troubleshooting](https://forum.magicmirror.builders/category/10/troubleshooting)
|
Problems installing or configuring your MagicMirror? Check out: [https://forum.magicmirror.builders/category/10/troubleshooting](https://forum.magicmirror.builders/category/10/troubleshooting)
|
||||||
|
|
||||||
## I found a bug in the MagicMirror installer
|
## 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:
|
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:
|
||||||
[https://github.com/sdetweil/MagicMirror_scripts](https://github.com/sdetweil/MagicMirror_scripts)
|
[https://github.com/sdetweil/MagicMirror_scripts](https://github.com/sdetweil/MagicMirror_scripts)
|
||||||
|
|
||||||
## I found a bug in the MagicMirror Docker image
|
## I found a bug in the MagicMirror Docker image
|
||||||
|
|
||||||
If you are facing an issue or found a bug while running MagicMirror inside a Docker container please create an issue in the GitHub repository of the MagicMirror Docker image:
|
If you are facing an issue or found a bug while running MagicMirror inside a Docker container please create an issue in the GitHub repository of the MagicMirror Docker image:
|
||||||
[https://github.com/bastilimbach/docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror)
|
[https://github.com/bastilimbach/docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## I found a bug in MagicMirror
|
## I found a bug in MagicMirror
|
||||||
|
|
||||||
Please make sure to only submit reproducible issues. You can safely remove everything above the dividing line.
|
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:
|
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, Windows, Mac, Linux, System V UNIX).
|
||||||
|
|
||||||
**Node Version**: Make sure it's version 8 or later.
|
**Node Version**: Make sure it's version 8 or later.
|
||||||
|
|
||||||
|
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -7,8 +7,7 @@ pull request to send us your changes. This makes everyone's lives
|
|||||||
easier (including yours) and helps us out on the development team.
|
easier (including yours) and helps us out on the development team.
|
||||||
Thanks!
|
Thanks!
|
||||||
|
|
||||||
|
- Does the pull request solve a **related** issue?
|
||||||
* Does the pull request solve a **related** issue?
|
- If so, can you reference the issue?
|
||||||
* If so, can you reference the issue?
|
- What does the pull request accomplish? Use a list if needed.
|
||||||
* What does the pull request accomplish? Use a list if needed.
|
- If it includes major visual changes please add screenshots.
|
||||||
* If it includes major visual changes please add screenshots.
|
|
||||||
|
1
.gitignore
vendored
@ -8,7 +8,6 @@ pids
|
|||||||
*.seed
|
*.seed
|
||||||
lib-cov
|
lib-cov
|
||||||
coverage
|
coverage
|
||||||
.grunt
|
|
||||||
.lock-wscript
|
.lock-wscript
|
||||||
build/Release
|
build/Release
|
||||||
/node_modules/**/*
|
/node_modules/**/*
|
||||||
|
5
.prettierignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package-lock.json
|
||||||
|
/config/**/*
|
||||||
|
/modules/default/calendar/vendor/ical.js/**/*
|
||||||
|
/vendor/**/*
|
||||||
|
!/vendor/vendor.js
|
3
.prettierrc.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "none"
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "stylelint-config-standard",
|
"extends": ["stylelint-prettier/recommended"],
|
||||||
"font-family-name-quotes": "double-where-recommended",
|
"plugins": ["stylelint-prettier"],
|
||||||
"block-no-empty": false
|
"rules": {
|
||||||
|
"prettier/prettier": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,14 @@ before_install:
|
|||||||
- npm i -g npm
|
- npm i -g npm
|
||||||
before_script:
|
before_script:
|
||||||
- yarn danger ci
|
- yarn danger ci
|
||||||
- npm install grunt-cli -g
|
|
||||||
- "export DISPLAY=:99.0"
|
- "export DISPLAY=:99.0"
|
||||||
- "export ELECTRON_DISABLE_SANDBOX=1"
|
- "export ELECTRON_DISABLE_SANDBOX=1"
|
||||||
- "sh -e /etc/init.d/xvfb start"
|
- "sh -e /etc/init.d/xvfb start"
|
||||||
- sleep 5
|
- sleep 5
|
||||||
script:
|
script:
|
||||||
- npm run test:lint
|
- npm run test:prettier
|
||||||
|
- npm run test:js
|
||||||
|
- npm run test:css
|
||||||
- npm run test:e2e
|
- npm run test:e2e
|
||||||
- npm run test:unit
|
- npm run test:unit
|
||||||
after_script:
|
after_script:
|
||||||
|
126
CHANGELOG.md
@ -1,10 +1,38 @@
|
|||||||
# MagicMirror² Change Log
|
# MagicMirror² Change Log
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
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²
|
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror²
|
||||||
|
|
||||||
|
## [2.12.0] - Unreleased (Develop Branch)
|
||||||
|
|
||||||
|
_This release is scheduled to be released on 2020-07-01._
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Compliments Module - Add Advice API (https://api.adviceslip.com/) Option
|
||||||
|
|
||||||
|
- Added prettier for an even cleaner codebase
|
||||||
|
|
||||||
|
### Updated
|
||||||
|
|
||||||
|
- Cleaned up alert module code
|
||||||
|
- Cleaned up check_config code
|
||||||
|
- Replaced grunt-based linters with their non-grunt equivalents
|
||||||
|
- Switch to most of the eslint:recommended rules and fix warnings
|
||||||
|
- Replaced insecure links with https ones
|
||||||
|
- Cleaned up all "no-undef" warnings from eslint
|
||||||
|
|
||||||
|
### Deleted
|
||||||
|
|
||||||
|
- Removed truetype (ttf) fonts
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The broken modules due to Socket.io change from last release [#1973](https://github.com/MichMich/MagicMirror/issues/1973)
|
||||||
|
- Add backward compatibility for old module code in socketclient.js [#1973](https://github.com/MichMich/MagicMirror/issues/1973)
|
||||||
|
|
||||||
## [2.11.0] - 2020-04-01
|
## [2.11.0] - 2020-04-01
|
||||||
|
|
||||||
🚨 READ THIS BEFORE UPDATING 🚨
|
🚨 READ THIS BEFORE UPDATING 🚨
|
||||||
@ -14,11 +42,13 @@ In the past years the project has grown a lot. This came with a huge downside: p
|
|||||||
For more information regarding this major change, please check issue [#1860](https://github.com/MichMich/MagicMirror/issues/1860).
|
For more information regarding this major change, please check issue [#1860](https://github.com/MichMich/MagicMirror/issues/1860).
|
||||||
|
|
||||||
### Deleted
|
### Deleted
|
||||||
|
|
||||||
- Remove installers.
|
- Remove installers.
|
||||||
- Remove externalized scripts.
|
- Remove externalized scripts.
|
||||||
- Remove jshint dependency, instead eslint checks your config file now
|
- Remove jshint dependency, instead eslint checks your config file now
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Brazilian translation for "FEELS".
|
- Brazilian translation for "FEELS".
|
||||||
- Ukrainian translation.
|
- Ukrainian translation.
|
||||||
- Finnish translation for "PRECIP", "UPDATE_INFO_MULTIPLE" and "UPDATE_INFO_SINGLE".
|
- Finnish translation for "PRECIP", "UPDATE_INFO_MULTIPLE" and "UPDATE_INFO_SINGLE".
|
||||||
@ -30,8 +60,10 @@ For more information regarding this major change, please check issue [#1860](htt
|
|||||||
- Added the ability to configure a list of modules that shouldn't be update checked.
|
- Added the ability to configure a list of modules that shouldn't be update checked.
|
||||||
- Run linters on git commits
|
- Run linters on git commits
|
||||||
- Added date functionality to compliments: display birthday wishes or celebrate an anniversary
|
- Added date functionality to compliments: display birthday wishes or celebrate an anniversary
|
||||||
|
- Add HTTPS support for clientonly-mode.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Force declaration of public ip address in config file (ISSUE #1852)
|
- Force declaration of public ip address in config file (ISSUE #1852)
|
||||||
- Fixes `run-start.sh`: If running in docker-container, don't check the environment, just start electron (ISSUE #1859)
|
- Fixes `run-start.sh`: If running in docker-container, don't check the environment, just start electron (ISSUE #1859)
|
||||||
- Fix calendar time offset for recurring events crossing Daylight Savings Time (ISSUE #1798)
|
- Fix calendar time offset for recurring events crossing Daylight Savings Time (ISSUE #1798)
|
||||||
@ -42,6 +74,7 @@ For more information regarding this major change, please check issue [#1860](htt
|
|||||||
- Fix update checking skipping 3rd party modules the first time
|
- Fix update checking skipping 3rd party modules the first time
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Remove documentation from core repository and link to new dedicated docs site: [docs.magicmirror.builders](https://docs.magicmirror.builders).
|
- Remove documentation from core repository and link to new dedicated docs site: [docs.magicmirror.builders](https://docs.magicmirror.builders).
|
||||||
- Updated config.js.sample: Corrected some grammar on `config.js.sample` comment section.
|
- Updated config.js.sample: Corrected some grammar on `config.js.sample` comment section.
|
||||||
- Removed `run-start.sh` script and update start commands:
|
- Removed `run-start.sh` script and update start commands:
|
||||||
@ -55,6 +88,7 @@ For more information regarding this major change, please check issue [#1860](htt
|
|||||||
## [2.10.1] - 2020-01-10
|
## [2.10.1] - 2020-01-10
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Updated README.md: Added links to the official documentation website and remove links to broken installer.
|
- Updated README.md: Added links to the official documentation website and remove links to broken installer.
|
||||||
|
|
||||||
## [2.10.0] - 2020-01-01
|
## [2.10.0] - 2020-01-01
|
||||||
@ -64,12 +98,14 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`.
|
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Timestamps in log output.
|
- Timestamps in log output.
|
||||||
- Padding in dateheader mode of the calendar module.
|
- Padding in dateheader mode of the calendar module.
|
||||||
- New upgrade script to help users consume regular updates installers/upgrade-script.sh.
|
- New upgrade script to help users consume regular updates installers/upgrade-script.sh.
|
||||||
- New script to help setup pm2, without install installers/fixuppm2.sh.
|
- New script to help setup pm2, without install installers/fixuppm2.sh.
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Updated lower bound of `lodash` and `helmet` dependencies for security patches.
|
- Updated lower bound of `lodash` and `helmet` dependencies for security patches.
|
||||||
- Updated compliments.js to handle newline in text, as textfields to not interpolate contents.
|
- Updated compliments.js to handle newline in text, as textfields to not interpolate contents.
|
||||||
- Updated raspberry.sh installer script to handle new platform issues, split node/npm, pm2, and screen saver changes.
|
- Updated raspberry.sh installer script to handle new platform issues, split node/npm, pm2, and screen saver changes.
|
||||||
@ -78,6 +114,7 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
- Only check for xwindows running if not on macOS.
|
- Only check for xwindows running if not on macOS.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed issue in weatherforecast module where predicted amount of rain was not using the decimal symbol specified in config.js.
|
- Fixed issue in weatherforecast module where predicted amount of rain was not using the decimal symbol specified in config.js.
|
||||||
- Module header now updates correctly, if a module need to dynamically show/hide its header based on a condition.
|
- Module header now updates correctly, if a module need to dynamically show/hide its header based on a condition.
|
||||||
- Fix handling of config.js for serverOnly mode commented out.
|
- Fix handling of config.js for serverOnly mode commented out.
|
||||||
@ -90,18 +127,21 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Spanish translation for "PRECIP".
|
- Spanish translation for "PRECIP".
|
||||||
- Adding a Malay (Malaysian) translation for MagicMirror².
|
- Adding a Malay (Malaysian) translation for MagicMirror².
|
||||||
- Add test check URLs of vendors 200 and 404 HTTP CODE.
|
- Add test check URLs of vendors 200 and 404 HTTP CODE.
|
||||||
- Add tests for new weather module and helper to stub ajax requests.
|
- Add tests for new weather module and helper to stub ajax requests.
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Updatenotification module: Display update notification for a limited (configurable) time.
|
- Updatenotification module: Display update notification for a limited (configurable) time.
|
||||||
- Enabled e2e/vendor_spec.js tests.
|
- Enabled e2e/vendor_spec.js tests.
|
||||||
- The css/custom.css will be rename after the next release. We've add into `run-start.sh` a instruction by GIT to ignore with `--skip-worktree` and `rm --cached`. [#1540](https://github.com/MichMich/MagicMirror/issues/1540)
|
- The css/custom.css will be renamed after the next release. We've added into `run-start.sh` an instruction by GIT to ignore with `--skip-worktree` and `rm --cached`. [#1540](https://github.com/MichMich/MagicMirror/issues/1540)
|
||||||
- Disable sending of notification CLOCK_SECOND when displaySeconds is false.
|
- Disable sending of notification CLOCK_SECOND when displaySeconds is false.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Updatenotification module: Properly handle race conditions, prevent crash.
|
- Updatenotification module: Properly handle race conditions, prevent crash.
|
||||||
- Send `NEWS_FEED` notification also for the first news messages which are shown.
|
- Send `NEWS_FEED` notification also for the first news messages which are shown.
|
||||||
- Fixed issue where weather module would not refresh data after a network or API outage. [#1722](https://github.com/MichMich/MagicMirror/issues/1722)
|
- Fixed issue where weather module would not refresh data after a network or API outage. [#1722](https://github.com/MichMich/MagicMirror/issues/1722)
|
||||||
@ -113,6 +153,7 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Option to show event location in calendar
|
- Option to show event location in calendar
|
||||||
- Finnish translation for "Feels" and "Weeks"
|
- Finnish translation for "Feels" and "Weeks"
|
||||||
- Russian translation for “Feels”
|
- Russian translation for “Feels”
|
||||||
@ -132,13 +173,15 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
- Added to `newsfeed.js`: in order to design the news article better with css, three more class-names were introduced: newsfeed-desc, newsfeed-desc, newsfeed-desc
|
- Added to `newsfeed.js`: in order to design the news article better with css, three more class-names were introduced: newsfeed-desc, newsfeed-desc, newsfeed-desc
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- English translation for "Feels" to "Feels like"
|
- English translation for "Feels" to "Feels like"
|
||||||
- Fixed the example calender url in `config.js.sample`
|
- Fixed the example calendar url in `config.js.sample`
|
||||||
- Update `ical.js` to solve various calendar issues.
|
- Update `ical.js` to solve various calendar issues.
|
||||||
- Update weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
|
- Update weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
|
||||||
- Only update clock once per minute when seconds aren't shown
|
- Only update clock once per minute when seconds aren't shown
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed uncaught exception, race condition on module update
|
- Fixed uncaught exception, race condition on module update
|
||||||
- Fixed issue [#1696](https://github.com/MichMich/MagicMirror/issues/1696), some ical files start date to not parse to date type
|
- Fixed issue [#1696](https://github.com/MichMich/MagicMirror/issues/1696), some ical files start date to not parse to date type
|
||||||
- Allowance HTML5 autoplay-policy (policy is changed from Chrome 66 updates)
|
- Allowance HTML5 autoplay-policy (policy is changed from Chrome 66 updates)
|
||||||
@ -150,6 +193,7 @@ Special thanks to @sdetweil for all his great contributions!
|
|||||||
- Updated the fetchedLocationName variable in currentweather.js so that city shows up in the header
|
- Updated the fetchedLocationName variable in currentweather.js so that city shows up in the header
|
||||||
|
|
||||||
### Updated installer
|
### Updated installer
|
||||||
|
|
||||||
- give non-pi2+ users (pi0, odroid, jetson nano, mac, windows, ...) option to continue install
|
- give non-pi2+ users (pi0, odroid, jetson nano, mac, windows, ...) option to continue install
|
||||||
- use current username vs hardcoded 'pi' to support non-pi install
|
- use current username vs hardcoded 'pi' to support non-pi install
|
||||||
- check for npm installed. node install doesn't do npm anymore
|
- check for npm installed. node install doesn't do npm anymore
|
||||||
@ -166,6 +210,7 @@ Fixed `package.json` version number.
|
|||||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Italian translation for "Feels"
|
- Italian translation for "Feels"
|
||||||
- Basic Klingon (tlhIngan Hol) translations
|
- Basic Klingon (tlhIngan Hol) translations
|
||||||
- Disabled the screensaver on raspbian with installation script
|
- Disabled the screensaver on raspbian with installation script
|
||||||
@ -179,12 +224,14 @@ Fixed `package.json` version number.
|
|||||||
- Add `name` config option for calendars to be sent along with event broadcasts
|
- Add `name` config option for calendars to be sent along with event broadcasts
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Bumped the Electron dependency to v3.0.13 to support the most recent Raspbian. [#1500](https://github.com/MichMich/MagicMirror/issues/1500)
|
- Bumped the Electron dependency to v3.0.13 to support the most recent Raspbian. [#1500](https://github.com/MichMich/MagicMirror/issues/1500)
|
||||||
- Updated modernizr code in alert module, fixed a small typo there too
|
- Updated modernizr code in alert module, fixed a small typo there too
|
||||||
- More verbose error message on console if the config is malformed
|
- More verbose error message on console if the config is malformed
|
||||||
- Updated installer script to install Node.js version 10.x
|
- Updated installer script to install Node.js version 10.x
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed temperature displays in currentweather and weatherforecast modules [#1503](https://github.com/MichMich/MagicMirror/issues/1503), [#1511](https://github.com/MichMich/MagicMirror/issues/1511).
|
- Fixed temperature displays in currentweather and weatherforecast modules [#1503](https://github.com/MichMich/MagicMirror/issues/1503), [#1511](https://github.com/MichMich/MagicMirror/issues/1511).
|
||||||
- Fixed unhandled error on bad git data in updatenotification module [#1285](https://github.com/MichMich/MagicMirror/issues/1285).
|
- Fixed unhandled error on bad git data in updatenotification module [#1285](https://github.com/MichMich/MagicMirror/issues/1285).
|
||||||
- Weather forecast now works with openweathermap in new weather module. Daily data are displayed, see issue [#1504](https://github.com/MichMich/MagicMirror/issues/1504).
|
- Weather forecast now works with openweathermap in new weather module. Daily data are displayed, see issue [#1504](https://github.com/MichMich/MagicMirror/issues/1504).
|
||||||
@ -193,7 +240,7 @@ Fixed `package.json` version number.
|
|||||||
- Installation script problems with raspbian
|
- Installation script problems with raspbian
|
||||||
- Calendar: only show repeating count if the event is actually repeating [#1534](https://github.com/MichMich/MagicMirror/pull/1534)
|
- Calendar: only show repeating count if the event is actually repeating [#1534](https://github.com/MichMich/MagicMirror/pull/1534)
|
||||||
- Calendar: Fix exdate handling when multiple values are specified (comma separated)
|
- Calendar: Fix exdate handling when multiple values are specified (comma separated)
|
||||||
- Calendar: Fix relative date handling for fulldate events, calculate difference always from start of day [#1572](https://github.com/MichMich/MagicMirror/issues/1572)
|
- Calendar: Fix relative date handling for fulldate events, calculate difference always from start of day [#1572](https://github.com/MichMich/MagicMirror/issues/1572)
|
||||||
- Fix null dereference in moduleNeedsUpdate when the module isn't visible
|
- Fix null dereference in moduleNeedsUpdate when the module isn't visible
|
||||||
- Calendar: Fixed event end times by setting default calendarEndTime to "LT" (Local time format). [#1479]
|
- Calendar: Fixed event end times by setting default calendarEndTime to "LT" (Local time format). [#1479]
|
||||||
- Calendar: Fixed missing calendar fetchers after server process restarts [#1589](https://github.com/MichMich/MagicMirror/issues/1589)
|
- Calendar: Fixed missing calendar fetchers after server process restarts [#1589](https://github.com/MichMich/MagicMirror/issues/1589)
|
||||||
@ -202,6 +249,7 @@ Fixed `package.json` version number.
|
|||||||
- Fix documentation of `useKMPHwind` option in currentweather
|
- Fix documentation of `useKMPHwind` option in currentweather
|
||||||
|
|
||||||
### New weather module
|
### New weather module
|
||||||
|
|
||||||
- Fixed weather forecast table display [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
|
- Fixed weather forecast table display [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
|
||||||
- Dimmed loading indicator for weather forecast.
|
- Dimmed loading indicator for weather forecast.
|
||||||
- Implemented config option `decimalSymbol` [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
|
- Implemented config option `decimalSymbol` [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
|
||||||
@ -219,11 +267,13 @@ Fixed `package.json` version number.
|
|||||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues updating, make sure you are running the latest version of Node.
|
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues updating, make sure you are running the latest version of Node.
|
||||||
|
|
||||||
### ✨ Experimental ✨
|
### ✨ Experimental ✨
|
||||||
|
|
||||||
- New default [module weather](modules/default/weather). This module will eventually replace the current `currentweather` and `weatherforecast` modules. The new module is still pretty experimental, but it's included so you can give it a try and help us improve this module. Please give us you feedback using [this forum post](https://forum.magicmirror.builders/topic/9335/default-weather-module-refactoring).
|
- New default [module weather](modules/default/weather). This module will eventually replace the current `currentweather` and `weatherforecast` modules. The new module is still pretty experimental, but it's included so you can give it a try and help us improve this module. Please give us you feedback using [this forum post](https://forum.magicmirror.builders/topic/9335/default-weather-module-refactoring).
|
||||||
|
|
||||||
A huge, huge, huge thanks to user @fewieden for all his hard work on the new `weather` module!
|
A huge, huge, huge thanks to user @fewieden for all his hard work on the new `weather` module!
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Possibility to add classes to the cell of symbol, title and time of the events of calendar.
|
- Possibility to add classes to the cell of symbol, title and time of the events of calendar.
|
||||||
- Font-awesome 5, still has 4 for backwards compatibility.
|
- Font-awesome 5, still has 4 for backwards compatibility.
|
||||||
- Missing `showEnd` in calendar documentation
|
- Missing `showEnd` in calendar documentation
|
||||||
@ -238,22 +288,25 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Documentation for the existing `scale` option in the Weather Forecast module.
|
- Documentation for the existing `scale` option in the Weather Forecast module.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Allow to parse recurring calendar events where the start date is before 1900
|
|
||||||
|
- Allow parsing recurring calendar events where the start date is before 1900
|
||||||
- Fixed Polish translation for Single Update Info
|
- Fixed Polish translation for Single Update Info
|
||||||
- Ignore entries with unparseable details in the calendar module
|
- Ignore entries with unparseable details in the calendar module
|
||||||
- Bug showing FullDayEvents one day too long in calendar fixed
|
- Bug showing FullDayEvents one day too long in calendar fixed
|
||||||
- Bug in newsfeed when `removeStartTags` is used on the description [#1478](https://github.com/MichMich/MagicMirror/issues/1478)
|
- Bug in newsfeed when `removeStartTags` is used on the description [#1478](https://github.com/MichMich/MagicMirror/issues/1478)
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- The default calendar setting `showEnd` is changed to `false`.
|
- The default calendar setting `showEnd` is changed to `false`.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- The Weather Forecast module by default displays the ° symbol after every numeric value to be consistent with the Current Weather module.
|
|
||||||
|
|
||||||
|
- The Weather Forecast module by default displays the ° symbol after every numeric value to be consistent with the Current Weather module.
|
||||||
|
|
||||||
## [2.5.0] - 2018-10-01
|
## [2.5.0] - 2018-10-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Romanian translation for "Feels"
|
- Romanian translation for "Feels"
|
||||||
- Support multi-line compliments
|
- Support multi-line compliments
|
||||||
- Simplified Chinese translation for "Feels"
|
- Simplified Chinese translation for "Feels"
|
||||||
@ -268,6 +321,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Support for showing end of events through config parameters showEnd and dateEndFormat
|
- Support for showing end of events through config parameters showEnd and dateEndFormat
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed gzip encoded calendar loading issue #1400.
|
- Fixed gzip encoded calendar loading issue #1400.
|
||||||
- Mixup between german and spanish translation for newsfeed.
|
- Mixup between german and spanish translation for newsfeed.
|
||||||
- Fixed close dates to be absolute, if no configured in the config.js - module Calendar
|
- Fixed close dates to be absolute, if no configured in the config.js - module Calendar
|
||||||
@ -313,11 +367,13 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add update translations for Português Brasileiro
|
- Add update translations for Português Brasileiro
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Upgrade to Electron 2.0.0.
|
- Upgrade to Electron 2.0.0.
|
||||||
- Remove yarn-or-npm which breaks production builds.
|
- Remove yarn-or-npm which breaks production builds.
|
||||||
- Invoke module suspend even if no dom content. [#1308](https://github.com/MichMich/MagicMirror/issues/1308)
|
- Invoke module suspend even if no dom content. [#1308](https://github.com/MichMich/MagicMirror/issues/1308)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed issue where wind chill could not be displayed in Fahrenheit. [#1247](https://github.com/MichMich/MagicMirror/issues/1247)
|
- Fixed issue where wind chill could not be displayed in Fahrenheit. [#1247](https://github.com/MichMich/MagicMirror/issues/1247)
|
||||||
- Fixed issues where a module crashes when it tries to dismiss a non existing alert. [#1240](https://github.com/MichMich/MagicMirror/issues/1240)
|
- Fixed issues where a module crashes when it tries to dismiss a non existing alert. [#1240](https://github.com/MichMich/MagicMirror/issues/1240)
|
||||||
- In default module currentWeather/currentWeather.js line 296, 300, self.config.animationSpeed can not be found because the notificationReceived function does not have "self" variable.
|
- In default module currentWeather/currentWeather.js line 296, 300, self.config.animationSpeed can not be found because the notificationReceived function does not have "self" variable.
|
||||||
@ -330,6 +386,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Fixed issue where heat index and wind chill were reporting incorrect values in Kelvin. [#1263](https://github.com/MichMich/MagicMirror/issues/1263)
|
- Fixed issue where heat index and wind chill were reporting incorrect values in Kelvin. [#1263](https://github.com/MichMich/MagicMirror/issues/1263)
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Updated Italian translation
|
- Updated Italian translation
|
||||||
- Updated German translation
|
- Updated German translation
|
||||||
- Updated Dutch translation
|
- Updated Dutch translation
|
||||||
@ -337,6 +394,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
## [2.3.1] - 2018-04-01
|
## [2.3.1] - 2018-04-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Downgrade electron to 1.4.15 to solve the black screen issue.[#1243](https://github.com/MichMich/MagicMirror/issues/1243)
|
- Downgrade electron to 1.4.15 to solve the black screen issue.[#1243](https://github.com/MichMich/MagicMirror/issues/1243)
|
||||||
|
|
||||||
## [2.3.0] - 2018-04-01
|
## [2.3.0] - 2018-04-01
|
||||||
@ -347,7 +405,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add system notification `MODULE_DOM_CREATED` for notifying each module when their Dom has been fully loaded.
|
- Add system notification `MODULE_DOM_CREATED` for notifying each module when their Dom has been fully loaded.
|
||||||
- Add types for module.
|
- Add types for module.
|
||||||
- Implement Danger.js to notify contributors when CHANGELOG.md is missing in PR.
|
- Implement Danger.js to notify contributors when CHANGELOG.md is missing in PR.
|
||||||
- Allow to scroll in full page article view of default newsfeed module with gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
|
- Allow scrolling in full page article view of default newsfeed module with gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
|
||||||
- Changed 'compliments.js' - update DOM if remote compliments are loaded instead of waiting one updateInterval to show custom compliments
|
- Changed 'compliments.js' - update DOM if remote compliments are loaded instead of waiting one updateInterval to show custom compliments
|
||||||
- Automated unit tests utils, deprecated, translator, cloneObject(lockstrings)
|
- Automated unit tests utils, deprecated, translator, cloneObject(lockstrings)
|
||||||
- Automated integration tests translations
|
- Automated integration tests translations
|
||||||
@ -357,6 +415,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add dc:date to parsing in newsfeed module, which allows parsing of more rss feeds.
|
- Add dc:date to parsing in newsfeed module, which allows parsing of more rss feeds.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Add link to GitHub repository which contains the respective Dockerfile.
|
- Add link to GitHub repository which contains the respective Dockerfile.
|
||||||
- Optimized automated unit tests cloneObject, cmpVersions
|
- Optimized automated unit tests cloneObject, cmpVersions
|
||||||
- Update notifications use now translation templates instead of normal strings.
|
- Update notifications use now translation templates instead of normal strings.
|
||||||
@ -364,6 +423,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Changed Electron dependency to v1.7.13.
|
- Changed Electron dependency to v1.7.13.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- News article in fullscreen (iframe) is now shown in front of modules.
|
- News article in fullscreen (iframe) is now shown in front of modules.
|
||||||
- Forecast respects maxNumberOfDays regardless of endpoint.
|
- Forecast respects maxNumberOfDays regardless of endpoint.
|
||||||
- Fix exception on translation of objects.
|
- Fix exception on translation of objects.
|
||||||
@ -381,6 +441,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
## [2.2.1] - 2018-01-01
|
## [2.2.1] - 2018-01-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed linting errors.
|
- Fixed linting errors.
|
||||||
|
|
||||||
## [2.2.0] - 2018-01-01
|
## [2.2.0] - 2018-01-01
|
||||||
@ -388,10 +449,12 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Calender week is now handled with a variable translation in order to move number language specific.
|
|
||||||
|
- Calendar week is now handled with a variable translation in order to move number language specific.
|
||||||
- Reverted the Electron dependency back to 1.4.15 since newer version don't seem to work on the Raspberry Pi very well.
|
- Reverted the Electron dependency back to 1.4.15 since newer version don't seem to work on the Raspberry Pi very well.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add option to use [Nunjucks](https://mozilla.github.io/nunjucks/) templates in modules. (See `helloworld` module as an example.)
|
- Add option to use [Nunjucks](https://mozilla.github.io/nunjucks/) templates in modules. (See `helloworld` module as an example.)
|
||||||
- Add Bulgarian translations for MagicMirror² and Alert module.
|
- Add Bulgarian translations for MagicMirror² and Alert module.
|
||||||
- Add graceful shutdown of modules by calling `stop` function of each `node_helper` on SIGINT before exiting.
|
- Add graceful shutdown of modules by calling `stop` function of each `node_helper` on SIGINT before exiting.
|
||||||
@ -405,6 +468,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add option for decimal symbols other than the decimal point for temperature values in both default weather modules: WeatherForecast and CurrentWeather.
|
- Add option for decimal symbols other than the decimal point for temperature values in both default weather modules: WeatherForecast and CurrentWeather.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed issue with calendar module showing more than `maximumEntries` allows
|
- Fixed issue with calendar module showing more than `maximumEntries` allows
|
||||||
- WeatherForecast and CurrentWeather are now using HTTPS instead of HTTP
|
- WeatherForecast and CurrentWeather are now using HTTPS instead of HTTP
|
||||||
- Correcting translation for Indonesian language
|
- Correcting translation for Indonesian language
|
||||||
@ -415,9 +479,11 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Remove Roboto fonts files inside `fonts` and these are installed by npm install command.
|
- Remove Roboto fonts files inside `fonts` and these are installed by npm install command.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add `clientonly` script to start only the electron client for a remote server.
|
- Add `clientonly` script to start only the electron client for a remote server.
|
||||||
- Add symbol and color properties of event when `CALENDAR_EVENTS` notification is broadcasted from `default/calendar` module.
|
- Add symbol and color properties of event when `CALENDAR_EVENTS` notification is broadcasted from `default/calendar` module.
|
||||||
- Add `.vscode/` folder to `.gitignore` to keep custom Visual Studio Code config out of git.
|
- Add `.vscode/` folder to `.gitignore` to keep custom Visual Studio Code config out of git.
|
||||||
@ -434,6 +500,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add Slack badge to Readme.
|
- Add Slack badge to Readme.
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Changed 'default.js' - listen on all attached interfaces by default.
|
- Changed 'default.js' - listen on all attached interfaces by default.
|
||||||
- Add execution of `npm list` after the test are ran in Travis CI.
|
- Add execution of `npm list` after the test are ran in Travis CI.
|
||||||
- Change hooks for the vendors e2e tests.
|
- Change hooks for the vendors e2e tests.
|
||||||
@ -442,6 +509,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Set version of the `express-ipfilter` on 0.3.1.
|
- Set version of the `express-ipfilter` on 0.3.1.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed issue with incorrect alignment of analog clock when displayed in the center column of the MM.
|
- Fixed issue with incorrect alignment of analog clock when displayed in the center column of the MM.
|
||||||
- Fixed ipWhitelist behaviour to make empty whitelist ([]) allow any and all hosts access to the MM.
|
- Fixed ipWhitelist behaviour to make empty whitelist ([]) allow any and all hosts access to the MM.
|
||||||
- Fixed issue with calendar module where 'excludedEvents' count towards 'maximumEntries'.
|
- Fixed issue with calendar module where 'excludedEvents' count towards 'maximumEntries'.
|
||||||
@ -452,11 +520,13 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
## [2.1.2] - 2017-07-01
|
## [2.1.2] - 2017-07-01
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Revert Docker related changes in favor of [docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror). All Docker images are outsourced. ([#856](https://github.com/MichMich/MagicMirror/pull/856))
|
- Revert Docker related changes in favor of [docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror). All Docker images are outsourced. ([#856](https://github.com/MichMich/MagicMirror/pull/856))
|
||||||
- Change Docker base image (Debian + Node) to an arm based distro (AlpineARM + Node) ([#846](https://github.com/MichMich/MagicMirror/pull/846))
|
- Change Docker base image (Debian + Node) to an arm based distro (AlpineARM + Node) ([#846](https://github.com/MichMich/MagicMirror/pull/846))
|
||||||
- Fix the dockerfile to have it running from the first time.
|
- Fix the dockerfile to have it running from the first time.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add in option to wrap long calendar events to multiple lines using `wrapEvents` configuration option.
|
- Add in option to wrap long calendar events to multiple lines using `wrapEvents` configuration option.
|
||||||
- Add test e2e `show title newsfeed` for newsfeed module.
|
- Add test e2e `show title newsfeed` for newsfeed module.
|
||||||
- Add task to check configuration file.
|
- Add task to check configuration file.
|
||||||
@ -475,11 +545,13 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Added Romanian translation.
|
- Added Romanian translation.
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Added missing keys to Polish translation.
|
- Added missing keys to Polish translation.
|
||||||
- Added missing key to German translation.
|
- Added missing key to German translation.
|
||||||
- Added better translation with flexible word order to Finnish translation.
|
- Added better translation with flexible word order to Finnish translation.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix instruction in README for using automatically installer script.
|
- Fix instruction in README for using automatically installer script.
|
||||||
- Bug of duplicated compliments as described in [here](https://forum.magicmirror.builders/topic/2381/compliments-module-stops-cycling-compliments).
|
- Bug of duplicated compliments as described in [here](https://forum.magicmirror.builders/topic/2381/compliments-module-stops-cycling-compliments).
|
||||||
- Fix double message about port when server is starting
|
- Fix double message about port when server is starting
|
||||||
@ -493,6 +565,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Add `anytime` group for Compliments module.
|
- Add `anytime` group for Compliments module.
|
||||||
- Compliments module can use remoteFile without default daytime arrays defined.
|
- Compliments module can use remoteFile without default daytime arrays defined.
|
||||||
- Installer: Use init config.js from config.js.sample.
|
- Installer: Use init config.js from config.js.sample.
|
||||||
@ -508,8 +581,9 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Restructured Test Suite.
|
- Restructured Test Suite.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added Docker support (Pull Request [#673](https://github.com/MichMich/MagicMirror/pull/673)).
|
- Added Docker support (Pull Request [#673](https://github.com/MichMich/MagicMirror/pull/673)).
|
||||||
- Calendar-specific support for `maximumEntries`, and ` maximumNumberOfDays`.
|
- Calendar-specific support for `maximumEntries`, and `maximumNumberOfDays`.
|
||||||
- Add loaded function to modules, providing an async callback.
|
- Add loaded function to modules, providing an async callback.
|
||||||
- Made default newsfeed module aware of gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
|
- Made default newsfeed module aware of gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
|
||||||
- Add use pm2 for manager process into Installer RaspberryPi script.
|
- Add use pm2 for manager process into Installer RaspberryPi script.
|
||||||
@ -550,11 +624,12 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Added a configurable Week section to the clock module.
|
- Added a configurable Week section to the clock module.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Update .gitignore to not ignore default modules folder.
|
- Update .gitignore to not ignore default modules folder.
|
||||||
- Remove white flash on boot up.
|
- Remove white flash on boot up.
|
||||||
- Added `update` in Raspberry Pi installation script.
|
- Added `update` in Raspberry Pi installation script.
|
||||||
- Fix an issue where the analog clock looked scrambled. ([#611](https://github.com/MichMich/MagicMirror/issues/611))
|
- Fix an issue where the analog clock looked scrambled. ([#611](https://github.com/MichMich/MagicMirror/issues/611))
|
||||||
- If units is set to imperial, the showRainAmount option of weatherforecast will show the correct unit.
|
- If units are set to imperial, the showRainAmount option of weatherforecast will show the correct unit.
|
||||||
- Module currentWeather: check if temperature received from api is defined.
|
- Module currentWeather: check if temperature received from api is defined.
|
||||||
- Fix an issue with module hidden status changing to `true` although lock string prevented showing it.
|
- Fix an issue with module hidden status changing to `true` although lock string prevented showing it.
|
||||||
- Fix newsfeed module bug (removeStartTags)
|
- Fix newsfeed module bug (removeStartTags)
|
||||||
@ -566,6 +641,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Finnish translation.
|
- Finnish translation.
|
||||||
- Danish translation.
|
- Danish translation.
|
||||||
- Turkish translation.
|
- Turkish translation.
|
||||||
@ -578,7 +654,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information.
|
- Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information.
|
||||||
- Module API: Option to define the minimum MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information.
|
- Module API: Option to define the minimum MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information.
|
||||||
- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information.
|
- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information.
|
||||||
- Possibility to use the the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information.
|
- Possibility to use the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information.
|
||||||
- Added option to show rain amount in the weatherforecast default module
|
- Added option to show rain amount in the weatherforecast default module
|
||||||
- Add module `updatenotification` to get an update whenever a new version is available. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information.
|
- Add module `updatenotification` to get an update whenever a new version is available. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information.
|
||||||
- Add the ability to set timezone on the date display in the Clock Module
|
- Add the ability to set timezone on the date display in the Clock Module
|
||||||
@ -586,7 +662,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Possibility to use currentweather for the compliments
|
- Possibility to use currentweather for the compliments
|
||||||
- Added option `disabled` for modules.
|
- Added option `disabled` for modules.
|
||||||
- Added option `address` to set bind address.
|
- Added option `address` to set bind address.
|
||||||
- Added option `onlyTemp` for currentweather module to show show only current temperature and weather icon.
|
- Added option `onlyTemp` for currentweather module to show only current temperature and weather icon.
|
||||||
- Added option `remoteFile` to compliments module to load compliment array from filesystem.
|
- Added option `remoteFile` to compliments module to load compliment array from filesystem.
|
||||||
- Added option `zoom` to scale the whole mirror display with a given factor.
|
- Added option `zoom` to scale the whole mirror display with a given factor.
|
||||||
- Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer.
|
- Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer.
|
||||||
@ -596,6 +672,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add root_path for global vars
|
- Add root_path for global vars
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Modified translations for Frysk.
|
- Modified translations for Frysk.
|
||||||
- Modified core English translations.
|
- Modified core English translations.
|
||||||
- Updated package.json as a result of Snyk security update.
|
- Updated package.json as a result of Snyk security update.
|
||||||
@ -606,6 +683,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Modules are now secure, and Helmet is now used to prevent abuse of the Mirror's API.
|
- Modules are now secure, and Helmet is now used to prevent abuse of the Mirror's API.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Solve an issue where module margins would appear when the first module of a section was hidden.
|
- Solve an issue where module margins would appear when the first module of a section was hidden.
|
||||||
- Solved visual display errors on chrome, if all modules in one of the right sections are hidden.
|
- Solved visual display errors on chrome, if all modules in one of the right sections are hidden.
|
||||||
- Global and Module default config values are no longer modified when setting config values.
|
- Global and Module default config values are no longer modified when setting config values.
|
||||||
@ -616,6 +694,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
## [2.0.5] - 2016-09-20
|
## [2.0.5] - 2016-09-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added ability to remove tags from the beginning or end of newsfeed items in 'newsfeed.js'.
|
- Added ability to remove tags from the beginning or end of newsfeed items in 'newsfeed.js'.
|
||||||
- Added ability to define "the day after tomorrow" for calendar events (Definition for German and Dutch already included).
|
- Added ability to define "the day after tomorrow" for calendar events (Definition for German and Dutch already included).
|
||||||
- Added CII Badge (we are compliant with the CII Best Practices)
|
- Added CII Badge (we are compliant with the CII Best Practices)
|
||||||
@ -623,11 +702,13 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Add the ability to turn off and on the date display in the Clock Module
|
- Add the ability to turn off and on the date display in the Clock Module
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix typo in installer.
|
- Fix typo in installer.
|
||||||
- Add message to unsupported Pi error to mention that Pi Zeros must use server only mode, as ARMv6 is unsupported. Closes #374.
|
- Add message to unsupported Pi error to mention that Pi Zeros must use server only mode, as ARMv6 is unsupported. Closes #374.
|
||||||
- Fix API url for weather API.
|
- Fix API url for weather API.
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Force fullscreen when kioskmode is active.
|
- Force fullscreen when kioskmode is active.
|
||||||
- Update the .github templates and information with more modern information.
|
- Update the .github templates and information with more modern information.
|
||||||
- Update the Gruntfile with a more functional StyleLint implementation.
|
- Update the Gruntfile with a more functional StyleLint implementation.
|
||||||
@ -635,6 +716,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
## [2.0.4] - 2016-08-07
|
## [2.0.4] - 2016-08-07
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Brazilian Portuguese Translation.
|
- Brazilian Portuguese Translation.
|
||||||
- Option to enable Kiosk mode.
|
- Option to enable Kiosk mode.
|
||||||
- Added ability to start the app with Dev Tools.
|
- Added ability to start the app with Dev Tools.
|
||||||
@ -642,6 +724,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Greek Translation
|
- Greek Translation
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Prevent `getModules()` selectors from returning duplicate entries.
|
- Prevent `getModules()` selectors from returning duplicate entries.
|
||||||
- Append endpoints of weather modules with `/` to retrieve the correct data. (Issue [#337](https://github.com/MichMich/MagicMirror/issues/337))
|
- Append endpoints of weather modules with `/` to retrieve the correct data. (Issue [#337](https://github.com/MichMich/MagicMirror/issues/337))
|
||||||
- Corrected grammar in `module.js` from 'suspend' to 'suspended'.
|
- Corrected grammar in `module.js` from 'suspend' to 'suspended'.
|
||||||
@ -650,55 +733,72 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
|
|||||||
- Fix issue where translation loading prevented the UI start-up when the language was set to 'en'. (Issue [#388](https://github.com/MichMich/MagicMirror/issues/388))
|
- Fix issue where translation loading prevented the UI start-up when the language was set to 'en'. (Issue [#388](https://github.com/MichMich/MagicMirror/issues/388))
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Updated package.json to fix possible vulnerabilities. (Using Snyk)
|
- Updated package.json to fix possible vulnerabilities. (Using Snyk)
|
||||||
- Updated weathericons
|
- Updated weathericons
|
||||||
- Updated default weatherforecast to work with the new icons.
|
- Updated default weatherforecast to work with the new icons.
|
||||||
- More detailed error message in case config file couldn't be loaded.
|
- More detailed error message in case config file couldn't be loaded.
|
||||||
|
|
||||||
## [2.0.3] - 2016-07-12
|
## [2.0.3] - 2016-07-12
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add max newsitems parameter to the newsfeed module.
|
- Add max newsitems parameter to the newsfeed module.
|
||||||
- Translations for Simplified Chinese, Traditional Chinese and Japanese.
|
- Translations for Simplified Chinese, Traditional Chinese and Japanese.
|
||||||
- Polish Translation
|
- Polish Translation
|
||||||
- Add an analog clock in addition to the digital one.
|
- Add an analog clock in addition to the digital one.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Edit Alert Module to display title & message if they are provided in the notification (Issue [#300](https://github.com/MichMich/MagicMirror/issues/300))
|
- Edit Alert Module to display title & message if they are provided in the notification (Issue [#300](https://github.com/MichMich/MagicMirror/issues/300))
|
||||||
- Removed 'null' reference from updateModuleContent(). This fixes recent Edge and Internet Explorer browser displays (Issue [#319](https://github.com/MichMich/MagicMirror/issues/319))
|
- Removed 'null' reference from updateModuleContent(). This fixes recent Edge and Internet Explorer browser displays (Issue [#319](https://github.com/MichMich/MagicMirror/issues/319))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Added default string to calendar titleReplace.
|
- Added default string to calendar titleReplace.
|
||||||
|
|
||||||
## [2.0.2] - 2016-06-05
|
## [2.0.2] - 2016-06-05
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Norwegian Translations (nb and nn)
|
- Norwegian Translations (nb and nn)
|
||||||
- Portuguese Translation
|
- Portuguese Translation
|
||||||
- Swedish Translation
|
- Swedish Translation
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Added reference to Italian Translation.
|
- Added reference to Italian Translation.
|
||||||
- Added the missing NE translation to all languages. [#344](https://github.com/MichMich/MagicMirror/issues/344)
|
- Added the missing NE translation to all languages. [#344](https://github.com/MichMich/MagicMirror/issues/344)
|
||||||
- Added proper User-Agent string to calendar call.
|
- Added proper User-Agent string to calendar call.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Add option to use locationID in weather modules.
|
- Add option to use locationID in weather modules.
|
||||||
|
|
||||||
## [2.0.1] - 2016-05-18
|
## [2.0.1] - 2016-05-18
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Changelog
|
- Changelog
|
||||||
- Italian Translation
|
- Italian Translation
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Improve the installer by fetching the latest Node.js without any 3rd party interferences.
|
- Improve the installer by fetching the latest Node.js without any 3rd party interferences.
|
||||||
|
|
||||||
## [2.0.0] - 2016-05-03
|
## [2.0.0] - 2016-05-03
|
||||||
|
|
||||||
### Initial release of MagicMirror²
|
### Initial release of MagicMirror²
|
||||||
|
|
||||||
It includes (but is not limited to) the following features:
|
It includes (but is not limited to) the following features:
|
||||||
|
|
||||||
- Modular system allowing 3rd party plugins.
|
- Modular system allowing 3rd party plugins.
|
||||||
- An Node/Electron based application taking away the need for external servers or browsers.
|
- An Node/Electron based application taking away the need for external servers or browsers.
|
||||||
- A complete development API documentation.
|
- A complete development API documentation.
|
||||||
- Small cute fairies that kiss you while you sleep.
|
- Small cute fairies that kiss you while you sleep.
|
||||||
|
|
||||||
## [1.0.0] - 2014-02-16
|
## [1.0.0] - 2014-02-16
|
||||||
|
|
||||||
### Initial release of MagicMirror.
|
### Initial release of MagicMirror.
|
||||||
This was part of the blogpost: [http://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the](http://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the)
|
|
||||||
|
This was part of the blogpost: [https://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the](https://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the)
|
||||||
|
106
Gruntfile.js
@ -1,106 +0,0 @@
|
|||||||
module.exports = function(grunt) {
|
|
||||||
require("time-grunt")(grunt);
|
|
||||||
var fix = (grunt.option("env") || "lint") === "lint";
|
|
||||||
grunt.initConfig({
|
|
||||||
eslint: {
|
|
||||||
options: {
|
|
||||||
fix: fix,
|
|
||||||
configFile: ".eslintrc.json"
|
|
||||||
},
|
|
||||||
target: [
|
|
||||||
"js/*.js",
|
|
||||||
"modules/default/*.js",
|
|
||||||
"modules/default/*/*.js",
|
|
||||||
"serveronly/*.js",
|
|
||||||
"clientonly/*.js",
|
|
||||||
"*.js",
|
|
||||||
"tests/**/*.js",
|
|
||||||
"!modules/default/alert/notificationFx.js",
|
|
||||||
"!modules/default/alert/modernizr.custom.js",
|
|
||||||
"!modules/default/alert/classie.js",
|
|
||||||
"config/*",
|
|
||||||
"translations/translations.js",
|
|
||||||
"vendor/vendor.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
stylelint: {
|
|
||||||
simple: {
|
|
||||||
options: {
|
|
||||||
fix: fix,
|
|
||||||
configFile: ".stylelintrc.json"
|
|
||||||
},
|
|
||||||
src: [
|
|
||||||
"css/main.css",
|
|
||||||
"modules/default/calendar/calendar.css",
|
|
||||||
"modules/default/clock/clock_styles.css",
|
|
||||||
"modules/default/currentweather/currentweather.css",
|
|
||||||
"modules/default/weatherforcast/weatherforcast.css"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
jsonlint: {
|
|
||||||
main: {
|
|
||||||
src: [
|
|
||||||
"package.json",
|
|
||||||
".eslintrc.json",
|
|
||||||
".stylelintrc.json",
|
|
||||||
"translations/*.json",
|
|
||||||
"modules/default/*/translations/*.json",
|
|
||||||
"vendor/package.json"
|
|
||||||
],
|
|
||||||
options: {
|
|
||||||
reporter: "jshint"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
markdownlint: {
|
|
||||||
all: {
|
|
||||||
options: {
|
|
||||||
config: {
|
|
||||||
"default": true,
|
|
||||||
"line-length": false,
|
|
||||||
"blanks-around-headers": false,
|
|
||||||
"no-duplicate-header": false,
|
|
||||||
"no-inline-html": false,
|
|
||||||
"MD010": false,
|
|
||||||
"MD001": false,
|
|
||||||
"MD031": false,
|
|
||||||
"MD040": false,
|
|
||||||
"MD002": false,
|
|
||||||
"MD029": false,
|
|
||||||
"MD041": false,
|
|
||||||
"MD032": false,
|
|
||||||
"MD036": false,
|
|
||||||
"MD037": false,
|
|
||||||
"MD009": false,
|
|
||||||
"MD018": false,
|
|
||||||
"MD012": false,
|
|
||||||
"MD026": false,
|
|
||||||
"MD038": false,
|
|
||||||
"MD047": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
src: [
|
|
||||||
"README.md",
|
|
||||||
"CHANGELOG.md",
|
|
||||||
"LICENSE.md",
|
|
||||||
"modules/README.md",
|
|
||||||
"modules/default/**/*.md",
|
|
||||||
"!modules/default/calendar/vendor/ical.js/readme.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
yamllint: {
|
|
||||||
all: [
|
|
||||||
".travis.yml"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
grunt.loadNpmTasks("grunt-eslint");
|
|
||||||
grunt.loadNpmTasks("grunt-stylelint");
|
|
||||||
grunt.loadNpmTasks("grunt-jsonlint");
|
|
||||||
grunt.loadNpmTasks("grunt-yamllint");
|
|
||||||
grunt.loadNpmTasks("grunt-markdownlint");
|
|
||||||
|
|
||||||
grunt.registerTask("default", ["eslint", "stylelint", "jsonlint", "markdownlint", "yamllint"]);
|
|
||||||
};
|
|
@ -1,5 +1,4 @@
|
|||||||
The MIT License (MIT)
|
# The MIT License (MIT)
|
||||||
=====================
|
|
||||||
|
|
||||||
Copyright © 2016-2019 Michael Teeuw
|
Copyright © 2016-2019 Michael Teeuw
|
||||||
|
|
||||||
|
@ -4,19 +4,21 @@
|
|||||||
<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"><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://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"></a>
|
||||||
<a href="http://choosealicense.com/licenses/mit"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></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://travis-ci.com/MichMich/MagicMirror"><img src="https://travis-ci.com/MichMich/MagicMirror.svg" alt="Travis"></a>
|
<a href="https://travis-ci.com/MichMich/MagicMirror"><img src="https://travis-ci.com/MichMich/MagicMirror.svg" alt="Travis"></a>
|
||||||
<a href="https://snyk.io/test/github/MichMich/MagicMirror"><img src="https://snyk.io/test/github/MichMich/MagicMirror/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/MichMich/MagicMirror" style="max-width:100%;"></a>
|
<a href="https://snyk.io/test/github/MichMich/MagicMirror"><img src="https://snyk.io/test/github/MichMich/MagicMirror/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/MichMich/MagicMirror" style="max-width:100%;"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
**MagicMirror²** is an open source modular smart mirror platform. With a growing list of installable modules, the **MagicMirror²** allows you to convert your hallway or bathroom mirror into your personal assistant. **MagicMirror²** is built by the creator of [the original MagicMirror](http://michaelteeuw.nl/tagged/magicmirror) with the incredible help of a [growing community of contributors](https://github.com/MichMich/MagicMirror/graphs/contributors).
|
**MagicMirror²** is an open source modular smart mirror platform. With a growing list of installable modules, the **MagicMirror²** allows you to convert your hallway or bathroom mirror into your personal assistant. **MagicMirror²** is built by the creator of [the original MagicMirror](https://michaelteeuw.nl/tagged/magicmirror) with the incredible help of a [growing community of contributors](https://github.com/MichMich/MagicMirror/graphs/contributors).
|
||||||
|
|
||||||
MagicMirror² focuses on a modular plugin system and uses [Electron](http://electron.atom.io/) as an application wrapper. So no more web server or browser installs necessary!
|
MagicMirror² focuses on a modular plugin system and uses [Electron](https://www.electronjs.org/) as an application wrapper. So no more web server or browser installs necessary!
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
For the full documentation including **[installation instructions](https://docs.magicmirror.builders/getting-started/installation.html)**, please visit our dedicated documentation website: [https://docs.magicmirror.builders](https://docs.magicmirror.builders).
|
For the full documentation including **[installation instructions](https://docs.magicmirror.builders/getting-started/installation.html)**, please visit our dedicated documentation website: [https://docs.magicmirror.builders](https://docs.magicmirror.builders).
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
- Website: [https://magicmirror.builders](https://magicmirror.builders)
|
- Website: [https://magicmirror.builders](https://magicmirror.builders)
|
||||||
- Documentation: [https://docs.magicmirror.builders](https://docs.magicmirror.builders)
|
- Documentation: [https://docs.magicmirror.builders](https://docs.magicmirror.builders)
|
||||||
- Forum: [https://forum.magicmirror.builders](https://forum.magicmirror.builders)
|
- Forum: [https://forum.magicmirror.builders](https://forum.magicmirror.builders)
|
||||||
@ -28,7 +30,6 @@ For the full documentation including **[installation instructions](https://docs.
|
|||||||
|
|
||||||
Contributions of all kinds are welcome, not only in the form of code but also with regards bug reports and documentation. For the full contribution guidelines, check out: [https://docs.magicmirror.builders/getting-started/contributing.html](https://docs.magicmirror.builders/getting-started/contributing.html)
|
Contributions of all kinds are welcome, not only in the form of code but also with regards bug reports and documentation. For the full contribution guidelines, check out: [https://docs.magicmirror.builders/getting-started/contributing.html](https://docs.magicmirror.builders/getting-started/contributing.html)
|
||||||
|
|
||||||
|
|
||||||
## Enjoying MagicMirror? Consider a donation!
|
## Enjoying MagicMirror? Consider a donation!
|
||||||
|
|
||||||
MagicMirror² is opensource and free. That doesn't mean we don't need any money.
|
MagicMirror² is opensource and free. That doesn't mean we don't need any money.
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
["address", "port"].forEach((key) => {
|
["address", "port"].forEach((key) => {
|
||||||
config[key] = getCommandLineParameter(key, process.env[key.toUpperCase()]);
|
config[key] = getCommandLineParameter(key, process.env[key.toUpperCase()]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// determine if "--use-tls"-flag was provided
|
||||||
|
config["tls"] = process.argv.indexOf("--use-tls") > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServerConfig(url) {
|
function getServerConfig(url) {
|
||||||
@ -29,16 +32,16 @@
|
|||||||
var configData = "";
|
var configData = "";
|
||||||
|
|
||||||
// Gather incoming data
|
// Gather incoming data
|
||||||
response.on("data", function(chunk) {
|
response.on("data", function (chunk) {
|
||||||
configData += chunk;
|
configData += chunk;
|
||||||
});
|
});
|
||||||
// Resolve promise at the end of the HTTP/HTTPS stream
|
// Resolve promise at the end of the HTTP/HTTPS stream
|
||||||
response.on("end", function() {
|
response.on("end", function () {
|
||||||
resolve(JSON.parse(configData));
|
resolve(JSON.parse(configData));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
request.on("error", function(error) {
|
request.on("error", function (error) {
|
||||||
reject(new Error(`Unable to read config from server (${url} (${error.message}`));
|
reject(new Error(`Unable to read config from server (${url} (${error.message}`));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -48,7 +51,7 @@
|
|||||||
if (message !== undefined && typeof message === "string") {
|
if (message !== undefined && typeof message === "string") {
|
||||||
console.log(message);
|
console.log(message);
|
||||||
} else {
|
} else {
|
||||||
console.log("Usage: 'node clientonly --address 192.168.1.10 --port 8080'");
|
console.log("Usage: 'node clientonly --address 192.168.1.10 --port 8080 [--use-tls]'");
|
||||||
}
|
}
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
}
|
}
|
||||||
@ -56,16 +59,18 @@
|
|||||||
getServerAddress();
|
getServerAddress();
|
||||||
|
|
||||||
(config.address && config.port) || fail();
|
(config.address && config.port) || fail();
|
||||||
|
var prefix = config.tls ? "https://" : "http://";
|
||||||
|
|
||||||
// Only start the client if a non-local server was provided
|
// Only start the client if a non-local server was provided
|
||||||
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].indexOf(config.address) === -1) {
|
||||||
getServerConfig(`http://${config.address}:${config.port}/config/`)
|
getServerConfig(`${prefix}${config.address}:${config.port}/config/`)
|
||||||
.then(function (configReturn) {
|
.then(function (configReturn) {
|
||||||
// Pass along the server config via an environment variable
|
// Pass along the server config via an environment variable
|
||||||
var env = Object.create(process.env);
|
var env = Object.create(process.env);
|
||||||
var options = { env: env };
|
var options = { env: env };
|
||||||
configReturn.address = config.address;
|
configReturn.address = config.address;
|
||||||
configReturn.port = config.port;
|
configReturn.port = config.port;
|
||||||
|
configReturn.tls = config.tls;
|
||||||
env.config = JSON.stringify(configReturn);
|
env.config = JSON.stringify(configReturn);
|
||||||
|
|
||||||
// Spawn electron application
|
// Spawn electron application
|
||||||
@ -91,7 +96,6 @@
|
|||||||
console.log(`There something wrong. The clientonly is not running code ${code}`);
|
console.log(`There something wrong. The clientonly is not running code ${code}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(function (reason) {
|
.catch(function (reason) {
|
||||||
fail(`Unable to connect to server: (${reason})`);
|
fail(`Unable to connect to server: (${reason})`);
|
||||||
@ -99,4 +103,4 @@
|
|||||||
} else {
|
} else {
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
}());
|
})();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* Magic Mirror Config Sample
|
/* Magic Mirror Config Sample
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*
|
*
|
||||||
* For more information on how you can configure this file
|
* For more information on how you can configure this file
|
||||||
@ -9,17 +9,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
address: "localhost", // Address to listen on, can be:
|
address: "localhost", // Address to listen on, can be:
|
||||||
// - "localhost", "127.0.0.1", "::1" to listen on loopback interface
|
// - "localhost", "127.0.0.1", "::1" to listen on loopback interface
|
||||||
// - another specific IPv4/6 to listen on a specific interface
|
// - another specific IPv4/6 to listen on a specific interface
|
||||||
// - "0.0.0.0", "::" to listen on any interface
|
// - "0.0.0.0", "::" to listen on any interface
|
||||||
// Default, when address config is left out or empty, is "localhost"
|
// Default, when address config is left out or empty, is "localhost"
|
||||||
port: 8080,
|
port: 8080,
|
||||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
|
basePath: "/", // The URL path where MagicMirror is hosted. If you are using a Reverse proxy
|
||||||
// or add a specific IPv4 of 192.168.1.5 :
|
// you must set the sub path here. basePath must end with a /
|
||||||
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"],
|
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
|
||||||
// or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format :
|
// or add a specific IPv4 of 192.168.1.5 :
|
||||||
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"],
|
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"],
|
||||||
|
// or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format :
|
||||||
|
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"],
|
||||||
|
|
||||||
useHttps: false, // Support HTTPS or not, default "false" will use HTTP
|
useHttps: false, // Support HTTPS or not, default "false" will use HTTP
|
||||||
httpsPrivateKey: "", // HTTPS private key path, only require when useHttps is true
|
httpsPrivateKey: "", // HTTPS private key path, only require when useHttps is true
|
||||||
@ -29,10 +31,10 @@ var config = {
|
|||||||
timeFormat: 24,
|
timeFormat: 24,
|
||||||
units: "metric",
|
units: "metric",
|
||||||
// serverOnly: true/false/"local" ,
|
// serverOnly: true/false/"local" ,
|
||||||
// local for armv6l processors, default
|
// local for armv6l processors, default
|
||||||
// starts serveronly and then starts chrome browser
|
// starts serveronly and then starts chrome browser
|
||||||
// false, default for all NON-armv6l devices
|
// false, default for all NON-armv6l devices
|
||||||
// true, force serveronly mode, because you want to.. no UI on this device
|
// true, force serveronly mode, because you want to.. no UI on this device
|
||||||
|
|
||||||
modules: [
|
modules: [
|
||||||
{
|
{
|
||||||
@ -88,7 +90,7 @@ var config = {
|
|||||||
feeds: [
|
feeds: [
|
||||||
{
|
{
|
||||||
title: "New York Times",
|
title: "New York Times",
|
||||||
url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml"
|
url: "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
showSourceTitle: true,
|
showSourceTitle: true,
|
||||||
@ -98,7 +100,6 @@ var config = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||||
|
@ -177,10 +177,6 @@ sup {
|
|||||||
.region.top.center,
|
.region.top.center,
|
||||||
.region.bottom.center {
|
.region.bottom.center {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
-moz-transform: translateX(-50%);
|
|
||||||
-o-transform: translateX(-50%);
|
|
||||||
-webkit-transform: translateX(-50%);
|
|
||||||
-ms-transform: translateX(-50%);
|
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,10 +209,6 @@ sup {
|
|||||||
.region.middle.center {
|
.region.middle.center {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
-moz-transform: translateY(-50%);
|
|
||||||
-o-transform: translateY(-50%);
|
|
||||||
-webkit-transform: translateY(-50%);
|
|
||||||
-ms-transform: translateY(-50%);
|
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
fonts/package-lock.json
generated
@ -4,9 +4,9 @@
|
|||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"roboto-fontface": {
|
"roboto-fontface": {
|
||||||
"version": "0.8.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz",
|
||||||
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
|
"integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "magicmirror-fonts",
|
"name": "magicmirror-fonts",
|
||||||
"description": "Package for fonts use by MagicMirror Core.",
|
"description": "Package for fonts use by MagicMirror Core.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/MichMich/MagicMirror.git"
|
"url": "git+https://github.com/MichMich/MagicMirror.git"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/MichMich/MagicMirror/issues"
|
"url": "https://github.com/MichMich/MagicMirror/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"roboto-fontface": "^0.8.0"
|
"roboto-fontface": "^0.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,94 +2,57 @@
|
|||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
src:
|
src: local("Roboto Thin"), local("Roboto-Thin"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff") format("woff");
|
||||||
local("Roboto Thin"),
|
|
||||||
local("Roboto-Thin"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Roboto Condensed";
|
font-family: "Roboto Condensed";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src:
|
src: local("Roboto Condensed Light"), local("RobotoCondensed-Light"), url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff2") format("woff2"),
|
||||||
local("Roboto Condensed Light"),
|
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff") format("woff");
|
||||||
local("RobotoCondensed-Light"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Roboto Condensed";
|
font-family: "Roboto Condensed";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src:
|
src: local("Roboto Condensed"), local("RobotoCondensed-Regular"), url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff2") format("woff2"),
|
||||||
local("Roboto Condensed"),
|
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff") format("woff");
|
||||||
local("RobotoCondensed-Regular"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Roboto Condensed";
|
font-family: "Roboto Condensed";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src:
|
src: local("Roboto Condensed Bold"), local("RobotoCondensed-Bold"), url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff2") format("woff2"),
|
||||||
local("Roboto Condensed Bold"),
|
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff") format("woff");
|
||||||
local("RobotoCondensed-Bold"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src:
|
src: local("Roboto"), local("Roboto-Regular"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff") format("woff");
|
||||||
local("Roboto"),
|
|
||||||
local("Roboto-Regular"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
src:
|
src: local("Roboto Medium"), local("Roboto-Medium"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff") format("woff");
|
||||||
local("Roboto Medium"),
|
|
||||||
local("Roboto-Medium"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src:
|
src: local("Roboto Bold"), local("Roboto-Bold"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff") format("woff");
|
||||||
local("Roboto Bold"),
|
|
||||||
local("Roboto-Bold"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
src:
|
src: local("Roboto Light"), local("Roboto-Light"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff2") format("woff2"), url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff") format("woff");
|
||||||
local("Roboto Light"),
|
|
||||||
local("Roboto-Light"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff2") format("woff2"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff") format("woff"),
|
|
||||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.ttf") format("truetype");
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
roboto-fontface@^0.8.0:
|
|
||||||
version "0.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/roboto-fontface/-/roboto-fontface-0.8.0.tgz#031a83c8f79932801a57d83bf743f37250163499"
|
|
48
js/app.js
@ -1,7 +1,7 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* The Core App (Server)
|
* The Core App (Server)
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
@ -44,7 +44,7 @@ process.on("uncaughtException", function (err) {
|
|||||||
|
|
||||||
/* App - The core app.
|
/* App - The core app.
|
||||||
*/
|
*/
|
||||||
var App = function() {
|
var App = function () {
|
||||||
var nodeHelpers = [];
|
var nodeHelpers = [];
|
||||||
|
|
||||||
/* loadConfig(callback)
|
/* loadConfig(callback)
|
||||||
@ -53,15 +53,15 @@ var App = function() {
|
|||||||
*
|
*
|
||||||
* argument callback function - The callback function.
|
* argument callback function - The callback function.
|
||||||
*/
|
*/
|
||||||
var loadConfig = function(callback) {
|
var loadConfig = function (callback) {
|
||||||
console.log("Loading config ...");
|
console.log("Loading config ...");
|
||||||
var defaults = require(__dirname + "/defaults.js");
|
var defaults = require(__dirname + "/defaults.js");
|
||||||
|
|
||||||
// For this check proposed to TestSuite
|
// For this check proposed to TestSuite
|
||||||
// https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8
|
// https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8
|
||||||
var configFilename = path.resolve(global.root_path + "/config/config.js");
|
var configFilename = path.resolve(global.root_path + "/config/config.js");
|
||||||
if (typeof(global.configuration_file) !== "undefined") {
|
if (typeof global.configuration_file !== "undefined") {
|
||||||
configFilename = path.resolve(global.configuration_file);
|
configFilename = path.resolve(global.configuration_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -82,23 +82,19 @@ var App = function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var checkDeprecatedOptions = function(userConfig) {
|
var checkDeprecatedOptions = function (userConfig) {
|
||||||
var deprecated = require(global.root_path + "/js/deprecated.js");
|
var deprecated = require(global.root_path + "/js/deprecated.js");
|
||||||
var deprecatedOptions = deprecated.configs;
|
var deprecatedOptions = deprecated.configs;
|
||||||
|
|
||||||
var usedDeprecated = [];
|
var usedDeprecated = [];
|
||||||
|
|
||||||
deprecatedOptions.forEach(function(option) {
|
deprecatedOptions.forEach(function (option) {
|
||||||
if (userConfig.hasOwnProperty(option)) {
|
if (userConfig.hasOwnProperty(option)) {
|
||||||
usedDeprecated.push(option);
|
usedDeprecated.push(option);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (usedDeprecated.length > 0) {
|
if (usedDeprecated.length > 0) {
|
||||||
console.warn(Utils.colors.warn(
|
console.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."));
|
||||||
"WARNING! Your config is using deprecated options: " +
|
|
||||||
usedDeprecated.join(", ") +
|
|
||||||
". Check README and CHANGELOG for more up-to-date ways of getting the same functionality.")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,8 +103,7 @@ var App = function() {
|
|||||||
*
|
*
|
||||||
* argument module string - The name of the module (including subpath).
|
* argument module string - The name of the module (including subpath).
|
||||||
*/
|
*/
|
||||||
var loadModule = function(module, callback) {
|
var loadModule = function (module, callback) {
|
||||||
|
|
||||||
var elements = module.split("/");
|
var elements = module.split("/");
|
||||||
var moduleName = elements[elements.length - 1];
|
var moduleName = elements[elements.length - 1];
|
||||||
var moduleFolder = __dirname + "/../modules/" + module;
|
var moduleFolder = __dirname + "/../modules/" + module;
|
||||||
@ -156,13 +151,13 @@ var App = function() {
|
|||||||
*
|
*
|
||||||
* argument module string - The name of the module (including subpath).
|
* argument module string - The name of the module (including subpath).
|
||||||
*/
|
*/
|
||||||
var loadModules = function(modules, callback) {
|
var loadModules = function (modules, callback) {
|
||||||
console.log("Loading module helpers ...");
|
console.log("Loading module helpers ...");
|
||||||
|
|
||||||
var loadNextModule = function() {
|
var loadNextModule = function () {
|
||||||
if (modules.length > 0) {
|
if (modules.length > 0) {
|
||||||
var nextModule = modules[0];
|
var nextModule = modules[0];
|
||||||
loadModule(nextModule, function() {
|
loadModule(nextModule, function () {
|
||||||
modules = modules.slice(1);
|
modules = modules.slice(1);
|
||||||
loadNextModule();
|
loadNextModule();
|
||||||
});
|
});
|
||||||
@ -205,9 +200,8 @@ var App = function() {
|
|||||||
*
|
*
|
||||||
* argument callback function - The callback function.
|
* argument callback function - The callback function.
|
||||||
*/
|
*/
|
||||||
this.start = function(callback) {
|
this.start = function (callback) {
|
||||||
|
loadConfig(function (c) {
|
||||||
loadConfig(function(c) {
|
|
||||||
config = c;
|
config = c;
|
||||||
|
|
||||||
var modules = [];
|
var modules = [];
|
||||||
@ -219,8 +213,8 @@ var App = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadModules(modules, function() {
|
loadModules(modules, function () {
|
||||||
var server = new Server(config, function(app, io) {
|
var server = new Server(config, function (app, io) {
|
||||||
console.log("Server started ...");
|
console.log("Server started ...");
|
||||||
|
|
||||||
for (var h in nodeHelpers) {
|
for (var h in nodeHelpers) {
|
||||||
@ -245,7 +239,7 @@ var App = function() {
|
|||||||
* This calls each node_helper's STOP() function, if it exists.
|
* This calls each node_helper's STOP() function, if it exists.
|
||||||
* Added to fix #1056
|
* Added to fix #1056
|
||||||
*/
|
*/
|
||||||
this.stop = function() {
|
this.stop = function () {
|
||||||
for (var h in nodeHelpers) {
|
for (var h in nodeHelpers) {
|
||||||
var nodeHelper = nodeHelpers[h];
|
var nodeHelper = nodeHelpers[h];
|
||||||
if (typeof nodeHelper.stop === "function") {
|
if (typeof nodeHelper.stop === "function") {
|
||||||
@ -262,7 +256,9 @@ var App = function() {
|
|||||||
*/
|
*/
|
||||||
process.on("SIGINT", () => {
|
process.on("SIGINT", () => {
|
||||||
console.log("[SIGINT] Received. Shutting down server...");
|
console.log("[SIGINT] Received. Shutting down server...");
|
||||||
setTimeout(() => { process.exit(0); }, 3000); // Force quit after 3 seconds
|
setTimeout(() => {
|
||||||
|
process.exit(0);
|
||||||
|
}, 3000); // Force quit after 3 seconds
|
||||||
this.stop();
|
this.stop();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
@ -271,7 +267,9 @@ var App = function() {
|
|||||||
*/
|
*/
|
||||||
process.on("SIGTERM", () => {
|
process.on("SIGTERM", () => {
|
||||||
console.log("[SIGTERM] Received. Shutting down server...");
|
console.log("[SIGTERM] Received. Shutting down server...");
|
||||||
setTimeout(() => { process.exit(0); }, 3000); // Force quit after 3 seconds
|
setTimeout(() => {
|
||||||
|
process.exit(0);
|
||||||
|
}, 3000); // Force quit after 3 seconds
|
||||||
this.stop();
|
this.stop();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
@ -11,11 +11,13 @@
|
|||||||
|
|
||||||
const Linter = require("eslint").Linter;
|
const Linter = require("eslint").Linter;
|
||||||
const linter = new Linter();
|
const linter = new Linter();
|
||||||
const config = require(__dirname + "/../../.eslintrc.json");
|
|
||||||
|
|
||||||
var path = require("path");
|
const path = require("path");
|
||||||
var fs = require("fs");
|
const fs = require("fs");
|
||||||
var Utils = require(__dirname + "/../../js/utils.js");
|
|
||||||
|
const rootPath = path.resolve(__dirname + "/../");
|
||||||
|
const config = require(rootPath + "/.eslintrc.json");
|
||||||
|
const Utils = require(rootPath + "/js/utils.js");
|
||||||
|
|
||||||
/* getConfigFile()
|
/* getConfigFile()
|
||||||
* Return string with path of configuration file
|
* Return string with path of configuration file
|
||||||
@ -23,8 +25,7 @@ var Utils = require(__dirname + "/../../js/utils.js");
|
|||||||
*/
|
*/
|
||||||
function getConfigFile() {
|
function getConfigFile() {
|
||||||
// FIXME: This function should be in core. Do you want refactor me ;) ?, be good!
|
// FIXME: This function should be in core. Do you want refactor me ;) ?, be good!
|
||||||
rootPath = path.resolve(__dirname + "/../../");
|
let configFileName = path.resolve(rootPath + "/config/config.js");
|
||||||
var configFileName = path.resolve(rootPath + "/config/config.js");
|
|
||||||
if (process.env.MM_CONFIG_FILE) {
|
if (process.env.MM_CONFIG_FILE) {
|
||||||
configFileName = path.resolve(process.env.MM_CONFIG_FILE);
|
configFileName = path.resolve(process.env.MM_CONFIG_FILE);
|
||||||
}
|
}
|
||||||
@ -32,7 +33,7 @@ function getConfigFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkConfigFile() {
|
function checkConfigFile() {
|
||||||
var configFileName = getConfigFile();
|
const configFileName = getConfigFile();
|
||||||
// Check if file is present
|
// Check if file is present
|
||||||
if (fs.existsSync(configFileName) === false) {
|
if (fs.existsSync(configFileName) === false) {
|
||||||
console.error(Utils.colors.error("File not found: "), configFileName);
|
console.error(Utils.colors.error("File not found: "), configFileName);
|
||||||
@ -49,24 +50,22 @@ function checkConfigFile() {
|
|||||||
// Validate syntax of the configuration file.
|
// Validate syntax of the configuration file.
|
||||||
// In case the there errors show messages and
|
// In case the there errors show messages and
|
||||||
// return
|
// return
|
||||||
console.info(Utils.colors.info("Checking file... ", configFileName));
|
console.info(Utils.colors.info("Checking file... "), configFileName);
|
||||||
// I'm not sure if all ever is utf-8
|
// I'm not sure if all ever is utf-8
|
||||||
fs.readFile(configFileName, "utf-8", function (err, data) {
|
fs.readFile(configFileName, "utf-8", function (err, data) {
|
||||||
if (err) { throw err; }
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
const messages = linter.verify(data, config);
|
const messages = linter.verify(data, config);
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
console.log("Your configuration file doesn't contain syntax errors :)");
|
console.log("Your configuration file doesn't contain syntax errors :)");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
errors = messages;
|
messages.forEach((error) => {
|
||||||
for (var idx in errors) {
|
|
||||||
error = errors[idx];
|
|
||||||
console.log("Line", error.line, "col", error.column, error.message);
|
console.log("Line", error.line, "col", error.column, error.message);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== "test") {
|
checkConfigFile();
|
||||||
checkConfigFile();
|
|
||||||
}
|
|
51
js/class.js
@ -1,15 +1,22 @@
|
|||||||
|
/* global Class, xyz */
|
||||||
|
|
||||||
/* Simple JavaScript Inheritance
|
/* Simple JavaScript Inheritance
|
||||||
* By John Resig http://ejohn.org/
|
* By John Resig https://johnresig.com/
|
||||||
|
*
|
||||||
|
* Inspired by base2 and Prototype
|
||||||
|
*
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Inspired by base2 and Prototype
|
|
||||||
(function () {
|
(function () {
|
||||||
var initializing = false;
|
var initializing = false;
|
||||||
var fnTest = /xyz/.test(function () { xyz; }) ? /\b_super\b/ : /.*/;
|
var fnTest = /xyz/.test(function () {
|
||||||
|
xyz;
|
||||||
|
})
|
||||||
|
? /\b_super\b/
|
||||||
|
: /.*/;
|
||||||
|
|
||||||
// The base Class implementation (does nothing)
|
// The base Class implementation (does nothing)
|
||||||
this.Class = function () { };
|
this.Class = function () {};
|
||||||
|
|
||||||
// Create a new Class that inherits from this class
|
// Create a new Class that inherits from this class
|
||||||
Class.extend = function (prop) {
|
Class.extend = function (prop) {
|
||||||
@ -22,30 +29,32 @@
|
|||||||
initializing = false;
|
initializing = false;
|
||||||
|
|
||||||
// Make a copy of all prototype properties, to prevent reference issues.
|
// Make a copy of all prototype properties, to prevent reference issues.
|
||||||
for (var name in prototype) {
|
for (var p in prototype) {
|
||||||
prototype[name] = cloneObject(prototype[name]);
|
prototype[p] = cloneObject(prototype[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the properties over onto the new prototype
|
// Copy the properties over onto the new prototype
|
||||||
for (var name in prop) {
|
for (var name in prop) {
|
||||||
// Check if we're overwriting an existing function
|
// Check if we're overwriting an existing function
|
||||||
prototype[name] = typeof prop[name] === "function" &&
|
prototype[name] =
|
||||||
typeof _super[name] === "function" && fnTest.test(prop[name]) ? (function (name, fn) {
|
typeof prop[name] === "function" && typeof _super[name] === "function" && fnTest.test(prop[name])
|
||||||
return function () {
|
? (function (name, fn) {
|
||||||
var tmp = this._super;
|
return function () {
|
||||||
|
var tmp = this._super;
|
||||||
|
|
||||||
// Add a new ._super() method that is the same method
|
// Add a new ._super() method that is the same method
|
||||||
// but on the super-class
|
// but on the super-class
|
||||||
this._super = _super[name];
|
this._super = _super[name];
|
||||||
|
|
||||||
// The method only need to be bound temporarily, so we
|
// The method only need to be bound temporarily, so we
|
||||||
// remove it when we're done executing
|
// remove it when we're done executing
|
||||||
var ret = fn.apply(this, arguments);
|
var ret = fn.apply(this, arguments);
|
||||||
this._super = tmp;
|
this._super = tmp;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
})(name, prop[name]) : prop[name];
|
})(name, prop[name])
|
||||||
|
: prop[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
// The dummy class constructor
|
// The dummy class constructor
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
/* exported defaults */
|
/* global mmPort */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Config Defauls
|
* Config Defaults
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var port = 8080;
|
|
||||||
var address = "localhost";
|
var address = "localhost";
|
||||||
if (typeof(mmPort) !== "undefined") {
|
var port = 8080;
|
||||||
|
if (typeof mmPort !== "undefined") {
|
||||||
port = mmPort;
|
port = mmPort;
|
||||||
}
|
}
|
||||||
var defaults = {
|
var defaults = {
|
||||||
address: address,
|
address: address,
|
||||||
port: port,
|
port: port,
|
||||||
|
basePath: "/",
|
||||||
kioskmode: false,
|
kioskmode: false,
|
||||||
electronOptions: {},
|
electronOptions: {},
|
||||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||||
@ -68,14 +68,16 @@ var defaults = {
|
|||||||
config: {
|
config: {
|
||||||
text: "www.michaelteeuw.nl"
|
text: "www.michaelteeuw.nl"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
paths: {
|
paths: {
|
||||||
modules: "modules",
|
modules: "modules",
|
||||||
vendor: "vendor"
|
vendor: "vendor"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||||
if (typeof module !== "undefined") {module.exports = defaults;}
|
if (typeof module !== "undefined") {
|
||||||
|
module.exports = defaults;
|
||||||
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
/* Magic Mirror Deprecated Config Options List
|
/* Magic Mirror Deprecated Config Options List
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*
|
*
|
||||||
* Olex S. original idea this deprecated option
|
* Olex S. original idea this deprecated option
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var deprecated = {
|
var deprecated = {
|
||||||
configs: ["kioskmode"],
|
configs: ["kioskmode"]
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||||
if (typeof module !== "undefined") {module.exports = deprecated;}
|
if (typeof module !== "undefined") {
|
||||||
|
module.exports = deprecated;
|
||||||
|
}
|
||||||
|
@ -45,8 +45,16 @@ function createWindow() {
|
|||||||
|
|
||||||
// and load the index.html of the app.
|
// 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
|
// If config.address is not defined or is an empty string (listening on all interfaces), connect to localhost
|
||||||
|
|
||||||
|
var 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;
|
var address = (config.address === void 0) | (config.address === "") ? (config.address = "localhost") : config.address;
|
||||||
mainWindow.loadURL(`http://${address}:${config.port}`);
|
mainWindow.loadURL(`${prefix}${address}:${config.port}`);
|
||||||
|
|
||||||
// Open the DevTools if run with "npm start dev"
|
// Open the DevTools if run with "npm start dev"
|
||||||
if (process.argv.includes("dev")) {
|
if (process.argv.includes("dev")) {
|
||||||
@ -54,21 +62,21 @@ function createWindow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set responders for window events.
|
// Set responders for window events.
|
||||||
mainWindow.on("closed", function() {
|
mainWindow.on("closed", function () {
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (config.kioskmode) {
|
if (config.kioskmode) {
|
||||||
mainWindow.on("blur", function() {
|
mainWindow.on("blur", function () {
|
||||||
mainWindow.focus();
|
mainWindow.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.on("leave-full-screen", function() {
|
mainWindow.on("leave-full-screen", function () {
|
||||||
mainWindow.setFullScreen(true);
|
mainWindow.setFullScreen(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.on("resize", function() {
|
mainWindow.on("resize", function () {
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
mainWindow.reload();
|
mainWindow.reload();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
@ -77,17 +85,17 @@ function createWindow() {
|
|||||||
|
|
||||||
// This method will be called when Electron has finished
|
// This method will be called when Electron has finished
|
||||||
// initialization and is ready to create browser windows.
|
// initialization and is ready to create browser windows.
|
||||||
app.on("ready", function() {
|
app.on("ready", function () {
|
||||||
console.log("Launching application.");
|
console.log("Launching application.");
|
||||||
createWindow();
|
createWindow();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on("window-all-closed", function() {
|
app.on("window-all-closed", function () {
|
||||||
createWindow();
|
createWindow();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on("activate", function() {
|
app.on("activate", function () {
|
||||||
// On OS X it's common to re-create a window in the app when the
|
// On OS X it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
if (mainWindow === null) {
|
if (mainWindow === null) {
|
||||||
@ -104,7 +112,9 @@ app.on("activate", function() {
|
|||||||
app.on("before-quit", (event) => {
|
app.on("before-quit", (event) => {
|
||||||
console.log("Shutting down server...");
|
console.log("Shutting down server...");
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setTimeout(() => { process.exit(0); }, 3000); // Force-quit after 3 seconds.
|
setTimeout(() => {
|
||||||
|
process.exit(0);
|
||||||
|
}, 3000); // Force-quit after 3 seconds.
|
||||||
core.stop();
|
core.stop();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
@ -112,7 +122,7 @@ app.on("before-quit", (event) => {
|
|||||||
// Start the core application if server is run on localhost
|
// Start the core application if server is run on localhost
|
||||||
// This starts all node helpers and starts the webserver.
|
// 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].indexOf(config.address) > -1) {
|
||||||
core.start(function(c) {
|
core.start(function (c) {
|
||||||
config = c;
|
config = c;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
120
js/loader.js
@ -1,13 +1,12 @@
|
|||||||
/* global config, vendor, MM, Log, Module */
|
/* global defaultModules, vendor */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module and File loaders.
|
* Module and File loaders.
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
var Loader = (function () {
|
||||||
var Loader = (function() {
|
|
||||||
|
|
||||||
/* Create helper variables */
|
/* Create helper variables */
|
||||||
|
|
||||||
var loadedModuleFiles = [];
|
var loadedModuleFiles = [];
|
||||||
@ -19,14 +18,13 @@ var Loader = (function() {
|
|||||||
/* loadModules()
|
/* loadModules()
|
||||||
* Loops thru all modules and requests load for every module.
|
* Loops thru all modules and requests load for every module.
|
||||||
*/
|
*/
|
||||||
var loadModules = function() {
|
var loadModules = function () {
|
||||||
|
|
||||||
var moduleData = getModuleData();
|
var moduleData = getModuleData();
|
||||||
|
|
||||||
var loadNextModule = function() {
|
var loadNextModule = function () {
|
||||||
if (moduleData.length > 0) {
|
if (moduleData.length > 0) {
|
||||||
var nextModule = moduleData[0];
|
var nextModule = moduleData[0];
|
||||||
loadModule(nextModule, function() {
|
loadModule(nextModule, function () {
|
||||||
moduleData = moduleData.slice(1);
|
moduleData = moduleData.slice(1);
|
||||||
loadNextModule();
|
loadNextModule();
|
||||||
});
|
});
|
||||||
@ -35,11 +33,10 @@ var Loader = (function() {
|
|||||||
// This is done after all the modules so we can
|
// This is done after all the modules so we can
|
||||||
// overwrite all the defined styles.
|
// overwrite all the defined styles.
|
||||||
|
|
||||||
loadFile(config.customCss, function() {
|
loadFile(config.customCss, function () {
|
||||||
// custom.css loaded. Start all modules.
|
// custom.css loaded. Start all modules.
|
||||||
startModules();
|
startModules();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,7 +46,7 @@ var Loader = (function() {
|
|||||||
/* startModules()
|
/* startModules()
|
||||||
* Loops thru all modules and requests start for every module.
|
* Loops thru all modules and requests start for every module.
|
||||||
*/
|
*/
|
||||||
var startModules = function() {
|
var startModules = function () {
|
||||||
for (var m in moduleObjects) {
|
for (var m in moduleObjects) {
|
||||||
var module = moduleObjects[m];
|
var module = moduleObjects[m];
|
||||||
module.start();
|
module.start();
|
||||||
@ -64,7 +61,7 @@ var Loader = (function() {
|
|||||||
*
|
*
|
||||||
* return array - module data as configured in config
|
* return array - module data as configured in config
|
||||||
*/
|
*/
|
||||||
var getAllModules = function() {
|
var getAllModules = function () {
|
||||||
return config.modules;
|
return config.modules;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,7 +70,7 @@ var Loader = (function() {
|
|||||||
*
|
*
|
||||||
* return array - Module information.
|
* return array - Module information.
|
||||||
*/
|
*/
|
||||||
var getModuleData = function() {
|
var getModuleData = function () {
|
||||||
var modules = getAllModules();
|
var modules = getAllModules();
|
||||||
var moduleFiles = [];
|
var moduleFiles = [];
|
||||||
|
|
||||||
@ -97,12 +94,12 @@ var Loader = (function() {
|
|||||||
index: m,
|
index: m,
|
||||||
identifier: "module_" + m + "_" + module,
|
identifier: "module_" + m + "_" + module,
|
||||||
name: moduleName,
|
name: moduleName,
|
||||||
path: moduleFolder + "/" ,
|
path: moduleFolder + "/",
|
||||||
file: moduleName + ".js",
|
file: moduleName + ".js",
|
||||||
position: moduleData.position,
|
position: moduleData.position,
|
||||||
header: moduleData.header,
|
header: moduleData.header,
|
||||||
config: moduleData.config,
|
config: moduleData.config,
|
||||||
classes: (typeof moduleData.classes !== "undefined") ? moduleData.classes + " " + module : module
|
classes: typeof moduleData.classes !== "undefined" ? moduleData.classes + " " + module : module
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,13 +112,13 @@ var Loader = (function() {
|
|||||||
* argument callback function - Function called when done.
|
* argument callback function - Function called when done.
|
||||||
* argument module object - Information about the module we want to load.
|
* argument module object - Information about the module we want to load.
|
||||||
*/
|
*/
|
||||||
var loadModule = function(module, callback) {
|
var loadModule = function (module, callback) {
|
||||||
var url = module.path + "/" + module.file;
|
var url = module.path + "/" + module.file;
|
||||||
|
|
||||||
var afterLoad = function() {
|
var afterLoad = function () {
|
||||||
var moduleObject = Module.create(module.name);
|
var moduleObject = Module.create(module.name);
|
||||||
if (moduleObject) {
|
if (moduleObject) {
|
||||||
bootstrapModule(module, moduleObject, function() {
|
bootstrapModule(module, moduleObject, function () {
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -132,7 +129,7 @@ var Loader = (function() {
|
|||||||
if (loadedModuleFiles.indexOf(url) !== -1) {
|
if (loadedModuleFiles.indexOf(url) !== -1) {
|
||||||
afterLoad();
|
afterLoad();
|
||||||
} else {
|
} else {
|
||||||
loadFile(url, function() {
|
loadFile(url, function () {
|
||||||
loadedModuleFiles.push(url);
|
loadedModuleFiles.push(url);
|
||||||
afterLoad();
|
afterLoad();
|
||||||
});
|
});
|
||||||
@ -146,16 +143,16 @@ var Loader = (function() {
|
|||||||
* argument mObj object - Modules instance.
|
* argument mObj object - Modules instance.
|
||||||
* argument callback function - Function called when done.
|
* argument callback function - Function called when done.
|
||||||
*/
|
*/
|
||||||
var bootstrapModule = function(module, mObj, callback) {
|
var bootstrapModule = function (module, mObj, callback) {
|
||||||
Log.info("Bootstrapping module: " + module.name);
|
Log.info("Bootstrapping module: " + module.name);
|
||||||
|
|
||||||
mObj.setData(module);
|
mObj.setData(module);
|
||||||
|
|
||||||
mObj.loadScripts(function() {
|
mObj.loadScripts(function () {
|
||||||
Log.log("Scripts loaded for: " + module.name);
|
Log.log("Scripts loaded for: " + module.name);
|
||||||
mObj.loadStyles(function() {
|
mObj.loadStyles(function () {
|
||||||
Log.log("Styles loaded for: " + module.name);
|
Log.log("Styles loaded for: " + module.name);
|
||||||
mObj.loadTranslations(function() {
|
mObj.loadTranslations(function () {
|
||||||
Log.log("Translations loaded for: " + module.name);
|
Log.log("Translations loaded for: " + module.name);
|
||||||
moduleObjects.push(mObj);
|
moduleObjects.push(mObj);
|
||||||
callback();
|
callback();
|
||||||
@ -170,52 +167,58 @@ var Loader = (function() {
|
|||||||
* argument fileName string - Path of the file we want to load.
|
* argument fileName string - Path of the file we want to load.
|
||||||
* argument callback function - Function called when done.
|
* argument callback function - Function called when done.
|
||||||
*/
|
*/
|
||||||
var loadFile = function(fileName, callback) {
|
var loadFile = function (fileName, callback) {
|
||||||
|
|
||||||
var extension = fileName.slice((Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1);
|
var extension = fileName.slice((Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1);
|
||||||
|
|
||||||
switch (extension.toLowerCase()) {
|
switch (extension.toLowerCase()) {
|
||||||
case "js":
|
case "js":
|
||||||
Log.log("Load script: " + fileName);
|
Log.log("Load script: " + fileName);
|
||||||
var script = document.createElement("script");
|
var script = document.createElement("script");
|
||||||
script.type = "text/javascript";
|
script.type = "text/javascript";
|
||||||
script.src = fileName;
|
script.src = fileName;
|
||||||
script.onload = function() {
|
script.onload = function () {
|
||||||
if (typeof callback === "function") {callback();}
|
if (typeof callback === "function") {
|
||||||
};
|
callback();
|
||||||
script.onerror = function() {
|
}
|
||||||
console.error("Error on loading script:", fileName);
|
};
|
||||||
if (typeof callback === "function") {callback();}
|
script.onerror = function () {
|
||||||
};
|
console.error("Error on loading script:", fileName);
|
||||||
|
if (typeof callback === "function") {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
document.getElementsByTagName("body")[0].appendChild(script);
|
document.getElementsByTagName("body")[0].appendChild(script);
|
||||||
break;
|
break;
|
||||||
case "css":
|
case "css":
|
||||||
Log.log("Load stylesheet: " + fileName);
|
Log.log("Load stylesheet: " + fileName);
|
||||||
var stylesheet = document.createElement("link");
|
var stylesheet = document.createElement("link");
|
||||||
stylesheet.rel = "stylesheet";
|
stylesheet.rel = "stylesheet";
|
||||||
stylesheet.type = "text/css";
|
stylesheet.type = "text/css";
|
||||||
stylesheet.href = fileName;
|
stylesheet.href = fileName;
|
||||||
stylesheet.onload = function() {
|
stylesheet.onload = function () {
|
||||||
if (typeof callback === "function") {callback();}
|
if (typeof callback === "function") {
|
||||||
};
|
callback();
|
||||||
stylesheet.onerror = function() {
|
}
|
||||||
console.error("Error on loading stylesheet:", fileName);
|
};
|
||||||
if (typeof callback === "function") {callback();}
|
stylesheet.onerror = function () {
|
||||||
};
|
console.error("Error on loading stylesheet:", fileName);
|
||||||
|
if (typeof callback === "function") {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
document.getElementsByTagName("head")[0].appendChild(stylesheet);
|
document.getElementsByTagName("head")[0].appendChild(stylesheet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Public Methods */
|
/* Public Methods */
|
||||||
return {
|
return {
|
||||||
|
|
||||||
/* loadModules()
|
/* loadModules()
|
||||||
* Load all modules as defined in the config.
|
* Load all modules as defined in the config.
|
||||||
*/
|
*/
|
||||||
loadModules: function() {
|
loadModules: function () {
|
||||||
loadModules();
|
loadModules();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -227,8 +230,7 @@ var Loader = (function() {
|
|||||||
* argument module Module Object - the module that calls the loadFile function.
|
* argument module Module Object - the module that calls the loadFile function.
|
||||||
* argument callback function - Function called when done.
|
* argument callback function - Function called when done.
|
||||||
*/
|
*/
|
||||||
loadFile: function(fileName, module, callback) {
|
loadFile: function (fileName, module, callback) {
|
||||||
|
|
||||||
if (loadedFiles.indexOf(fileName.toLowerCase()) !== -1) {
|
if (loadedFiles.indexOf(fileName.toLowerCase()) !== -1) {
|
||||||
Log.log("File already loaded: " + fileName);
|
Log.log("File already loaded: " + fileName);
|
||||||
callback();
|
callback();
|
||||||
|
15
js/logger.js
@ -1,20 +1,15 @@
|
|||||||
/* global console */
|
|
||||||
/* exported Log */
|
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Logger
|
* Logger
|
||||||
|
* This logger is very simple, but needs to be extended.
|
||||||
|
* This system can eventually be used to push the log messages to an external target.
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
const Log = (function () {
|
||||||
// This logger is very simple, but needs to be extended.
|
|
||||||
// This system can eventually be used to push the log messages to an external target.
|
|
||||||
|
|
||||||
var Log = (function() {
|
|
||||||
return {
|
return {
|
||||||
info: Function.prototype.bind.call(console.info, console),
|
info: Function.prototype.bind.call(console.info, console),
|
||||||
log: Function.prototype.bind.call(console.log, console),
|
log: Function.prototype.bind.call(console.log, console),
|
||||||
error: Function.prototype.bind.call(console.error, console),
|
error: Function.prototype.bind.call(console.error, console),
|
||||||
warn: Function.prototype.bind.call(console.warn, console),
|
warn: Function.prototype.bind.call(console.warn, console),
|
||||||
group: Function.prototype.bind.call(console.group, console),
|
group: Function.prototype.bind.call(console.group, console),
|
||||||
|
147
js/main.js
@ -1,14 +1,12 @@
|
|||||||
/* global Log, Loader, Module, config, defaults */
|
/* global Loader, defaults, Translator */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Main System
|
* Main System
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
var MM = (function () {
|
||||||
var MM = (function() {
|
|
||||||
|
|
||||||
var modules = [];
|
var modules = [];
|
||||||
|
|
||||||
/* Private Methods */
|
/* Private Methods */
|
||||||
@ -17,10 +15,10 @@ var MM = (function() {
|
|||||||
* Create dom objects for all modules that
|
* Create dom objects for all modules that
|
||||||
* are configured for a specific position.
|
* are configured for a specific position.
|
||||||
*/
|
*/
|
||||||
var createDomObjects = function() {
|
var createDomObjects = function () {
|
||||||
var domCreationPromises = [];
|
var domCreationPromises = [];
|
||||||
|
|
||||||
modules.forEach(function(module) {
|
modules.forEach(function (module) {
|
||||||
if (typeof module.data.position !== "string") {
|
if (typeof module.data.position !== "string") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -53,14 +51,16 @@ var MM = (function() {
|
|||||||
|
|
||||||
var domCreationPromise = updateDom(module, 0);
|
var domCreationPromise = updateDom(module, 0);
|
||||||
domCreationPromises.push(domCreationPromise);
|
domCreationPromises.push(domCreationPromise);
|
||||||
domCreationPromise.then(function() {
|
domCreationPromise
|
||||||
sendNotification("MODULE_DOM_CREATED", null, null, module);
|
.then(function () {
|
||||||
}).catch(Log.error);
|
sendNotification("MODULE_DOM_CREATED", null, null, module);
|
||||||
|
})
|
||||||
|
.catch(Log.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
updateWrapperStates();
|
updateWrapperStates();
|
||||||
|
|
||||||
Promise.all(domCreationPromises).then(function() {
|
Promise.all(domCreationPromises).then(function () {
|
||||||
sendNotification("DOM_OBJECTS_CREATED");
|
sendNotification("DOM_OBJECTS_CREATED");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -70,8 +70,8 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* argument position string - The name of the position.
|
* argument position string - The name of the position.
|
||||||
*/
|
*/
|
||||||
var selectWrapper = function(position) {
|
var selectWrapper = function (position) {
|
||||||
var classes = position.replace("_"," ");
|
var classes = position.replace("_", " ");
|
||||||
var parentWrapper = document.getElementsByClassName(classes);
|
var parentWrapper = document.getElementsByClassName(classes);
|
||||||
if (parentWrapper.length > 0) {
|
if (parentWrapper.length > 0) {
|
||||||
var wrapper = parentWrapper[0].getElementsByClassName("container");
|
var wrapper = parentWrapper[0].getElementsByClassName("container");
|
||||||
@ -89,7 +89,7 @@ var MM = (function() {
|
|||||||
* argument sender Module - The module that sent the notification.
|
* argument sender Module - The module that sent the notification.
|
||||||
* argument sendTo Module - The module to send the notification to. (optional)
|
* argument sendTo Module - The module to send the notification to. (optional)
|
||||||
*/
|
*/
|
||||||
var sendNotification = function(notification, payload, sender, sendTo) {
|
var sendNotification = function (notification, payload, sender, sendTo) {
|
||||||
for (var m in modules) {
|
for (var m in modules) {
|
||||||
var module = modules[m];
|
var module = modules[m];
|
||||||
if (module !== sender && (!sendTo || module === sendTo)) {
|
if (module !== sender && (!sendTo || module === sendTo)) {
|
||||||
@ -106,8 +106,8 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return Promise - Resolved when the dom is fully updated.
|
* return Promise - Resolved when the dom is fully updated.
|
||||||
*/
|
*/
|
||||||
var updateDom = function(module, speed) {
|
var updateDom = function (module, speed) {
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function (resolve) {
|
||||||
var newContentPromise = module.getDom();
|
var newContentPromise = module.getDom();
|
||||||
var newHeader = module.getHeader();
|
var newHeader = module.getHeader();
|
||||||
|
|
||||||
@ -116,11 +116,13 @@ var MM = (function() {
|
|||||||
newContentPromise = Promise.resolve(newContentPromise);
|
newContentPromise = Promise.resolve(newContentPromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
newContentPromise.then(function(newContent) {
|
newContentPromise
|
||||||
var updatePromise = updateDomWithContent(module, speed, newHeader, newContent);
|
.then(function (newContent) {
|
||||||
|
var updatePromise = updateDomWithContent(module, speed, newHeader, newContent);
|
||||||
|
|
||||||
updatePromise.then(resolve).catch(Log.error);
|
updatePromise.then(resolve).catch(Log.error);
|
||||||
}).catch(Log.error);
|
})
|
||||||
|
.catch(Log.error);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -134,8 +136,8 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return Promise - Resolved when the module dom has been updated.
|
* return Promise - Resolved when the module dom has been updated.
|
||||||
*/
|
*/
|
||||||
var updateDomWithContent = function(module, speed, newHeader, newContent) {
|
var updateDomWithContent = function (module, speed, newHeader, newContent) {
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function (resolve) {
|
||||||
if (module.hidden || !speed) {
|
if (module.hidden || !speed) {
|
||||||
updateModuleContent(module, newHeader, newContent);
|
updateModuleContent(module, newHeader, newContent);
|
||||||
resolve();
|
resolve();
|
||||||
@ -153,7 +155,7 @@ var MM = (function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hideModule(module, speed / 2, function() {
|
hideModule(module, speed / 2, function () {
|
||||||
updateModuleContent(module, newHeader, newContent);
|
updateModuleContent(module, newHeader, newContent);
|
||||||
if (!module.hidden) {
|
if (!module.hidden) {
|
||||||
showModule(module, speed / 2);
|
showModule(module, speed / 2);
|
||||||
@ -172,7 +174,7 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return bool - Does the module need an update?
|
* return bool - Does the module need an update?
|
||||||
*/
|
*/
|
||||||
var moduleNeedsUpdate = function(module, newHeader, newContent) {
|
var moduleNeedsUpdate = function (module, newHeader, newContent) {
|
||||||
var moduleWrapper = document.getElementById(module.identifier);
|
var moduleWrapper = document.getElementById(module.identifier);
|
||||||
if (moduleWrapper === null) {
|
if (moduleWrapper === null) {
|
||||||
return false;
|
return false;
|
||||||
@ -202,9 +204,11 @@ var MM = (function() {
|
|||||||
* argument newHeader String - The new header that is generated.
|
* argument newHeader String - The new header that is generated.
|
||||||
* argument newContent Domobject - The new content that is generated.
|
* argument newContent Domobject - The new content that is generated.
|
||||||
*/
|
*/
|
||||||
var updateModuleContent = function(module, newHeader, newContent) {
|
var updateModuleContent = function (module, newHeader, newContent) {
|
||||||
var moduleWrapper = document.getElementById(module.identifier);
|
var moduleWrapper = document.getElementById(module.identifier);
|
||||||
if (moduleWrapper === null) {return;}
|
if (moduleWrapper === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
|
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
|
||||||
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");
|
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");
|
||||||
|
|
||||||
@ -222,7 +226,7 @@ var MM = (function() {
|
|||||||
* argument speed Number - The speed of the hide animation.
|
* argument speed Number - The speed of the hide animation.
|
||||||
* argument callback function - Called when the animation is done.
|
* argument callback function - Called when the animation is done.
|
||||||
*/
|
*/
|
||||||
var hideModule = function(module, speed, callback, options) {
|
var hideModule = function (module, speed, callback, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
// set lockString if set in options.
|
// set lockString if set in options.
|
||||||
@ -239,7 +243,7 @@ var MM = (function() {
|
|||||||
moduleWrapper.style.opacity = 0;
|
moduleWrapper.style.opacity = 0;
|
||||||
|
|
||||||
clearTimeout(module.showHideTimer);
|
clearTimeout(module.showHideTimer);
|
||||||
module.showHideTimer = setTimeout(function() {
|
module.showHideTimer = setTimeout(function () {
|
||||||
// To not take up any space, we just make the position absolute.
|
// To not take up any space, we just make the position absolute.
|
||||||
// since it's fade out anyway, we can see it lay above or
|
// since it's fade out anyway, we can see it lay above or
|
||||||
// below other modules. This works way better than adjusting
|
// below other modules. This works way better than adjusting
|
||||||
@ -248,11 +252,15 @@ var MM = (function() {
|
|||||||
|
|
||||||
updateWrapperStates();
|
updateWrapperStates();
|
||||||
|
|
||||||
if (typeof callback === "function") { callback(); }
|
if (typeof callback === "function") {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
}, speed);
|
}, speed);
|
||||||
} else {
|
} else {
|
||||||
// invoke callback even if no content, issue 1308
|
// invoke callback even if no content, issue 1308
|
||||||
if (typeof callback === "function") { callback(); }
|
if (typeof callback === "function") {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -263,13 +271,13 @@ var MM = (function() {
|
|||||||
* argument speed Number - The speed of the show animation.
|
* argument speed Number - The speed of the show animation.
|
||||||
* argument callback function - Called when the animation is done.
|
* argument callback function - Called when the animation is done.
|
||||||
*/
|
*/
|
||||||
var showModule = function(module, speed, callback, options) {
|
var showModule = function (module, speed, callback, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
// remove lockString if set in options.
|
// remove lockString if set in options.
|
||||||
if (options.lockString) {
|
if (options.lockString) {
|
||||||
var index = module.lockStrings.indexOf(options.lockString);
|
var index = module.lockStrings.indexOf(options.lockString);
|
||||||
if ( index !== -1) {
|
if (index !== -1) {
|
||||||
module.lockStrings.splice(index, 1);
|
module.lockStrings.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,12 +310,16 @@ var MM = (function() {
|
|||||||
moduleWrapper.style.opacity = 1;
|
moduleWrapper.style.opacity = 1;
|
||||||
|
|
||||||
clearTimeout(module.showHideTimer);
|
clearTimeout(module.showHideTimer);
|
||||||
module.showHideTimer = setTimeout(function() {
|
module.showHideTimer = setTimeout(function () {
|
||||||
if (typeof callback === "function") { callback(); }
|
if (typeof callback === "function") {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
}, speed);
|
}, speed);
|
||||||
} else {
|
} else {
|
||||||
// invoke callback
|
// invoke callback
|
||||||
if (typeof callback === "function") { callback(); }
|
if (typeof callback === "function") {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -322,15 +334,15 @@ var MM = (function() {
|
|||||||
* an ugly top margin. By using this function, the top bar will be hidden if the
|
* an ugly top margin. By using this function, the top bar will be hidden if the
|
||||||
* update notification is not visible.
|
* update notification is not visible.
|
||||||
*/
|
*/
|
||||||
var updateWrapperStates = function() {
|
var updateWrapperStates = function () {
|
||||||
var positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"];
|
var positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"];
|
||||||
|
|
||||||
positions.forEach(function(position) {
|
positions.forEach(function (position) {
|
||||||
var wrapper = selectWrapper(position);
|
var wrapper = selectWrapper(position);
|
||||||
var moduleWrappers = wrapper.getElementsByClassName("module");
|
var moduleWrappers = wrapper.getElementsByClassName("module");
|
||||||
|
|
||||||
var showWrapper = false;
|
var showWrapper = false;
|
||||||
Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) {
|
Array.prototype.forEach.call(moduleWrappers, function (moduleWrapper) {
|
||||||
if (moduleWrapper.style.position === "" || moduleWrapper.style.position === "static") {
|
if (moduleWrapper.style.position === "" || moduleWrapper.style.position === "static") {
|
||||||
showWrapper = true;
|
showWrapper = true;
|
||||||
}
|
}
|
||||||
@ -343,7 +355,9 @@ var MM = (function() {
|
|||||||
/* loadConfig()
|
/* loadConfig()
|
||||||
* Loads the core config and combines it with de system defaults.
|
* Loads the core config and combines it with de system defaults.
|
||||||
*/
|
*/
|
||||||
var loadConfig = function() {
|
var loadConfig = function () {
|
||||||
|
// FIXME: Think about how to pass config around without breaking tests
|
||||||
|
/* eslint-disable */
|
||||||
if (typeof config === "undefined") {
|
if (typeof config === "undefined") {
|
||||||
config = defaults;
|
config = defaults;
|
||||||
Log.error("Config file is missing! Please create a config file.");
|
Log.error("Config file is missing! Please create a config file.");
|
||||||
@ -351,6 +365,7 @@ var MM = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config = Object.assign({}, defaults, config);
|
config = Object.assign({}, defaults, config);
|
||||||
|
/* eslint-enable */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* setSelectionMethodsForModules()
|
/* setSelectionMethodsForModules()
|
||||||
@ -358,8 +373,7 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* argument modules array - Array of modules.
|
* argument modules array - Array of modules.
|
||||||
*/
|
*/
|
||||||
var setSelectionMethodsForModules = function(modules) {
|
var setSelectionMethodsForModules = function (modules) {
|
||||||
|
|
||||||
/* withClass(className)
|
/* withClass(className)
|
||||||
* calls modulesByClass to filter modules with the specified classes.
|
* calls modulesByClass to filter modules with the specified classes.
|
||||||
*
|
*
|
||||||
@ -367,7 +381,7 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return array - Filtered collection of modules.
|
* return array - Filtered collection of modules.
|
||||||
*/
|
*/
|
||||||
var withClass = function(className) {
|
var withClass = function (className) {
|
||||||
return modulesByClass(className, true);
|
return modulesByClass(className, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -378,7 +392,7 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return array - Filtered collection of modules.
|
* return array - Filtered collection of modules.
|
||||||
*/
|
*/
|
||||||
var exceptWithClass = function(className) {
|
var exceptWithClass = function (className) {
|
||||||
return modulesByClass(className, false);
|
return modulesByClass(className, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -390,13 +404,13 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return array - Filtered collection of modules.
|
* return array - Filtered collection of modules.
|
||||||
*/
|
*/
|
||||||
var modulesByClass = function(className, include) {
|
var modulesByClass = function (className, include) {
|
||||||
var searchClasses = className;
|
var searchClasses = className;
|
||||||
if (typeof className === "string") {
|
if (typeof className === "string") {
|
||||||
searchClasses = className.split(" ");
|
searchClasses = className.split(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
var newModules = modules.filter(function(module) {
|
var newModules = modules.filter(function (module) {
|
||||||
var classes = module.data.classes.toLowerCase().split(" ");
|
var classes = module.data.classes.toLowerCase().split(" ");
|
||||||
|
|
||||||
for (var c in searchClasses) {
|
for (var c in searchClasses) {
|
||||||
@ -420,8 +434,8 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return array - Filtered collection of modules.
|
* return array - Filtered collection of modules.
|
||||||
*/
|
*/
|
||||||
var exceptModule = function(module) {
|
var exceptModule = function (module) {
|
||||||
var newModules = modules.filter(function(mod) {
|
var newModules = modules.filter(function (mod) {
|
||||||
return mod.identifier !== module.identifier;
|
return mod.identifier !== module.identifier;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -434,16 +448,24 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* argument callback function - The function to execute with the module as an argument.
|
* argument callback function - The function to execute with the module as an argument.
|
||||||
*/
|
*/
|
||||||
var enumerate = function(callback) {
|
var enumerate = function (callback) {
|
||||||
modules.map(function(module) {
|
modules.map(function (module) {
|
||||||
callback(module);
|
callback(module);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof modules.withClass === "undefined") { Object.defineProperty(modules, "withClass", {value: withClass, enumerable: false}); }
|
if (typeof modules.withClass === "undefined") {
|
||||||
if (typeof modules.exceptWithClass === "undefined") { Object.defineProperty(modules, "exceptWithClass", {value: exceptWithClass, enumerable: false}); }
|
Object.defineProperty(modules, "withClass", { value: withClass, enumerable: false });
|
||||||
if (typeof modules.exceptModule === "undefined") { Object.defineProperty(modules, "exceptModule", {value: exceptModule, enumerable: false}); }
|
}
|
||||||
if (typeof modules.enumerate === "undefined") { Object.defineProperty(modules, "enumerate", {value: enumerate, enumerable: false}); }
|
if (typeof modules.exceptWithClass === "undefined") {
|
||||||
|
Object.defineProperty(modules, "exceptWithClass", { value: exceptWithClass, enumerable: false });
|
||||||
|
}
|
||||||
|
if (typeof modules.exceptModule === "undefined") {
|
||||||
|
Object.defineProperty(modules, "exceptModule", { value: exceptModule, enumerable: false });
|
||||||
|
}
|
||||||
|
if (typeof modules.enumerate === "undefined") {
|
||||||
|
Object.defineProperty(modules, "enumerate", { value: enumerate, enumerable: false });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -452,7 +474,7 @@ var MM = (function() {
|
|||||||
/* init()
|
/* init()
|
||||||
* Main init method.
|
* Main init method.
|
||||||
*/
|
*/
|
||||||
init: function() {
|
init: function () {
|
||||||
Log.info("Initializing MagicMirror.");
|
Log.info("Initializing MagicMirror.");
|
||||||
loadConfig();
|
loadConfig();
|
||||||
Translator.loadCoreTranslations(config.language);
|
Translator.loadCoreTranslations(config.language);
|
||||||
@ -464,7 +486,7 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* argument moduleObjects array<Module> - All module instances.
|
* argument moduleObjects array<Module> - All module instances.
|
||||||
*/
|
*/
|
||||||
modulesStarted: function(moduleObjects) {
|
modulesStarted: function (moduleObjects) {
|
||||||
modules = [];
|
modules = [];
|
||||||
for (var m in moduleObjects) {
|
for (var m in moduleObjects) {
|
||||||
var module = moduleObjects[m];
|
var module = moduleObjects[m];
|
||||||
@ -484,7 +506,7 @@ var MM = (function() {
|
|||||||
* argument payload mixed - The payload of the notification.
|
* argument payload mixed - The payload of the notification.
|
||||||
* argument sender Module - The module that sent the notification.
|
* argument sender Module - The module that sent the notification.
|
||||||
*/
|
*/
|
||||||
sendNotification: function(notification, payload, sender) {
|
sendNotification: function (notification, payload, sender) {
|
||||||
if (arguments.length < 3) {
|
if (arguments.length < 3) {
|
||||||
Log.error("sendNotification: Missing arguments.");
|
Log.error("sendNotification: Missing arguments.");
|
||||||
return;
|
return;
|
||||||
@ -510,7 +532,7 @@ var MM = (function() {
|
|||||||
* argument module Module - The module that needs an update.
|
* argument module Module - The module that needs an update.
|
||||||
* argument speed Number - The number of microseconds for the animation. (optional)
|
* argument speed Number - The number of microseconds for the animation. (optional)
|
||||||
*/
|
*/
|
||||||
updateDom: function(module, speed) {
|
updateDom: function (module, speed) {
|
||||||
if (!(module instanceof Module)) {
|
if (!(module instanceof Module)) {
|
||||||
Log.error("updateDom: Sender should be a module.");
|
Log.error("updateDom: Sender should be a module.");
|
||||||
return;
|
return;
|
||||||
@ -525,7 +547,7 @@ var MM = (function() {
|
|||||||
*
|
*
|
||||||
* return array - A collection of all modules currently active.
|
* return array - A collection of all modules currently active.
|
||||||
*/
|
*/
|
||||||
getModules: function() {
|
getModules: function () {
|
||||||
setSelectionMethodsForModules(modules);
|
setSelectionMethodsForModules(modules);
|
||||||
return modules;
|
return modules;
|
||||||
},
|
},
|
||||||
@ -538,7 +560,7 @@ var MM = (function() {
|
|||||||
* argument callback function - Called when the animation is done.
|
* argument callback function - Called when the animation is done.
|
||||||
* argument options object - Optional settings for the hide method.
|
* argument options object - Optional settings for the hide method.
|
||||||
*/
|
*/
|
||||||
hideModule: function(module, speed, callback, options) {
|
hideModule: function (module, speed, callback, options) {
|
||||||
module.hidden = true;
|
module.hidden = true;
|
||||||
hideModule(module, speed, callback, options);
|
hideModule(module, speed, callback, options);
|
||||||
},
|
},
|
||||||
@ -551,18 +573,17 @@ var MM = (function() {
|
|||||||
* argument callback function - Called when the animation is done.
|
* argument callback function - Called when the animation is done.
|
||||||
* argument options object - Optional settings for the hide method.
|
* argument options object - Optional settings for the hide method.
|
||||||
*/
|
*/
|
||||||
showModule: function(module, speed, callback, options) {
|
showModule: function (module, speed, callback, options) {
|
||||||
// do not change module.hidden yet, only if we really show it later
|
// do not change module.hidden yet, only if we really show it later
|
||||||
showModule(module, speed, callback, options);
|
showModule(module, speed, callback, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// Add polyfill for Object.assign.
|
// Add polyfill for Object.assign.
|
||||||
if (typeof Object.assign !== "function") {
|
if (typeof Object.assign !== "function") {
|
||||||
(function() {
|
(function () {
|
||||||
Object.assign = function(target) {
|
Object.assign = function (target) {
|
||||||
"use strict";
|
"use strict";
|
||||||
if (target === undefined || target === null) {
|
if (target === undefined || target === null) {
|
||||||
throw new TypeError("Cannot convert undefined or null to object");
|
throw new TypeError("Cannot convert undefined or null to object");
|
||||||
|
79
js/module.js
@ -1,15 +1,12 @@
|
|||||||
/* global Log, Class, Loader, Class , MM */
|
/* global Class, cloneObject, Loader, MMSocket, nunjucks, Translator */
|
||||||
/* exported Module */
|
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module Blueprint.
|
* Module Blueprint.
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Module = Class.extend({
|
var Module = Class.extend({
|
||||||
|
|
||||||
/*********************************************************
|
/*********************************************************
|
||||||
* All methods (and properties) below can be subclassed. *
|
* All methods (and properties) below can be subclassed. *
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
@ -82,7 +79,7 @@ var Module = Class.extend({
|
|||||||
*/
|
*/
|
||||||
getDom: function () {
|
getDom: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function (resolve) {
|
||||||
var div = document.createElement("div");
|
var div = document.createElement("div");
|
||||||
var template = self.getTemplate();
|
var template = self.getTemplate();
|
||||||
var templateData = self.getTemplateData();
|
var templateData = self.getTemplateData();
|
||||||
@ -128,7 +125,7 @@ var Module = Class.extend({
|
|||||||
* return string - The template string of filename.
|
* return string - The template string of filename.
|
||||||
*/
|
*/
|
||||||
getTemplate: function () {
|
getTemplate: function () {
|
||||||
return "<div class=\"normal\">" + this.name + "</div><div class=\"small dimmed\">" + this.identifier + "</div>";
|
return '<div class="normal">' + this.name + '</div><div class="small dimmed">' + this.identifier + "</div>";
|
||||||
},
|
},
|
||||||
|
|
||||||
/* getTemplateData()
|
/* getTemplateData()
|
||||||
@ -163,18 +160,18 @@ var Module = Class.extend({
|
|||||||
|
|
||||||
* @returns Nunjucks Environment
|
* @returns Nunjucks Environment
|
||||||
*/
|
*/
|
||||||
nunjucksEnvironment: function() {
|
nunjucksEnvironment: function () {
|
||||||
if (this._nunjucksEnvironment !== null) {
|
if (this._nunjucksEnvironment !== null) {
|
||||||
return this._nunjucksEnvironment;
|
return this._nunjucksEnvironment;
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._nunjucksEnvironment = new nunjucks.Environment(new nunjucks.WebLoader(this.file(""), {async: true}), {
|
this._nunjucksEnvironment = new nunjucks.Environment(new nunjucks.WebLoader(this.file(""), { async: true }), {
|
||||||
trimBlocks: true,
|
trimBlocks: true,
|
||||||
lstripBlocks: true
|
lstripBlocks: true
|
||||||
});
|
});
|
||||||
this._nunjucksEnvironment.addFilter("translate", function(str) {
|
this._nunjucksEnvironment.addFilter("translate", function (str) {
|
||||||
return self.translate(str);
|
return self.translate(str);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -238,7 +235,7 @@ var Module = Class.extend({
|
|||||||
*/
|
*/
|
||||||
socket: function () {
|
socket: function () {
|
||||||
if (typeof this._socket === "undefined") {
|
if (typeof this._socket === "undefined") {
|
||||||
this._socket = this._socket = new MMSocket(this.name);
|
this._socket = new MMSocket(this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -315,7 +312,9 @@ var Module = Class.extend({
|
|||||||
|
|
||||||
// The variable `first` will contain the first
|
// The variable `first` will contain the first
|
||||||
// defined translation after the following line.
|
// defined translation after the following line.
|
||||||
for (var first in translations) { break; }
|
for (var first in translations) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (translations) {
|
if (translations) {
|
||||||
var translationFile = translations[lang] || undefined;
|
var translationFile = translations[lang] || undefined;
|
||||||
@ -339,11 +338,11 @@ var Module = Class.extend({
|
|||||||
* Request the translation for a given key with optional variables and default value.
|
* Request the translation for a given key with optional variables and default value.
|
||||||
*
|
*
|
||||||
* argument key string - The key of the string to translate
|
* argument key string - The key of the string to translate
|
||||||
* argument defaultValueOrVariables string/object - The default value or variables for translating. (Optional)
|
* argument defaultValueOrVariables string/object - The default value or variables for translating. (Optional)
|
||||||
* argument defaultValue string - The default value with variables. (Optional)
|
* argument defaultValue string - The default value with variables. (Optional)
|
||||||
*/
|
*/
|
||||||
translate: function (key, defaultValueOrVariables, defaultValue) {
|
translate: function (key, defaultValueOrVariables, defaultValue) {
|
||||||
if(typeof defaultValueOrVariables === "object") {
|
if (typeof defaultValueOrVariables === "object") {
|
||||||
return Translator.translate(this, key, defaultValueOrVariables) || defaultValue || "";
|
return Translator.translate(this, key, defaultValueOrVariables) || defaultValue || "";
|
||||||
}
|
}
|
||||||
return Translator.translate(this, key) || defaultValueOrVariables || "";
|
return Translator.translate(this, key) || defaultValueOrVariables || "";
|
||||||
@ -388,17 +387,22 @@ var Module = Class.extend({
|
|||||||
hide: function (speed, callback, options) {
|
hide: function (speed, callback, options) {
|
||||||
if (typeof callback === "object") {
|
if (typeof callback === "object") {
|
||||||
options = callback;
|
options = callback;
|
||||||
callback = function () { };
|
callback = function () {};
|
||||||
}
|
}
|
||||||
|
|
||||||
callback = callback || function () { };
|
callback = callback || function () {};
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
MM.hideModule(self, speed, function () {
|
MM.hideModule(
|
||||||
self.suspend();
|
self,
|
||||||
callback();
|
speed,
|
||||||
}, options);
|
function () {
|
||||||
|
self.suspend();
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
/* showModule(module, speed, callback)
|
/* showModule(module, speed, callback)
|
||||||
@ -411,24 +415,28 @@ var Module = Class.extend({
|
|||||||
show: function (speed, callback, options) {
|
show: function (speed, callback, options) {
|
||||||
if (typeof callback === "object") {
|
if (typeof callback === "object") {
|
||||||
options = callback;
|
options = callback;
|
||||||
callback = function () { };
|
callback = function () {};
|
||||||
}
|
}
|
||||||
|
|
||||||
callback = callback || function () { };
|
callback = callback || function () {};
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
MM.showModule(this, speed, function () {
|
MM.showModule(
|
||||||
self.resume();
|
this,
|
||||||
callback;
|
speed,
|
||||||
}, options);
|
function () {
|
||||||
|
self.resume();
|
||||||
|
callback;
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Module.definitions = {};
|
Module.definitions = {};
|
||||||
|
|
||||||
Module.create = function (name) {
|
Module.create = function (name) {
|
||||||
|
|
||||||
// Make sure module definition is available.
|
// Make sure module definition is available.
|
||||||
if (!Module.definitions[name]) {
|
if (!Module.definitions[name]) {
|
||||||
return;
|
return;
|
||||||
@ -444,11 +452,11 @@ Module.create = function (name) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* cmpVersions(a,b)
|
/* cmpVersions(a,b)
|
||||||
* Compare two semantic version numbers and return the difference.
|
* Compare two semantic version numbers and return the difference.
|
||||||
*
|
*
|
||||||
* argument a string - Version number a.
|
* argument a string - Version number a.
|
||||||
* argument a string - Version number b.
|
* argument a string - Version number b.
|
||||||
*/
|
*/
|
||||||
function cmpVersions(a, b) {
|
function cmpVersions(a, b) {
|
||||||
var i, diff;
|
var i, diff;
|
||||||
var regExStrip0 = /(\.0+)+$/;
|
var regExStrip0 = /(\.0+)+$/;
|
||||||
@ -466,10 +474,9 @@ function cmpVersions(a, b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Module.register = function (name, moduleDefinition) {
|
Module.register = function (name, moduleDefinition) {
|
||||||
|
|
||||||
if (moduleDefinition.requiresVersion) {
|
if (moduleDefinition.requiresVersion) {
|
||||||
Log.log("Check MagicMirror version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + version);
|
Log.log("Check MagicMirror version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + window.version);
|
||||||
if (cmpVersions(version, moduleDefinition.requiresVersion) >= 0) {
|
if (cmpVersions(window.version, moduleDefinition.requiresVersion) >= 0) {
|
||||||
Log.log("Version is ok!");
|
Log.log("Version is ok!");
|
||||||
} else {
|
} else {
|
||||||
Log.log("Version is incorrect. Skip module: '" + name + "'");
|
Log.log("Version is incorrect. Skip module: '" + name + "'");
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Node Helper Superclass
|
* Node Helper Superclass
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
const Class = require("./class.js");
|
||||||
|
const express = require("express");
|
||||||
|
|
||||||
var Class = require("./class.js");
|
var NodeHelper = Class.extend({
|
||||||
var express = require("express");
|
init: function () {
|
||||||
var path = require("path");
|
|
||||||
|
|
||||||
NodeHelper = Class.extend({
|
|
||||||
init: function() {
|
|
||||||
console.log("Initializing new module helper ...");
|
console.log("Initializing new module helper ...");
|
||||||
},
|
},
|
||||||
|
|
||||||
loaded: function(callback) {
|
loaded: function (callback) {
|
||||||
console.log("Module helper loaded: " + this.name);
|
console.log("Module helper loaded: " + this.name);
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
|
|
||||||
start: function() {
|
start: function () {
|
||||||
console.log("Starting module helper: " + this.name);
|
console.log("Starting module helper: " + this.name);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -29,7 +27,7 @@ NodeHelper = Class.extend({
|
|||||||
* gracefully exit the module.
|
* gracefully exit the module.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
stop: function() {
|
stop: function () {
|
||||||
console.log("Stopping module helper: " + this.name);
|
console.log("Stopping module helper: " + this.name);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -39,7 +37,7 @@ NodeHelper = Class.extend({
|
|||||||
* argument notification string - The identifier of the notification.
|
* argument notification string - The identifier of the notification.
|
||||||
* argument payload mixed - The payload of the notification.
|
* argument payload mixed - The payload of the notification.
|
||||||
*/
|
*/
|
||||||
socketNotificationReceived: function(notification, payload) {
|
socketNotificationReceived: function (notification, payload) {
|
||||||
console.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
|
console.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -48,7 +46,7 @@ NodeHelper = Class.extend({
|
|||||||
*
|
*
|
||||||
* argument name string - Module name.
|
* argument name string - Module name.
|
||||||
*/
|
*/
|
||||||
setName: function(name) {
|
setName: function (name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ NodeHelper = Class.extend({
|
|||||||
*
|
*
|
||||||
* argument path string - Module path.
|
* argument path string - Module path.
|
||||||
*/
|
*/
|
||||||
setPath: function(path) {
|
setPath: function (path) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -67,7 +65,7 @@ NodeHelper = Class.extend({
|
|||||||
* argument notification string - The identifier of the notification.
|
* argument notification string - The identifier of the notification.
|
||||||
* argument payload mixed - The payload of the notification.
|
* argument payload mixed - The payload of the notification.
|
||||||
*/
|
*/
|
||||||
sendSocketNotification: function(notification, payload) {
|
sendSocketNotification: function (notification, payload) {
|
||||||
this.io.of(this.name).emit(notification, payload);
|
this.io.of(this.name).emit(notification, payload);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -77,7 +75,7 @@ NodeHelper = Class.extend({
|
|||||||
*
|
*
|
||||||
* argument app Express app - The Express app object.
|
* argument app Express app - The Express app object.
|
||||||
*/
|
*/
|
||||||
setExpressApp: function(app) {
|
setExpressApp: function (app) {
|
||||||
this.expressApp = app;
|
this.expressApp = app;
|
||||||
|
|
||||||
var publicPath = this.path + "/public";
|
var publicPath = this.path + "/public";
|
||||||
@ -90,16 +88,16 @@ NodeHelper = Class.extend({
|
|||||||
*
|
*
|
||||||
* argument io Socket.io - The Socket io object.
|
* argument io Socket.io - The Socket io object.
|
||||||
*/
|
*/
|
||||||
setSocketIO: function(io) {
|
setSocketIO: function (io) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.io = io;
|
self.io = io;
|
||||||
|
|
||||||
console.log("Connecting socket for: " + this.name);
|
console.log("Connecting socket for: " + this.name);
|
||||||
var namespace = this.name;
|
var namespace = this.name;
|
||||||
io.of(namespace).on("connection", function(socket) {
|
io.of(namespace).on("connection", function (socket) {
|
||||||
// add a catch all event.
|
// add a catch all event.
|
||||||
var onevent = socket.onevent;
|
var onevent = socket.onevent;
|
||||||
socket.onevent = function(packet) {
|
socket.onevent = function (packet) {
|
||||||
var args = packet.data || [];
|
var args = packet.data || [];
|
||||||
onevent.call(this, packet); // original call
|
onevent.call(this, packet); // original call
|
||||||
packet.data = ["*"].concat(args);
|
packet.data = ["*"].concat(args);
|
||||||
@ -107,19 +105,21 @@ NodeHelper = Class.extend({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// register catch all.
|
// register catch all.
|
||||||
socket.on("*", function(notification, payload) {
|
socket.on("*", function (notification, payload) {
|
||||||
if (notification !== "*") {
|
if (notification !== "*") {
|
||||||
//console.log('received message in namespace: ' + namespace);
|
//console.log('received message in namespace: ' + namespace);
|
||||||
self.socketNotificationReceived(notification, payload);
|
self.socketNotificationReceived(notification, payload);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
NodeHelper.create = function(moduleDefinition) {
|
NodeHelper.create = function (moduleDefinition) {
|
||||||
return NodeHelper.extend(moduleDefinition);
|
return NodeHelper.extend(moduleDefinition);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = NodeHelper;
|
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||||
|
if (typeof module !== "undefined") {
|
||||||
|
module.exports = NodeHelper;
|
||||||
|
}
|
||||||
|
27
js/server.js
@ -1,7 +1,7 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Server
|
* Server
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -13,21 +13,20 @@ var fs = require("fs");
|
|||||||
var helmet = require("helmet");
|
var helmet = require("helmet");
|
||||||
var Utils = require(__dirname + "/utils.js");
|
var Utils = require(__dirname + "/utils.js");
|
||||||
|
|
||||||
var Server = function(config, callback) {
|
var Server = function (config, callback) {
|
||||||
|
|
||||||
var port = config.port;
|
var port = config.port;
|
||||||
if (process.env.MM_PORT) {
|
if (process.env.MM_PORT) {
|
||||||
port = process.env.MM_PORT;
|
port = process.env.MM_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
var server = null;
|
var server = null;
|
||||||
if(config.useHttps){
|
if (config.useHttps) {
|
||||||
var options = {
|
var options = {
|
||||||
key: fs.readFileSync(config.httpsPrivateKey),
|
key: fs.readFileSync(config.httpsPrivateKey),
|
||||||
cert: fs.readFileSync(config.httpsCertificate)
|
cert: fs.readFileSync(config.httpsCertificate)
|
||||||
};
|
};
|
||||||
server = require("https").Server(options, app);
|
server = require("https").Server(options, app);
|
||||||
}else{
|
} else {
|
||||||
server = require("http").Server(app);
|
server = require("http").Server(app);
|
||||||
}
|
}
|
||||||
var io = require("socket.io")(server);
|
var io = require("socket.io")(server);
|
||||||
@ -40,8 +39,8 @@ var Server = function(config, callback) {
|
|||||||
console.info(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs"));
|
console.info(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(function(req, res, next) {
|
app.use(function (req, res, next) {
|
||||||
var result = ipfilter(config.ipWhitelist, {mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false})(req, res, function(err) {
|
var result = ipfilter(config.ipWhitelist, { mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false })(req, res, function (err) {
|
||||||
if (err === undefined) {
|
if (err === undefined) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
@ -59,21 +58,21 @@ var Server = function(config, callback) {
|
|||||||
app.use(directory, express.static(path.resolve(global.root_path + directory)));
|
app.use(directory, express.static(path.resolve(global.root_path + directory)));
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get("/version", function(req,res) {
|
app.get("/version", function (req, res) {
|
||||||
res.send(global.version);
|
res.send(global.version);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/config", function(req,res) {
|
app.get("/config", function (req, res) {
|
||||||
res.send(config);
|
res.send(config);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/", function(req, res) {
|
app.get("/", function (req, res) {
|
||||||
var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), {encoding: "utf8"});
|
var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), { encoding: "utf8" });
|
||||||
html = html.replace("#VERSION#", global.version);
|
html = html.replace("#VERSION#", global.version);
|
||||||
|
|
||||||
configFile = "config/config.js";
|
var configFile = "config/config.js";
|
||||||
if (typeof(global.configuration_file) !== "undefined") {
|
if (typeof global.configuration_file !== "undefined") {
|
||||||
configFile = global.configuration_file;
|
configFile = global.configuration_file;
|
||||||
}
|
}
|
||||||
html = html.replace("#CONFIG_FILE#", configFile);
|
html = html.replace("#CONFIG_FILE#", configFile);
|
||||||
|
|
||||||
|
35
js/socket.js
@ -1,35 +0,0 @@
|
|||||||
/* exported Log */
|
|
||||||
|
|
||||||
/* Magic Mirror
|
|
||||||
* Socket Connection
|
|
||||||
*
|
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
|
||||||
* MIT Licensed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var MMSocket = function(moduleName) {
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (typeof moduleName !== "string") {
|
|
||||||
throw new Error("Please set the module name for the MMSocket.");
|
|
||||||
}
|
|
||||||
|
|
||||||
self.moduleName = moduleName;
|
|
||||||
|
|
||||||
self.socket = io("http://localhost:8080");
|
|
||||||
self.socket.on("notification", function(data) {
|
|
||||||
MM.sendNotification(data.notification, data.payload, Socket);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
sendMessage: function(notification, payload, sender) {
|
|
||||||
Log.log("Send socket message: " + notification);
|
|
||||||
self.socket.emit("notification", {
|
|
||||||
notification: notification,
|
|
||||||
sender: sender,
|
|
||||||
payload: payload
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,4 +1,12 @@
|
|||||||
var MMSocket = function(moduleName) {
|
/* global io */
|
||||||
|
|
||||||
|
/* Magic Mirror
|
||||||
|
* TODO add description
|
||||||
|
*
|
||||||
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
|
* MIT Licensed.
|
||||||
|
*/
|
||||||
|
var MMSocket = function (moduleName) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (typeof moduleName !== "string") {
|
if (typeof moduleName !== "string") {
|
||||||
@ -8,13 +16,17 @@ var MMSocket = function(moduleName) {
|
|||||||
self.moduleName = moduleName;
|
self.moduleName = moduleName;
|
||||||
|
|
||||||
// Private Methods
|
// Private Methods
|
||||||
|
var base = "/";
|
||||||
|
if (typeof config !== "undefined" && typeof config.basePath !== "undefined") {
|
||||||
|
base = config.basePath;
|
||||||
|
}
|
||||||
self.socket = io("/" + self.moduleName, {
|
self.socket = io("/" + self.moduleName, {
|
||||||
path: window.location.pathname + "socket.io"
|
path: base + "socket.io"
|
||||||
});
|
});
|
||||||
var notificationCallback = function() {};
|
var notificationCallback = function () {};
|
||||||
|
|
||||||
var onevent = self.socket.onevent;
|
var onevent = self.socket.onevent;
|
||||||
self.socket.onevent = function(packet) {
|
self.socket.onevent = function (packet) {
|
||||||
var args = packet.data || [];
|
var args = packet.data || [];
|
||||||
onevent.call(this, packet); // original call
|
onevent.call(this, packet); // original call
|
||||||
packet.data = ["*"].concat(args);
|
packet.data = ["*"].concat(args);
|
||||||
@ -22,18 +34,18 @@ var MMSocket = function(moduleName) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// register catch all.
|
// register catch all.
|
||||||
self.socket.on("*", function(notification, payload) {
|
self.socket.on("*", function (notification, payload) {
|
||||||
if (notification !== "*") {
|
if (notification !== "*") {
|
||||||
notificationCallback(notification, payload);
|
notificationCallback(notification, payload);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Public Methods
|
// Public Methods
|
||||||
this.setNotificationCallback = function(callback) {
|
this.setNotificationCallback = function (callback) {
|
||||||
notificationCallback = callback;
|
notificationCallback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.sendNotification = function(notification, payload) {
|
this.sendNotification = function (notification, payload) {
|
||||||
if (typeof payload === "undefined") {
|
if (typeof payload === "undefined") {
|
||||||
payload = {};
|
payload = {};
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/* exported Translator */
|
/* global translations */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Translator (l10n)
|
* Translator (l10n)
|
||||||
*
|
*
|
||||||
* By Christopher Fenner http://github.com/CFenner
|
* By Christopher Fenner https://github.com/CFenner
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
var Translator = (function() {
|
var Translator = (function () {
|
||||||
|
|
||||||
/* loadJSON(file, callback)
|
/* loadJSON(file, callback)
|
||||||
* Load a JSON file via XHR.
|
* Load a JSON file via XHR.
|
||||||
*
|
*
|
||||||
@ -61,7 +61,7 @@ var Translator = (function() {
|
|||||||
currentChar = str[i];
|
currentChar = str[i];
|
||||||
nextChar = str[i + 1];
|
nextChar = str[i + 1];
|
||||||
|
|
||||||
if (!insideComment && currentChar === "\"") {
|
if (!insideComment && currentChar === '"') {
|
||||||
var escaped = str[i - 1] === "\\" && str[i - 2] !== "\\";
|
var escaped = str[i - 1] === "\\" && str[i - 2] !== "\\";
|
||||||
if (!escaped) {
|
if (!escaped) {
|
||||||
insideString = !insideString;
|
insideString = !insideString;
|
||||||
@ -118,7 +118,7 @@ var Translator = (function() {
|
|||||||
* argument key string - The key of the text to translate.
|
* argument key string - The key of the text to translate.
|
||||||
* argument variables - The variables to use within the translation template (optional)
|
* argument variables - The variables to use within the translation template (optional)
|
||||||
*/
|
*/
|
||||||
translate: function(module, key, variables) {
|
translate: function (module, key, variables) {
|
||||||
variables = variables || {}; //Empty object by default
|
variables = variables || {}; //Empty object by default
|
||||||
|
|
||||||
// Combines template and variables like:
|
// Combines template and variables like:
|
||||||
@ -126,18 +126,18 @@ var Translator = (function() {
|
|||||||
// variables: {timeToWait: "2 hours", work: "painting"}
|
// variables: {timeToWait: "2 hours", work: "painting"}
|
||||||
// to: "Please wait for 2 hours before continuing with painting."
|
// to: "Please wait for 2 hours before continuing with painting."
|
||||||
function createStringFromTemplate(template, variables) {
|
function createStringFromTemplate(template, variables) {
|
||||||
if(Object.prototype.toString.call(template) !== "[object String]") {
|
if (Object.prototype.toString.call(template) !== "[object String]") {
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
if(variables.fallback && !template.match(new RegExp("\{.+\}"))) {
|
if (variables.fallback && !template.match(new RegExp("{.+}"))) {
|
||||||
template = variables.fallback;
|
template = variables.fallback;
|
||||||
}
|
}
|
||||||
return template.replace(new RegExp("\{([^\}]+)\}", "g"), function(_unused, varName){
|
return template.replace(new RegExp("{([^}]+)}", "g"), function (_unused, varName) {
|
||||||
return variables[varName] || "{"+varName+"}";
|
return variables[varName] || "{" + varName + "}";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.translations[module.name] && key in this.translations[module.name]) {
|
if (this.translations[module.name] && key in this.translations[module.name]) {
|
||||||
// Log.log("Got translation for " + key + " from module translation: ");
|
// Log.log("Got translation for " + key + " from module translation: ");
|
||||||
return createStringFromTemplate(this.translations[module.name][key], variables);
|
return createStringFromTemplate(this.translations[module.name][key], variables);
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ var Translator = (function() {
|
|||||||
* argument isFallback boolean - Flag to indicate fallback translations.
|
* argument isFallback boolean - Flag to indicate fallback translations.
|
||||||
* argument callback function - Function called when done.
|
* argument callback function - Function called when done.
|
||||||
*/
|
*/
|
||||||
load: function(module, file, isFallback, callback) {
|
load: function (module, file, isFallback, callback) {
|
||||||
if (!isFallback) {
|
if (!isFallback) {
|
||||||
Log.log(module.name + " - Load translation: " + file);
|
Log.log(module.name + " - Load translation: " + file);
|
||||||
} else {
|
} else {
|
||||||
@ -176,8 +176,8 @@ var Translator = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if(!this.translationsFallback[module.name]) {
|
if (!this.translationsFallback[module.name]) {
|
||||||
loadJSON(module.file(file), function(json) {
|
loadJSON(module.file(file), function (json) {
|
||||||
if (!isFallback) {
|
if (!isFallback) {
|
||||||
self.translations[module.name] = json;
|
self.translations[module.name] = json;
|
||||||
} else {
|
} else {
|
||||||
@ -195,12 +195,12 @@ var Translator = (function() {
|
|||||||
*
|
*
|
||||||
* argument lang String - The language identifier of the core language.
|
* argument lang String - The language identifier of the core language.
|
||||||
*/
|
*/
|
||||||
loadCoreTranslations: function(lang) {
|
loadCoreTranslations: function (lang) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (lang in translations) {
|
if (lang in translations) {
|
||||||
Log.log("Loading core translation file: " + translations[lang]);
|
Log.log("Loading core translation file: " + translations[lang]);
|
||||||
loadJSON(translations[lang], function(translations) {
|
loadJSON(translations[lang], function (translations) {
|
||||||
self.coreTranslations = translations;
|
self.coreTranslations = translations;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -214,19 +214,21 @@ var Translator = (function() {
|
|||||||
* Load the core translations fallback.
|
* Load the core translations fallback.
|
||||||
* The first language defined in translations.js will be used.
|
* The first language defined in translations.js will be used.
|
||||||
*/
|
*/
|
||||||
loadCoreTranslationsFallback: function() {
|
loadCoreTranslationsFallback: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// The variable `first` will contain the first
|
// The variable `first` will contain the first
|
||||||
// defined translation after the following line.
|
// defined translation after the following line.
|
||||||
for (var first in translations) {break;}
|
for (var first in translations) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
Log.log("Loading core translation fallback file: " + translations[first]);
|
Log.log("Loading core translation fallback file: " + translations[first]);
|
||||||
loadJSON(translations[first], function(translations) {
|
loadJSON(translations[first], function (translations) {
|
||||||
self.coreTranslationsFallback = translations;
|
self.coreTranslationsFallback = translations;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
/* exported Utils */
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Utils
|
* Utils
|
||||||
*
|
*
|
||||||
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
|
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var colors = require("colors/safe");
|
var colors = require("colors/safe");
|
||||||
|
|
||||||
var Utils = {
|
var Utils = {
|
||||||
@ -16,4 +14,6 @@ var Utils = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof module !== "undefined") {module.exports = Utils;}
|
if (typeof module !== "undefined") {
|
||||||
|
module.exports = Utils;
|
||||||
|
}
|
||||||
|
@ -6,8 +6,5 @@
|
|||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"allowSyntheticDefaultImports": true
|
"allowSyntheticDefaultImports": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["modules", "node_modules"]
|
||||||
"modules",
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Module: Alert
|
# Module: Alert
|
||||||
|
|
||||||
The alert module is one of the default modules of the MagicMirror. This module displays notifications from other modules.
|
The alert module is one of the default modules of the MagicMirror. This module displays notifications from other modules.
|
||||||
|
|
||||||
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/alert.html).
|
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/alert.html).
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
/* global Module */
|
/* global NotificationFx */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: alert
|
* Module: alert
|
||||||
*
|
*
|
||||||
* By Paul-Vincent Roll http://paulvincentroll.com
|
* By Paul-Vincent Roll https://paulvincentroll.com/
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
Module.register("alert", {
|
||||||
Module.register("alert",{
|
|
||||||
defaults: {
|
defaults: {
|
||||||
// scale|slide|genie|jelly|flip|bouncyflip|exploader
|
// scale|slide|genie|jelly|flip|bouncyflip|exploader
|
||||||
effect: "slide",
|
effect: "slide",
|
||||||
@ -18,31 +17,33 @@ Module.register("alert",{
|
|||||||
//Position
|
//Position
|
||||||
position: "center",
|
position: "center",
|
||||||
//shown at startup
|
//shown at startup
|
||||||
welcome_message: false,
|
welcome_message: false
|
||||||
},
|
},
|
||||||
getScripts: function() {
|
getScripts: function () {
|
||||||
return ["classie.js", "modernizr.custom.js", "notificationFx.js"];
|
return ["notificationFx.js"];
|
||||||
},
|
},
|
||||||
getStyles: function() {
|
getStyles: function () {
|
||||||
return ["ns-default.css", "font-awesome.css"];
|
return ["notificationFx.css", "font-awesome.css"];
|
||||||
},
|
},
|
||||||
// Define required translations.
|
// Define required translations.
|
||||||
getTranslations: function() {
|
getTranslations: function () {
|
||||||
return {
|
return {
|
||||||
en: "translations/en.json",
|
en: "translations/en.json",
|
||||||
de: "translations/de.json",
|
de: "translations/de.json",
|
||||||
nl: "translations/nl.json",
|
nl: "translations/nl.json"
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
show_notification: function(message) {
|
show_notification: function (message) {
|
||||||
if (this.config.effect === "slide") {this.config.effect = this.config.effect + "-" + this.config.position;}
|
if (this.config.effect === "slide") {
|
||||||
msg = "";
|
this.config.effect = this.config.effect + "-" + this.config.position;
|
||||||
|
}
|
||||||
|
let msg = "";
|
||||||
if (message.title) {
|
if (message.title) {
|
||||||
msg += "<span class='thin dimmed medium'>" + message.title + "</span>";
|
msg += "<span class='thin dimmed medium'>" + message.title + "</span>";
|
||||||
}
|
}
|
||||||
if (message.message){
|
if (message.message) {
|
||||||
if (msg !== ""){
|
if (msg !== "") {
|
||||||
msg+= "<br />";
|
msg += "<br />";
|
||||||
}
|
}
|
||||||
msg += "<span class='light bright small'>" + message.message + "</span>";
|
msg += "<span class='light bright small'>" + message.message + "</span>";
|
||||||
}
|
}
|
||||||
@ -54,23 +55,26 @@ Module.register("alert",{
|
|||||||
ttl: message.timer !== undefined ? message.timer : this.config.display_time
|
ttl: message.timer !== undefined ? message.timer : this.config.display_time
|
||||||
}).show();
|
}).show();
|
||||||
},
|
},
|
||||||
show_alert: function(params, sender) {
|
show_alert: function (params, sender) {
|
||||||
var self = this;
|
let image = "";
|
||||||
//Set standard params if not provided by module
|
//Set standard params if not provided by module
|
||||||
if (typeof params.timer === "undefined") { params.timer = null; }
|
if (typeof params.timer === "undefined") {
|
||||||
if (typeof params.imageHeight === "undefined") { params.imageHeight = "80px"; }
|
params.timer = null;
|
||||||
|
}
|
||||||
|
if (typeof params.imageHeight === "undefined") {
|
||||||
|
params.imageHeight = "80px";
|
||||||
|
}
|
||||||
if (typeof params.imageUrl === "undefined" && typeof params.imageFA === "undefined") {
|
if (typeof params.imageUrl === "undefined" && typeof params.imageFA === "undefined") {
|
||||||
params.imageUrl = null;
|
params.imageUrl = null;
|
||||||
image = "";
|
} else if (typeof params.imageFA === "undefined") {
|
||||||
} else if (typeof params.imageFA === "undefined"){
|
image = "<img src='" + params.imageUrl.toString() + "' height='" + params.imageHeight.toString() + "' style='margin-bottom: 10px;'/><br />";
|
||||||
image = "<img src='" + (params.imageUrl).toString() + "' height='" + (params.imageHeight).toString() + "' style='margin-bottom: 10px;'/><br />";
|
} else if (typeof params.imageUrl === "undefined") {
|
||||||
} else if (typeof params.imageUrl === "undefined"){
|
image = "<span class='bright " + "fa fa-" + params.imageFA + "' style='margin-bottom: 10px;font-size:" + params.imageHeight.toString() + ";'/></span><br />";
|
||||||
image = "<span class='bright " + "fa fa-" + params.imageFA + "' style='margin-bottom: 10px;font-size:" + (params.imageHeight).toString() + ";'/></span><br />";
|
|
||||||
}
|
}
|
||||||
//Create overlay
|
//Create overlay
|
||||||
var overlay = document.createElement("div");
|
const overlay = document.createElement("div");
|
||||||
overlay.id = "overlay";
|
overlay.id = "overlay";
|
||||||
overlay.innerHTML += "<div class=\"black_overlay\"></div>";
|
overlay.innerHTML += '<div class="black_overlay"></div>';
|
||||||
document.body.insertBefore(overlay, document.body.firstChild);
|
document.body.insertBefore(overlay, document.body.firstChild);
|
||||||
|
|
||||||
//If module already has an open alert close it
|
//If module already has an open alert close it
|
||||||
@ -79,12 +83,12 @@ Module.register("alert",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Display title and message only if they are provided in notification parameters
|
//Display title and message only if they are provided in notification parameters
|
||||||
var message = "";
|
let message = "";
|
||||||
if (params.title) {
|
if (params.title) {
|
||||||
message += "<span class='light dimmed medium'>" + params.title + "</span>";
|
message += "<span class='light dimmed medium'>" + params.title + "</span>";
|
||||||
}
|
}
|
||||||
if (params.message) {
|
if (params.message) {
|
||||||
if (message !== ""){
|
if (message !== "") {
|
||||||
message += "<br />";
|
message += "<br />";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,34 +106,40 @@ Module.register("alert",{
|
|||||||
this.alerts[sender.name].show();
|
this.alerts[sender.name].show();
|
||||||
//Add timer to dismiss alert and overlay
|
//Add timer to dismiss alert and overlay
|
||||||
if (params.timer) {
|
if (params.timer) {
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
self.hide_alert(sender);
|
this.hide_alert(sender);
|
||||||
}, params.timer);
|
}, params.timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
hide_alert: function(sender) {
|
hide_alert: function (sender) {
|
||||||
//Dismiss alert and remove from this.alerts
|
//Dismiss alert and remove from this.alerts
|
||||||
if (this.alerts[sender.name]) {
|
if (this.alerts[sender.name]) {
|
||||||
this.alerts[sender.name].dismiss();
|
this.alerts[sender.name].dismiss();
|
||||||
this.alerts[sender.name] = null;
|
this.alerts[sender.name] = null;
|
||||||
//Remove overlay
|
//Remove overlay
|
||||||
var overlay = document.getElementById("overlay");
|
const overlay = document.getElementById("overlay");
|
||||||
overlay.parentNode.removeChild(overlay);
|
overlay.parentNode.removeChild(overlay);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setPosition: function(pos) {
|
setPosition: function (pos) {
|
||||||
//Add css to body depending on the set position for notifications
|
//Add css to body depending on the set position for notifications
|
||||||
var sheet = document.createElement("style");
|
const sheet = document.createElement("style");
|
||||||
if (pos === "center") {sheet.innerHTML = ".ns-box {margin-left: auto; margin-right: auto;text-align: center;}";}
|
if (pos === "center") {
|
||||||
if (pos === "right") {sheet.innerHTML = ".ns-box {margin-left: auto;text-align: right;}";}
|
sheet.innerHTML = ".ns-box {margin-left: auto; margin-right: auto;text-align: center;}";
|
||||||
if (pos === "left") {sheet.innerHTML = ".ns-box {margin-right: auto;text-align: left;}";}
|
}
|
||||||
|
if (pos === "right") {
|
||||||
|
sheet.innerHTML = ".ns-box {margin-left: auto;text-align: right;}";
|
||||||
|
}
|
||||||
|
if (pos === "left") {
|
||||||
|
sheet.innerHTML = ".ns-box {margin-right: auto;text-align: left;}";
|
||||||
|
}
|
||||||
document.body.appendChild(sheet);
|
document.body.appendChild(sheet);
|
||||||
|
|
||||||
},
|
},
|
||||||
notificationReceived: function(notification, payload, sender) {
|
notificationReceived: function (notification, payload, sender) {
|
||||||
if (notification === "SHOW_ALERT") {
|
if (notification === "SHOW_ALERT") {
|
||||||
if (typeof payload.type === "undefined") { payload.type = "alert"; }
|
if (typeof payload.type === "undefined") {
|
||||||
|
payload.type = "alert";
|
||||||
|
}
|
||||||
if (payload.type === "alert") {
|
if (payload.type === "alert") {
|
||||||
this.show_alert(payload, sender);
|
this.show_alert(payload, sender);
|
||||||
} else if (payload.type === "notification") {
|
} else if (payload.type === "notification") {
|
||||||
@ -139,15 +149,14 @@ Module.register("alert",{
|
|||||||
this.hide_alert(sender);
|
this.hide_alert(sender);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
start: function() {
|
start: function () {
|
||||||
this.alerts = {};
|
this.alerts = {};
|
||||||
this.setPosition(this.config.position);
|
this.setPosition(this.config.position);
|
||||||
if (this.config.welcome_message) {
|
if (this.config.welcome_message) {
|
||||||
if (this.config.welcome_message === true){
|
if (this.config.welcome_message === true) {
|
||||||
this.show_notification({title: this.translate("sysTitle"), message: this.translate("welcome")});
|
this.show_notification({ title: this.translate("sysTitle"), message: this.translate("welcome") });
|
||||||
}
|
} else {
|
||||||
else{
|
this.show_notification({ title: this.translate("sysTitle"), message: this.config.welcome_message });
|
||||||
this.show_notification({title: this.translate("sysTitle"), message: this.config.welcome_message});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
/*!
|
|
||||||
* classie - class helper functions
|
|
||||||
* from bonzo https://github.com/ded/bonzo
|
|
||||||
*
|
|
||||||
* classie.has( elem, 'my-class' ) -> true/false
|
|
||||||
* classie.add( elem, 'my-new-class' )
|
|
||||||
* classie.remove( elem, 'my-unwanted-class' )
|
|
||||||
* classie.toggle( elem, 'my-class' )
|
|
||||||
*/
|
|
||||||
// jscs:disable
|
|
||||||
/*jshint browser: true, strict: true, undef: true */
|
|
||||||
/*global define: false */
|
|
||||||
|
|
||||||
(function(window) {
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// class helper functions from bonzo https://github.com/ded/bonzo
|
|
||||||
|
|
||||||
function classReg(className) {
|
|
||||||
return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// classList support for class management
|
|
||||||
// altho to be fair, the api sucks because it won't accept multiple classes at once
|
|
||||||
var hasClass, addClass, removeClass;
|
|
||||||
|
|
||||||
if ("classList" in document.documentElement) {
|
|
||||||
hasClass = function(elem, c) {
|
|
||||||
return elem.classList.contains(c);
|
|
||||||
};
|
|
||||||
addClass = function(elem, c) {
|
|
||||||
elem.classList.add(c);
|
|
||||||
};
|
|
||||||
removeClass = function(elem, c) {
|
|
||||||
elem.classList.remove(c);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
hasClass = function(elem, c) {
|
|
||||||
return classReg(c).test(elem.className);
|
|
||||||
};
|
|
||||||
addClass = function(elem, c) {
|
|
||||||
if (!hasClass(elem, c)) {
|
|
||||||
elem.className = elem.className + " " + c;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
removeClass = function(elem, c) {
|
|
||||||
elem.className = elem.className.replace(classReg(c), " ");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleClass(elem, c) {
|
|
||||||
var fn = hasClass(elem, c) ? removeClass : addClass;
|
|
||||||
fn(elem, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
var classie = {
|
|
||||||
// full names
|
|
||||||
hasClass: hasClass,
|
|
||||||
addClass: addClass,
|
|
||||||
removeClass: removeClass,
|
|
||||||
toggleClass: toggleClass,
|
|
||||||
// short names
|
|
||||||
has: hasClass,
|
|
||||||
add: addClass,
|
|
||||||
remove: removeClass,
|
|
||||||
toggle: toggleClass
|
|
||||||
};
|
|
||||||
|
|
||||||
// transport
|
|
||||||
if (typeof define === "function" && define.amd) {
|
|
||||||
// AMD
|
|
||||||
define(classie);
|
|
||||||
} else {
|
|
||||||
// browser global
|
|
||||||
window.classie = classie;
|
|
||||||
}
|
|
||||||
|
|
||||||
})(window);
|
|
933
modules/default/alert/notificationFx.css
Normal file
@ -0,0 +1,933 @@
|
|||||||
|
/* Based on work by https://tympanus.net/codrops/licensing/ */
|
||||||
|
|
||||||
|
.ns-box {
|
||||||
|
background-color: rgba(0, 0, 0, 0.93);
|
||||||
|
padding: 17px;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
z-index: 1;
|
||||||
|
color: black;
|
||||||
|
font-size: 70%;
|
||||||
|
position: relative;
|
||||||
|
display: table;
|
||||||
|
word-wrap: break-word;
|
||||||
|
max-width: 100%;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-alert {
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #fff;
|
||||||
|
padding: 17px;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
z-index: 3;
|
||||||
|
color: white;
|
||||||
|
font-size: 70%;
|
||||||
|
position: fixed;
|
||||||
|
text-align: center;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
top: 40%;
|
||||||
|
width: 40%;
|
||||||
|
height: auto;
|
||||||
|
word-wrap: break-word;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.black_overlay {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 2;
|
||||||
|
background-color: rgba(0, 0, 0, 0.93);
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="ns-effect-"].ns-growl.ns-hide,
|
||||||
|
[class*=" ns-effect-"].ns-growl.ns-hide {
|
||||||
|
animation-direction: reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-flip {
|
||||||
|
transform-origin: 50% 100%;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-flip.ns-show,
|
||||||
|
.ns-effect-flip.ns-hide {
|
||||||
|
animation-name: animFlipFront;
|
||||||
|
animation-duration: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-flip.ns-hide {
|
||||||
|
animation-name: animFlipBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animFlipFront {
|
||||||
|
0% {
|
||||||
|
transform: perspective(1000px) rotate3d(1, 0, 0, -90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: perspective(1000px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animFlipBack {
|
||||||
|
0% {
|
||||||
|
transform: perspective(1000px) rotate3d(1, 0, 0, 90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: perspective(1000px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-bouncyflip.ns-show,
|
||||||
|
.ns-effect-bouncyflip.ns-hide {
|
||||||
|
animation-name: flipInX;
|
||||||
|
animation-duration: 0.8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flipInX {
|
||||||
|
0% {
|
||||||
|
transform: perspective(400px) rotate3d(1, 0, 0, -90deg);
|
||||||
|
transition-timing-function: ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: perspective(400px) rotate3d(1, 0, 0, 20deg);
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: perspective(400px) rotate3d(1, 0, 0, -10deg);
|
||||||
|
transition-timing-function: ease-in;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
transform: perspective(400px) rotate3d(1, 0, 0, 5deg);
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: perspective(400px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-bouncyflip.ns-hide {
|
||||||
|
animation-name: flipInXSimple;
|
||||||
|
animation-duration: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flipInXSimple {
|
||||||
|
0% {
|
||||||
|
transform: perspective(400px) rotate3d(1, 0, 0, -90deg);
|
||||||
|
transition-timing-function: ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: perspective(400px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-exploader {
|
||||||
|
transform-origin: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-exploader p {
|
||||||
|
padding: 0.25em 2em 0.25em 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-exploader.ns-show {
|
||||||
|
animation-name: animLoad;
|
||||||
|
animation-duration: 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animLoad {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale3d(0, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale3d(1, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-exploader.ns-hide {
|
||||||
|
animation-name: animFade;
|
||||||
|
animation-duration: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-exploader.ns-show .ns-box-inner,
|
||||||
|
.ns-effect-exploader.ns-show .ns-close {
|
||||||
|
animation-fill-mode: both;
|
||||||
|
animation-duration: 0.3s;
|
||||||
|
animation-delay: 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-exploader.ns-show .ns-close {
|
||||||
|
animation-name: animFade;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-exploader.ns-show .ns-box-inner {
|
||||||
|
animation-name: animFadeMove;
|
||||||
|
animation-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animFadeMove {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate3d(0, 10px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animFade {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-scale.ns-show,
|
||||||
|
.ns-effect-scale.ns-hide {
|
||||||
|
animation-name: animScale;
|
||||||
|
animation-duration: 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animScale {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate3d(0, 40px, 0) scale3d(0.1, 0.6, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-jelly.ns-show {
|
||||||
|
animation-name: animJelly;
|
||||||
|
animation-duration: 1s;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-jelly.ns-hide {
|
||||||
|
animation-name: animFade;
|
||||||
|
animation-duration: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animFade {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animJelly {
|
||||||
|
0% {
|
||||||
|
transform: matrix3d(0.7, 0, 0, 0, 0, 0.7, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
2.083333% {
|
||||||
|
transform: matrix3d(0.75266, 0, 0, 0, 0, 0.76342, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
4.166667% {
|
||||||
|
transform: matrix3d(0.81071, 0, 0, 0, 0, 0.84545, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
6.25% {
|
||||||
|
transform: matrix3d(0.86808, 0, 0, 0, 0, 0.9286, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
8.333333% {
|
||||||
|
transform: matrix3d(0.92038, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
10.416667% {
|
||||||
|
transform: matrix3d(0.96482, 0, 0, 0, 0, 1.05202, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
12.5% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1.08204, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
14.583333% {
|
||||||
|
transform: matrix3d(1.02563, 0, 0, 0, 0, 1.09149, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
16.666667% {
|
||||||
|
transform: matrix3d(1.04227, 0, 0, 0, 0, 1.08453, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
18.75% {
|
||||||
|
transform: matrix3d(1.05102, 0, 0, 0, 0, 1.06666, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
20.833333% {
|
||||||
|
transform: matrix3d(1.05334, 0, 0, 0, 0, 1.04355, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
22.916667% {
|
||||||
|
transform: matrix3d(1.05078, 0, 0, 0, 0, 1.02012, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
transform: matrix3d(1.04487, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
27.083333% {
|
||||||
|
transform: matrix3d(1.03699, 0, 0, 0, 0, 0.98534, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
29.166667% {
|
||||||
|
transform: matrix3d(1.02831, 0, 0, 0, 0, 0.97688, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
31.25% {
|
||||||
|
transform: matrix3d(1.01973, 0, 0, 0, 0, 0.97422, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.333333% {
|
||||||
|
transform: matrix3d(1.01191, 0, 0, 0, 0, 0.97618, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
35.416667% {
|
||||||
|
transform: matrix3d(1.00526, 0, 0, 0, 0, 0.98122, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
37.5% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.98773, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
39.583333% {
|
||||||
|
transform: matrix3d(0.99617, 0, 0, 0, 0, 0.99433, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
41.666667% {
|
||||||
|
transform: matrix3d(0.99368, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
43.75% {
|
||||||
|
transform: matrix3d(0.99237, 0, 0, 0, 0, 1.00413, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
45.833333% {
|
||||||
|
transform: matrix3d(0.99202, 0, 0, 0, 0, 1.00651, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
47.916667% {
|
||||||
|
transform: matrix3d(0.99241, 0, 0, 0, 0, 1.00726, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: matrix3d(0.99329, 0, 0, 0, 0, 1.00671, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
52.083333% {
|
||||||
|
transform: matrix3d(0.99447, 0, 0, 0, 0, 1.00529, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
54.166667% {
|
||||||
|
transform: matrix3d(0.99577, 0, 0, 0, 0, 1.00346, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
56.25% {
|
||||||
|
transform: matrix3d(0.99705, 0, 0, 0, 0, 1.0016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
58.333333% {
|
||||||
|
transform: matrix3d(0.99822, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
60.416667% {
|
||||||
|
transform: matrix3d(0.99921, 0, 0, 0, 0, 0.99884, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
62.5% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.99816, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
64.583333% {
|
||||||
|
transform: matrix3d(1.00057, 0, 0, 0, 0, 0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.666667% {
|
||||||
|
transform: matrix3d(1.00095, 0, 0, 0, 0, 0.99811, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
68.75% {
|
||||||
|
transform: matrix3d(1.00114, 0, 0, 0, 0, 0.99851, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
70.833333% {
|
||||||
|
transform: matrix3d(1.00119, 0, 0, 0, 0, 0.99903, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
72.916667% {
|
||||||
|
transform: matrix3d(1.00114, 0, 0, 0, 0, 0.99955, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
transform: matrix3d(1.001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
77.083333% {
|
||||||
|
transform: matrix3d(1.00083, 0, 0, 0, 0, 1.00033, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
79.166667% {
|
||||||
|
transform: matrix3d(1.00063, 0, 0, 0, 0, 1.00052, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
81.25% {
|
||||||
|
transform: matrix3d(1.00044, 0, 0, 0, 0, 1.00058, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
83.333333% {
|
||||||
|
transform: matrix3d(1.00027, 0, 0, 0, 0, 1.00053, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
85.416667% {
|
||||||
|
transform: matrix3d(1.00012, 0, 0, 0, 0, 1.00042, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
87.5% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1.00027, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
89.583333% {
|
||||||
|
transform: matrix3d(0.99991, 0, 0, 0, 0, 1.00013, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
91.666667% {
|
||||||
|
transform: matrix3d(0.99986, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
93.75% {
|
||||||
|
transform: matrix3d(0.99983, 0, 0, 0, 0, 0.99991, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
95.833333% {
|
||||||
|
transform: matrix3d(0.99982, 0, 0, 0, 0, 0.99985, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
97.916667% {
|
||||||
|
transform: matrix3d(0.99983, 0, 0, 0, 0, 0.99984, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-slide-left.ns-show {
|
||||||
|
animation-name: animSlideElasticLeft;
|
||||||
|
animation-duration: 1s;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animSlideElasticLeft {
|
||||||
|
0% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1000, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
1.666667% {
|
||||||
|
transform: matrix3d(1.92933, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -739.26805, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
3.333333% {
|
||||||
|
transform: matrix3d(1.96989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -521.82545, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
5% {
|
||||||
|
transform: matrix3d(1.70901, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -349.26115, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
6.666667% {
|
||||||
|
transform: matrix3d(1.4235, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -218.3238, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
8.333333% {
|
||||||
|
transform: matrix3d(1.21065, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -123.29848, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
transform: matrix3d(1.08167, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -57.59273, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
11.666667% {
|
||||||
|
transform: matrix3d(1.0165, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -14.72371, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
13.333333% {
|
||||||
|
transform: matrix3d(0.99057, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.12794, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
15% {
|
||||||
|
transform: matrix3d(0.98478, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 24.86339, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
16.666667% {
|
||||||
|
transform: matrix3d(0.98719, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.40503, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
18.333333% {
|
||||||
|
transform: matrix3d(0.9916, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 30.75275, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
transform: matrix3d(0.99541, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 28.10141, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
21.666667% {
|
||||||
|
transform: matrix3d(0.99795, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 23.98271, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
23.333333% {
|
||||||
|
transform: matrix3d(0.99936, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 19.40752, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14.99558, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
26.666667% {
|
||||||
|
transform: matrix3d(1.00021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 11.08575, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
28.333333% {
|
||||||
|
transform: matrix3d(1.00022, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.82507, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
30% {
|
||||||
|
transform: matrix3d(1.00016, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5.23737, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
31.666667% {
|
||||||
|
transform: matrix3d(1.0001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3.27389, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.333333% {
|
||||||
|
transform: matrix3d(1.00005, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.84893, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
35% {
|
||||||
|
transform: matrix3d(1.00002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.86364, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
36.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.22079, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
38.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16687, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.37284, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
41.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.45594, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
43.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.46116, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
45% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.4214, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
46.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.35963, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
48.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.29103, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.22487, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
51.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.16624, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
53.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.11734, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
55% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.07854, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
56.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.04909, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
58.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.02773, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.01295, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
61.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00331, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
63.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.0025, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
65% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00559, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00684, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
68.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00692, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00632, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
71.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00539, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
73.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00436, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00337, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
76.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00249, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
78.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00176, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00118, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
81.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00074, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
83.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00042, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
85% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00019, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
86.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.00005, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
88.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00004, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
90% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
91.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
93.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.0001, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
95% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00009, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
96.666667% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00008, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
98.333333% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.00007, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-slide-left.ns-hide {
|
||||||
|
animation-name: animSlideLeft;
|
||||||
|
animation-duration: 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animSlideLeft {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(-30px, 0, 0) translate3d(-100%, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-slide-right.ns-show {
|
||||||
|
animation: animSlideElasticRight 2000ms linear both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animSlideElasticRight {
|
||||||
|
0% {
|
||||||
|
transform: matrix3d(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1000, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
2.15% {
|
||||||
|
transform: matrix3d(1.486, 0, 0, 0, 0, 0.514, 0, 0, 0, 0, 1, 0, 664.594, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
4.1% {
|
||||||
|
transform: matrix3d(1.147, 0, 0, 0, 0, 0.853, 0, 0, 0, 0, 1, 0, 419.708, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
4.3% {
|
||||||
|
transform: matrix3d(1.121, 0, 0, 0, 0, 0.879, 0, 0, 0, 0, 1, 0, 398.136, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
6.46% {
|
||||||
|
transform: matrix3d(0.948, 0, 0, 0, 0, 1.052, 0, 0, 0, 0, 1, 0, 206.714, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
8.11% {
|
||||||
|
transform: matrix3d(0.908, 0, 0, 0, 0, 1.092, 0, 0, 0, 0, 1, 0, 105.491, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
8.61% {
|
||||||
|
transform: matrix3d(0.907, 0, 0, 0, 0, 1.093, 0, 0, 0, 0, 1, 0, 81.572, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
12.11% {
|
||||||
|
transform: matrix3d(0.95, 0, 0, 0, 0, 1.05, 0, 0, 0, 0, 1, 0, -18.434, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
14.16% {
|
||||||
|
transform: matrix3d(0.979, 0, 0, 0, 0, 1.021, 0, 0, 0, 0, 1, 0, -38.734, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
16.12% {
|
||||||
|
transform: matrix3d(0.997, 0, 0, 0, 0, 1.003, 0, 0, 0, 0, 1, 0, -43.356, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
19.72% {
|
||||||
|
transform: matrix3d(1.006, 0, 0, 0, 0, 0.994, 0, 0, 0, 0, 1, 0, -34.155, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
27.23% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -7.839, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
30.83% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1.951, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
38.34% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.037, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
41.99% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.812, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.159, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
60.56% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -0.025, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
82.78% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0.001, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-slide-right.ns-hide {
|
||||||
|
animation-name: animSlideRight;
|
||||||
|
animation-duration: 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animSlideRight {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(30px, 0, 0) translate3d(100%, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-slide-center.ns-show {
|
||||||
|
animation: animSlideElasticCenter 2000ms linear both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animSlideElasticCenter {
|
||||||
|
0% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, -300, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
2.15% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1.971, 0, 0, 0, 0, 1, 0, 0, -199.378, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
4.1% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1.294, 0, 0, 0, 0, 1, 0, 0, -125.912, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
4.3% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1.243, 0, 0, 0, 0, 1, 0, 0, -119.441, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
6.46% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.895, 0, 0, 0, 0, 1, 0, 0, -62.014, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
8.11% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.817, 0, 0, 0, 0, 1, 0, 0, -31.647, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
8.61% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.813, 0, 0, 0, 0, 1, 0, 0, -24.472, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
12.11% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.9, 0, 0, 0, 0, 1, 0, 0, 5.53, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
14.16% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.959, 0, 0, 0, 0, 1, 0, 0, 11.62, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
16.12% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.994, 0, 0, 0, 0, 1, 0, 0, 13.007, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
19.72% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1.012, 0, 0, 0, 0, 1, 0, 0, 10.247, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
27.23% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2.352, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
30.83% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 0.999, 0, 0, 0, 0, 1, 0, 0, 0.585, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
38.34% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -0.311, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
41.99% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -0.244, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -0.048, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
60.56% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0.007, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
82.78% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-slide-center.ns-hide {
|
||||||
|
animation-name: animSlideCenter;
|
||||||
|
animation-duration: 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animSlideCenter {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(0, -30px, 0) translate3d(0, -100%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ns-effect-genie.ns-show,
|
||||||
|
.ns-effect-genie.ns-hide {
|
||||||
|
animation-name: animGenie;
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animGenie {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate3d(0, calc(200% + 30px), 0) scale3d(0, 1, 1);
|
||||||
|
animation-timing-function: ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
opacity: 0.5;
|
||||||
|
transform: translate3d(0, 0, 0) scale3d(0.02, 1.1, 1);
|
||||||
|
animation-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
70% {
|
||||||
|
opacity: 0.6;
|
||||||
|
transform: translate3d(0, -40px, 0) scale3d(0.8, 1.1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +1,21 @@
|
|||||||
/**
|
/**
|
||||||
|
* Based on work by
|
||||||
|
*
|
||||||
* notificationFx.js v1.0.0
|
* notificationFx.js v1.0.0
|
||||||
* http://www.codrops.com
|
* https://tympanus.net/codrops/
|
||||||
*
|
*
|
||||||
* Licensed under the MIT license.
|
* Licensed under the MIT license.
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
* https://opensource.org/licenses/mit-license.php
|
||||||
*
|
*
|
||||||
* Copyright 2014, Codrops
|
* Copyright 2014, Codrops
|
||||||
* http://www.codrops.com
|
* https://tympanus.net/codrops/
|
||||||
*/
|
*/
|
||||||
// jscs:disable
|
(function (window) {
|
||||||
;(function(window) {
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var docElem = window.document.documentElement,
|
|
||||||
support = {animations: Modernizr.cssanimations},
|
|
||||||
animEndEventNames = {
|
|
||||||
"WebkitAnimation": "webkitAnimationEnd",
|
|
||||||
"OAnimation": "oAnimationEnd",
|
|
||||||
"msAnimation": "MSAnimationEnd",
|
|
||||||
"animation": "animationend"
|
|
||||||
},
|
|
||||||
// animation end event name
|
|
||||||
animEndEventName = animEndEventNames[ Modernizr.prefixed("animation") ];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* extend obj function
|
* extend obj function
|
||||||
*/
|
*/
|
||||||
function extend(a, b) {
|
function extend(a, b) {
|
||||||
for (var key in b) {
|
for (let key in b) {
|
||||||
if (b.hasOwnProperty(key)) {
|
if (b.hasOwnProperty(key)) {
|
||||||
a[key] = b[key];
|
a[key] = b[key];
|
||||||
}
|
}
|
||||||
@ -70,19 +57,23 @@
|
|||||||
ttl: 6000,
|
ttl: 6000,
|
||||||
al_no: "ns-box",
|
al_no: "ns-box",
|
||||||
// callbacks
|
// callbacks
|
||||||
onClose: function() { return false; },
|
onClose: function () {
|
||||||
onOpen: function() { return false; }
|
return false;
|
||||||
|
},
|
||||||
|
onOpen: function () {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init function
|
* init function
|
||||||
* initialize and cache some vars
|
* initialize and cache some vars
|
||||||
*/
|
*/
|
||||||
NotificationFx.prototype._init = function() {
|
NotificationFx.prototype._init = function () {
|
||||||
// create HTML structure
|
// create HTML structure
|
||||||
this.ntf = document.createElement("div");
|
this.ntf = document.createElement("div");
|
||||||
this.ntf.className = this.options.al_no + " ns-" + this.options.layout + " ns-effect-" + this.options.effect + " ns-type-" + this.options.type;
|
this.ntf.className = this.options.al_no + " ns-" + this.options.layout + " ns-effect-" + this.options.effect + " ns-type-" + this.options.type;
|
||||||
var strinner = "<div class=\"ns-box-inner\">";
|
let strinner = '<div class="ns-box-inner">';
|
||||||
strinner += this.options.message;
|
strinner += this.options.message;
|
||||||
strinner += "</div>";
|
strinner += "</div>";
|
||||||
this.ntf.innerHTML = strinner;
|
this.ntf.innerHTML = strinner;
|
||||||
@ -91,13 +82,12 @@
|
|||||||
this.options.wrapper.insertBefore(this.ntf, this.options.wrapper.nextSibling);
|
this.options.wrapper.insertBefore(this.ntf, this.options.wrapper.nextSibling);
|
||||||
|
|
||||||
// dismiss after [options.ttl]ms
|
// dismiss after [options.ttl]ms
|
||||||
var self = this;
|
|
||||||
if (this.options.ttl) {
|
if (this.options.ttl) {
|
||||||
this.dismissttl = setTimeout(function() {
|
this.dismissttl = setTimeout(() => {
|
||||||
if (self.active) {
|
if (this.active) {
|
||||||
self.dismiss();
|
this.dismiss();
|
||||||
}
|
}
|
||||||
}, this.options.ttl);
|
}, this.options.ttl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// init events
|
// init events
|
||||||
@ -107,59 +97,54 @@
|
|||||||
/**
|
/**
|
||||||
* init events
|
* init events
|
||||||
*/
|
*/
|
||||||
NotificationFx.prototype._initEvents = function() {
|
NotificationFx.prototype._initEvents = function () {
|
||||||
var self = this;
|
|
||||||
// dismiss notification by tapping on it if someone has a touchscreen
|
// dismiss notification by tapping on it if someone has a touchscreen
|
||||||
this.ntf.querySelector(".ns-box-inner").addEventListener("click", function() { self.dismiss(); });
|
this.ntf.querySelector(".ns-box-inner").addEventListener("click", () => {
|
||||||
|
this.dismiss();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* show the notification
|
* show the notification
|
||||||
*/
|
*/
|
||||||
NotificationFx.prototype.show = function() {
|
NotificationFx.prototype.show = function () {
|
||||||
this.active = true;
|
this.active = true;
|
||||||
classie.remove(this.ntf, "ns-hide");
|
this.ntf.classList.remove("ns-hide");
|
||||||
classie.add(this.ntf, "ns-show");
|
this.ntf.classList.add("ns-show");
|
||||||
this.options.onOpen();
|
this.options.onOpen();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dismiss the notification
|
* dismiss the notification
|
||||||
*/
|
*/
|
||||||
NotificationFx.prototype.dismiss = function() {
|
NotificationFx.prototype.dismiss = function () {
|
||||||
var self = this;
|
|
||||||
this.active = false;
|
this.active = false;
|
||||||
clearTimeout(this.dismissttl);
|
clearTimeout(this.dismissttl);
|
||||||
classie.remove(this.ntf, "ns-show");
|
this.ntf.classList.remove("ns-show");
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
classie.add(self.ntf, "ns-hide");
|
this.ntf.classList.add("ns-hide");
|
||||||
|
|
||||||
// callback
|
// callback
|
||||||
self.options.onClose();
|
this.options.onClose();
|
||||||
}, 25);
|
}, 25);
|
||||||
|
|
||||||
// after animation ends remove ntf from the DOM
|
// after animation ends remove ntf from the DOM
|
||||||
var onEndAnimationFn = function(ev) {
|
const onEndAnimationFn = (ev) => {
|
||||||
if (support.animations) {
|
if (ev.target !== this.ntf) {
|
||||||
if (ev.target !== self.ntf) return false;
|
return false;
|
||||||
this.removeEventListener(animEndEventName, onEndAnimationFn);
|
|
||||||
}
|
}
|
||||||
|
this.ntf.removeEventListener("animationend", onEndAnimationFn);
|
||||||
|
|
||||||
if (this.parentNode === self.options.wrapper) {
|
if (ev.target.parentNode === this.options.wrapper) {
|
||||||
self.options.wrapper.removeChild(this);
|
this.options.wrapper.removeChild(this.ntf);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (support.animations) {
|
this.ntf.addEventListener("animationend", onEndAnimationFn);
|
||||||
this.ntf.addEventListener(animEndEventName, onEndAnimationFn);
|
|
||||||
} else {
|
|
||||||
onEndAnimationFn();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add to global namespace
|
* add to global namespace
|
||||||
*/
|
*/
|
||||||
window.NotificationFx = NotificationFx;
|
window.NotificationFx = NotificationFx;
|
||||||
|
|
||||||
})(window);
|
})(window);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror нотификация",
|
"sysTitle": "MagicMirror нотификация",
|
||||||
"welcome": "Добре дошли, стартирането беше успешно"
|
"welcome": "Добре дошли, стартирането беше успешно"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror Notifikation",
|
"sysTitle": "MagicMirror Notifikation",
|
||||||
"welcome": "Velkommen, modulet er succesfuldt startet!"
|
"welcome": "Velkommen, modulet er succesfuldt startet!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror Benachrichtigung",
|
"sysTitle": "MagicMirror Benachrichtigung",
|
||||||
"welcome": "Willkommen, Start war erfolgreich!"
|
"welcome": "Willkommen, Start war erfolgreich!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror Notification",
|
"sysTitle": "MagicMirror Notification",
|
||||||
"welcome": "Welcome, start was successful!"
|
"welcome": "Welcome, start was successful!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror Notificaciones",
|
"sysTitle": "MagicMirror Notificaciones",
|
||||||
"welcome": "Bienvenido, ¡se iniciado correctamente!"
|
"welcome": "Bienvenido, ¡se iniciado correctamente!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror Notification",
|
"sysTitle": "MagicMirror Notification",
|
||||||
"welcome": "Bienvenue, le démarrage a été un succès!"
|
"welcome": "Bienvenue, le démarrage a été un succès!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror értesítés",
|
"sysTitle": "MagicMirror értesítés",
|
||||||
"welcome": "Üdvözöljük, indulás sikeres!"
|
"welcome": "Üdvözöljük, indulás sikeres!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror Notificatie",
|
"sysTitle": "MagicMirror Notificatie",
|
||||||
"welcome": "Welkom, Succesvol gestart!"
|
"welcome": "Welkom, Succesvol gestart!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"sysTitle": "MagicMirror Уведомление",
|
"sysTitle": "MagicMirror Уведомление",
|
||||||
"welcome": "Добро пожаловать, старт был успешным!"
|
"welcome": "Добро пожаловать, старт был успешным!"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Module: Calendar
|
# Module: Calendar
|
||||||
|
|
||||||
The `calendar` module is one of the default modules of the MagicMirror.
|
The `calendar` module is one of the default modules of the MagicMirror.
|
||||||
This module displays events from a public .ical calendar. It can combine multiple calendars.
|
This module displays events from a public .ical calendar. It can combine multiple calendars.
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
.calendar .symbol span {
|
.calendar .symbol span {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
-ms-transform: translate(0, 2px); /* IE 9 */
|
|
||||||
-webkit-transform: translate(0, 2px); /* Safari */
|
|
||||||
transform: translate(0, 2px);
|
transform: translate(0, 2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
/* global Module */
|
/* global cloneObject */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: Calendar
|
* Module: Calendar
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Module.register("calendar", {
|
Module.register("calendar", {
|
||||||
|
|
||||||
// Define module defaults
|
// Define module defaults
|
||||||
defaults: {
|
defaults: {
|
||||||
maximumEntries: 10, // Total Maximum Entries
|
maximumEntries: 10, // Total Maximum Entries
|
||||||
maximumNumberOfDays: 365,
|
maximumNumberOfDays: 365,
|
||||||
displaySymbol: true,
|
displaySymbol: true,
|
||||||
defaultSymbol: "calendar", // Fontawesome Symbol see http://fontawesome.io/cheatsheet/
|
defaultSymbol: "calendar", // Fontawesome Symbol see https://fontawesome.com/cheatsheet?from=io
|
||||||
showLocation: false,
|
showLocation: false,
|
||||||
displayRepeatingCountTitle: false,
|
displayRepeatingCountTitle: false,
|
||||||
defaultRepeatingCountTitle: "",
|
defaultRepeatingCountTitle: "",
|
||||||
@ -40,8 +38,8 @@ Module.register("calendar", {
|
|||||||
calendars: [
|
calendars: [
|
||||||
{
|
{
|
||||||
symbol: "calendar",
|
symbol: "calendar",
|
||||||
url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics",
|
url: "https://www.calendarlabs.com/templates/ical/US-Holidays.ics"
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
titleReplace: {
|
titleReplace: {
|
||||||
"De verjaardag van ": "",
|
"De verjaardag van ": "",
|
||||||
@ -86,7 +84,7 @@ Module.register("calendar", {
|
|||||||
var calendarConfig = {
|
var calendarConfig = {
|
||||||
maximumEntries: calendar.maximumEntries,
|
maximumEntries: calendar.maximumEntries,
|
||||||
maximumNumberOfDays: calendar.maximumNumberOfDays,
|
maximumNumberOfDays: calendar.maximumNumberOfDays,
|
||||||
broadcastPastEvents: calendar.broadcastPastEvents,
|
broadcastPastEvents: calendar.broadcastPastEvents
|
||||||
};
|
};
|
||||||
if (calendar.symbolClass === "undefined" || calendar.symbolClass === null) {
|
if (calendar.symbolClass === "undefined" || calendar.symbolClass === null) {
|
||||||
calendarConfig.symbolClass = "";
|
calendarConfig.symbolClass = "";
|
||||||
@ -99,7 +97,7 @@ Module.register("calendar", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we check user and password here for backwards compatibility with old configs
|
// we check user and password here for backwards compatibility with old configs
|
||||||
if(calendar.user && calendar.pass) {
|
if (calendar.user && calendar.pass) {
|
||||||
Log.warn("Deprecation warning: Please update your calendar authentication configuration.");
|
Log.warn("Deprecation warning: Please update your calendar authentication configuration.");
|
||||||
Log.warn("https://github.com/MichMich/MagicMirror/tree/v2.1.2/modules/default/calendar#calendar-authentication-options");
|
Log.warn("https://github.com/MichMich/MagicMirror/tree/v2.1.2/modules/default/calendar#calendar-authentication-options");
|
||||||
calendar.auth = {
|
calendar.auth = {
|
||||||
@ -113,7 +111,7 @@ Module.register("calendar", {
|
|||||||
// Trigger ADD_CALENDAR every fetchInterval to make sure there is always a calendar
|
// Trigger ADD_CALENDAR every fetchInterval to make sure there is always a calendar
|
||||||
// fetcher running on the server side.
|
// fetcher running on the server side.
|
||||||
var self = this;
|
var self = this;
|
||||||
setInterval(function() {
|
setInterval(function () {
|
||||||
self.addCalendar(calendar.url, calendar.auth, calendarConfig);
|
self.addCalendar(calendar.url, calendar.auth, calendarConfig);
|
||||||
}, self.config.fetchInterval);
|
}, self.config.fetchInterval);
|
||||||
}
|
}
|
||||||
@ -145,13 +143,12 @@ Module.register("calendar", {
|
|||||||
|
|
||||||
// Override dom generator.
|
// Override dom generator.
|
||||||
getDom: function () {
|
getDom: function () {
|
||||||
|
|
||||||
var events = this.createEventList();
|
var events = this.createEventList();
|
||||||
var wrapper = document.createElement("table");
|
var wrapper = document.createElement("table");
|
||||||
wrapper.className = this.config.tableClass;
|
wrapper.className = this.config.tableClass;
|
||||||
|
|
||||||
if (events.length === 0) {
|
if (events.length === 0) {
|
||||||
wrapper.innerHTML = (this.loaded) ? this.translate("EMPTY") : this.translate("LOADING");
|
wrapper.innerHTML = this.loaded ? this.translate("EMPTY") : this.translate("LOADING");
|
||||||
wrapper.className = this.config.tableClass + " dimmed";
|
wrapper.className = this.config.tableClass + " dimmed";
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
@ -170,8 +167,8 @@ Module.register("calendar", {
|
|||||||
for (var e in events) {
|
for (var e in events) {
|
||||||
var event = events[e];
|
var event = events[e];
|
||||||
var dateAsString = moment(event.startDate, "x").format(this.config.dateFormat);
|
var dateAsString = moment(event.startDate, "x").format(this.config.dateFormat);
|
||||||
if(this.config.timeFormat === "dateheaders"){
|
if (this.config.timeFormat === "dateheaders") {
|
||||||
if(lastSeenDate !== dateAsString){
|
if (lastSeenDate !== dateAsString) {
|
||||||
var dateRow = document.createElement("tr");
|
var dateRow = document.createElement("tr");
|
||||||
dateRow.className = "normal";
|
dateRow.className = "normal";
|
||||||
var dateCell = document.createElement("td");
|
var dateCell = document.createElement("td");
|
||||||
@ -182,9 +179,10 @@ Module.register("calendar", {
|
|||||||
dateRow.appendChild(dateCell);
|
dateRow.appendChild(dateCell);
|
||||||
wrapper.appendChild(dateRow);
|
wrapper.appendChild(dateRow);
|
||||||
|
|
||||||
if (e >= startFade) { //fading
|
if (e >= startFade) {
|
||||||
|
//fading
|
||||||
currentFadeStep = e - startFade;
|
currentFadeStep = e - startFade;
|
||||||
dateRow.style.opacity = 1 - (1 / fadeSteps * currentFadeStep);
|
dateRow.style.opacity = 1 - (1 / fadeSteps) * currentFadeStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSeenDate = dateAsString;
|
lastSeenDate = dateAsString;
|
||||||
@ -210,20 +208,20 @@ Module.register("calendar", {
|
|||||||
symbolWrapper.className = "symbol align-right " + symbolClass;
|
symbolWrapper.className = "symbol align-right " + symbolClass;
|
||||||
|
|
||||||
var symbols = this.symbolsForUrl(event.url);
|
var symbols = this.symbolsForUrl(event.url);
|
||||||
if(typeof symbols === "string") {
|
if (typeof symbols === "string") {
|
||||||
symbols = [symbols];
|
symbols = [symbols];
|
||||||
}
|
}
|
||||||
|
|
||||||
for(var i = 0; i < symbols.length; i++) {
|
for (var i = 0; i < symbols.length; i++) {
|
||||||
var symbol = document.createElement("span");
|
var symbol = document.createElement("span");
|
||||||
symbol.className = "fa fa-fw fa-" + symbols[i];
|
symbol.className = "fa fa-fw fa-" + symbols[i];
|
||||||
if(i > 0){
|
if (i > 0) {
|
||||||
symbol.style.paddingLeft = "5px";
|
symbol.style.paddingLeft = "5px";
|
||||||
}
|
}
|
||||||
symbolWrapper.appendChild(symbol);
|
symbolWrapper.appendChild(symbol);
|
||||||
}
|
}
|
||||||
eventWrapper.appendChild(symbolWrapper);
|
eventWrapper.appendChild(symbolWrapper);
|
||||||
} else if(this.config.timeFormat === "dateheaders"){
|
} else if (this.config.timeFormat === "dateheaders") {
|
||||||
var blankCell = document.createElement("td");
|
var blankCell = document.createElement("td");
|
||||||
blankCell.innerHTML = " ";
|
blankCell.innerHTML = " ";
|
||||||
eventWrapper.appendChild(blankCell);
|
eventWrapper.appendChild(blankCell);
|
||||||
@ -233,7 +231,6 @@ Module.register("calendar", {
|
|||||||
repeatingCountTitle = "";
|
repeatingCountTitle = "";
|
||||||
|
|
||||||
if (this.config.displayRepeatingCountTitle && event.firstYear !== undefined) {
|
if (this.config.displayRepeatingCountTitle && event.firstYear !== undefined) {
|
||||||
|
|
||||||
repeatingCountTitle = this.countTitleForUrl(event.url);
|
repeatingCountTitle = this.countTitleForUrl(event.url);
|
||||||
|
|
||||||
if (repeatingCountTitle !== "") {
|
if (repeatingCountTitle !== "") {
|
||||||
@ -254,17 +251,15 @@ Module.register("calendar", {
|
|||||||
titleWrapper.className = "title " + titleClass;
|
titleWrapper.className = "title " + titleClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.config.timeFormat === "dateheaders"){
|
var timeWrapper;
|
||||||
|
|
||||||
|
if (this.config.timeFormat === "dateheaders") {
|
||||||
if (event.fullDayEvent) {
|
if (event.fullDayEvent) {
|
||||||
titleWrapper.colSpan = "2";
|
titleWrapper.colSpan = "2";
|
||||||
titleWrapper.align = "left";
|
titleWrapper.align = "left";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
timeWrapper = document.createElement("td");
|
||||||
var timeClass = this.timeClassForUrl(event.url);
|
timeWrapper.className = "time light " + this.timeClassForUrl(event.url);
|
||||||
var timeWrapper = document.createElement("td");
|
|
||||||
timeWrapper.className = "time light " + timeClass;
|
|
||||||
timeWrapper.align = "left";
|
timeWrapper.align = "left";
|
||||||
timeWrapper.style.paddingLeft = "2px";
|
timeWrapper.style.paddingLeft = "2px";
|
||||||
timeWrapper.innerHTML = moment(event.startDate, "x").format("LT");
|
timeWrapper.innerHTML = moment(event.startDate, "x").format("LT");
|
||||||
@ -274,7 +269,7 @@ Module.register("calendar", {
|
|||||||
|
|
||||||
eventWrapper.appendChild(titleWrapper);
|
eventWrapper.appendChild(titleWrapper);
|
||||||
} else {
|
} else {
|
||||||
var timeWrapper = document.createElement("td");
|
timeWrapper = document.createElement("td");
|
||||||
|
|
||||||
eventWrapper.appendChild(titleWrapper);
|
eventWrapper.appendChild(titleWrapper);
|
||||||
//console.log(event.today);
|
//console.log(event.today);
|
||||||
@ -299,14 +294,14 @@ Module.register("calendar", {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Check to see if the user displays absolute or relative dates with their events
|
/* Check to see if the user displays absolute or relative dates with their events
|
||||||
* Also check to see if an event is happening within an 'urgency' time frameElement
|
* Also check to see if an event is happening within an 'urgency' time frameElement
|
||||||
* For example, if the user set an .urgency of 7 days, those events that fall within that
|
* For example, if the user set an .urgency of 7 days, those events that fall within that
|
||||||
* time frame will be displayed with 'in xxx' time format or moment.fromNow()
|
* time frame will be displayed with 'in xxx' time format or moment.fromNow()
|
||||||
*
|
*
|
||||||
* Note: this needs to be put in its own function, as the whole thing repeats again verbatim
|
* Note: this needs to be put in its own function, as the whole thing repeats again verbatim
|
||||||
*/
|
*/
|
||||||
if (this.config.timeFormat === "absolute") {
|
if (this.config.timeFormat === "absolute") {
|
||||||
if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) {
|
if (this.config.urgency > 1 && event.startDate - now < this.config.urgency * oneDay) {
|
||||||
// This event falls within the config.urgency period that the user has set
|
// This event falls within the config.urgency period that the user has set
|
||||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
|
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
|
||||||
} else {
|
} else {
|
||||||
@ -316,9 +311,9 @@ Module.register("calendar", {
|
|||||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
|
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(this.config.showEnd){
|
if (this.config.showEnd) {
|
||||||
timeWrapper.innerHTML += "-" ;
|
timeWrapper.innerHTML += "-";
|
||||||
timeWrapper.innerHTML += this.capFirst(moment(event.endDate , "x").format(this.config.fullDayEventDateFormat));
|
timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.fullDayEventDateFormat));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (event.startDate >= new Date()) {
|
if (event.startDate >= new Date()) {
|
||||||
@ -328,7 +323,7 @@ Module.register("calendar", {
|
|||||||
// If event is within 6 hour, display 'in xxx' time format or moment.fromNow()
|
// If event is within 6 hour, display 'in xxx' time format or moment.fromNow()
|
||||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
|
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
|
||||||
} else {
|
} else {
|
||||||
if(this.config.timeFormat === "absolute" && !this.config.nextDaysRelative) {
|
if (this.config.timeFormat === "absolute" && !this.config.nextDaysRelative) {
|
||||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
|
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
|
||||||
} else {
|
} else {
|
||||||
// Otherwise just say 'Today/Tomorrow at such-n-such time'
|
// Otherwise just say 'Today/Tomorrow at such-n-such time'
|
||||||
@ -337,14 +332,14 @@ Module.register("calendar", {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Check to see if the user displays absolute or relative dates with their events
|
/* Check to see if the user displays absolute or relative dates with their events
|
||||||
* Also check to see if an event is happening within an 'urgency' time frameElement
|
* Also check to see if an event is happening within an 'urgency' time frameElement
|
||||||
* For example, if the user set an .urgency of 7 days, those events that fall within that
|
* For example, if the user set an .urgency of 7 days, those events that fall within that
|
||||||
* time frame will be displayed with 'in xxx' time format or moment.fromNow()
|
* time frame will be displayed with 'in xxx' time format or moment.fromNow()
|
||||||
*
|
*
|
||||||
* Note: this needs to be put in its own function, as the whole thing repeats again verbatim
|
* Note: this needs to be put in its own function, as the whole thing repeats again verbatim
|
||||||
*/
|
*/
|
||||||
if (this.config.timeFormat === "absolute") {
|
if (this.config.timeFormat === "absolute") {
|
||||||
if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) {
|
if (this.config.urgency > 1 && event.startDate - now < this.config.urgency * oneDay) {
|
||||||
// This event falls within the config.urgency period that the user has set
|
// This event falls within the config.urgency period that the user has set
|
||||||
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
|
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
|
||||||
} else {
|
} else {
|
||||||
@ -365,13 +360,11 @@ Module.register("calendar", {
|
|||||||
if (this.config.showEnd) {
|
if (this.config.showEnd) {
|
||||||
timeWrapper.innerHTML += "-";
|
timeWrapper.innerHTML += "-";
|
||||||
timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.dateEndFormat));
|
timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.dateEndFormat));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
|
//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
|
||||||
//console.log(event);
|
//console.log(event);
|
||||||
var timeClass = this.timeClassForUrl(event.url);
|
timeWrapper.className = "time light " + this.timeClassForUrl(event.url);
|
||||||
timeWrapper.className = "time light " + timeClass;
|
|
||||||
eventWrapper.appendChild(timeWrapper);
|
eventWrapper.appendChild(timeWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +373,7 @@ Module.register("calendar", {
|
|||||||
// Create fade effect.
|
// Create fade effect.
|
||||||
if (e >= startFade) {
|
if (e >= startFade) {
|
||||||
currentFadeStep = e - startFade;
|
currentFadeStep = e - startFade;
|
||||||
eventWrapper.style.opacity = 1 - (1 / fadeSteps * currentFadeStep);
|
eventWrapper.style.opacity = 1 - (1 / fadeSteps) * currentFadeStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.showLocation) {
|
if (this.config.showLocation) {
|
||||||
@ -403,7 +396,7 @@ Module.register("calendar", {
|
|||||||
|
|
||||||
if (e >= startFade) {
|
if (e >= startFade) {
|
||||||
currentFadeStep = e - startFade;
|
currentFadeStep = e - startFade;
|
||||||
locationRow.style.opacity = 1 - (1 / fadeSteps * currentFadeStep);
|
locationRow.style.opacity = 1 - (1 / fadeSteps) * currentFadeStep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,20 +413,17 @@ Module.register("calendar", {
|
|||||||
* @param {number} timeFormat Specifies either 12 or 24 hour time format
|
* @param {number} timeFormat Specifies either 12 or 24 hour time format
|
||||||
* @returns {moment.LocaleSpecification}
|
* @returns {moment.LocaleSpecification}
|
||||||
*/
|
*/
|
||||||
getLocaleSpecification: function(timeFormat) {
|
getLocaleSpecification: function (timeFormat) {
|
||||||
switch (timeFormat) {
|
switch (timeFormat) {
|
||||||
case 12: {
|
case 12: {
|
||||||
return { longDateFormat: {LT: "h:mm A"} };
|
return { longDateFormat: { LT: "h:mm A" } };
|
||||||
break;
|
}
|
||||||
}
|
case 24: {
|
||||||
case 24: {
|
return { longDateFormat: { LT: "HH:mm" } };
|
||||||
return { longDateFormat: {LT: "HH:mm"} };
|
}
|
||||||
break;
|
default: {
|
||||||
}
|
return { longDateFormat: { LT: moment.localeData().longDateFormat("LT") } };
|
||||||
default: {
|
}
|
||||||
return { longDateFormat: {LT: moment.localeData().longDateFormat("LT")} };
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -469,37 +459,37 @@ Module.register("calendar", {
|
|||||||
var calendar = this.calendarData[c];
|
var calendar = this.calendarData[c];
|
||||||
for (var e in calendar) {
|
for (var e in calendar) {
|
||||||
var event = JSON.parse(JSON.stringify(calendar[e])); // clone object
|
var event = JSON.parse(JSON.stringify(calendar[e])); // clone object
|
||||||
if(event.endDate < now) {
|
if (event.endDate < now) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(this.config.hidePrivate) {
|
if (this.config.hidePrivate) {
|
||||||
if(event.class === "PRIVATE") {
|
if (event.class === "PRIVATE") {
|
||||||
// do not add the current event, skip it
|
// do not add the current event, skip it
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(this.config.hideOngoing) {
|
|
||||||
if(event.startDate < now) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(this.listContainsEvent(events,event)){
|
if (this.config.hideOngoing) {
|
||||||
|
if (event.startDate < now) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.listContainsEvent(events, event)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
event.url = c;
|
event.url = c;
|
||||||
event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000);
|
event.today = event.startDate >= today && event.startDate < today + 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
/* if sliceMultiDayEvents is set to true, multiday events (events exceeding at least one midnight) are sliced into days,
|
/* if sliceMultiDayEvents is set to true, multiday events (events exceeding at least one midnight) are sliced into days,
|
||||||
* otherwise, esp. in dateheaders mode it is not clear how long these events are.
|
* otherwise, esp. in dateheaders mode it is not clear how long these events are.
|
||||||
*/
|
*/
|
||||||
var maxCount = Math.ceil(((event.endDate - 1) - moment(event.startDate, "x").endOf("day").format("x"))/(1000*60*60*24)) + 1;
|
var maxCount = Math.ceil((event.endDate - 1 - moment(event.startDate, "x").endOf("day").format("x")) / (1000 * 60 * 60 * 24)) + 1;
|
||||||
if (this.config.sliceMultiDayEvents && maxCount > 1) {
|
if (this.config.sliceMultiDayEvents && maxCount > 1) {
|
||||||
var splitEvents = [];
|
var splitEvents = [];
|
||||||
var midnight = moment(event.startDate, "x").clone().startOf("day").add(1, "day").format("x");
|
var midnight = moment(event.startDate, "x").clone().startOf("day").add(1, "day").format("x");
|
||||||
var count = 1;
|
var count = 1;
|
||||||
while (event.endDate > midnight) {
|
while (event.endDate > midnight) {
|
||||||
var thisEvent = JSON.parse(JSON.stringify(event)); // clone object
|
var thisEvent = JSON.parse(JSON.stringify(event)); // clone object
|
||||||
thisEvent.today = thisEvent.startDate >= today && thisEvent.startDate < (today + 24 * 60 * 60 * 1000);
|
thisEvent.today = thisEvent.startDate >= today && thisEvent.startDate < today + 24 * 60 * 60 * 1000;
|
||||||
thisEvent.endDate = midnight;
|
thisEvent.endDate = midnight;
|
||||||
thisEvent.title += " (" + count + "/" + maxCount + ")";
|
thisEvent.title += " (" + count + "/" + maxCount + ")";
|
||||||
splitEvents.push(thisEvent);
|
splitEvents.push(thisEvent);
|
||||||
@ -509,11 +499,11 @@ Module.register("calendar", {
|
|||||||
midnight = moment(midnight, "x").add(1, "day").format("x"); // next day
|
midnight = moment(midnight, "x").add(1, "day").format("x"); // next day
|
||||||
}
|
}
|
||||||
// Last day
|
// Last day
|
||||||
event.title += " ("+count+"/"+maxCount+")";
|
event.title += " (" + count + "/" + maxCount + ")";
|
||||||
splitEvents.push(event);
|
splitEvents.push(event);
|
||||||
|
|
||||||
for (event of splitEvents) {
|
for (event of splitEvents) {
|
||||||
if ((event.endDate > now) && (event.endDate <= future)) {
|
if (event.endDate > now && event.endDate <= future) {
|
||||||
events.push(event);
|
events.push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,9 +519,9 @@ Module.register("calendar", {
|
|||||||
return events.slice(0, this.config.maximumEntries);
|
return events.slice(0, this.config.maximumEntries);
|
||||||
},
|
},
|
||||||
|
|
||||||
listContainsEvent: function(eventList, event){
|
listContainsEvent: function (eventList, event) {
|
||||||
for(var evt of eventList){
|
for (var evt of eventList) {
|
||||||
if(evt.title === event.title && parseInt(evt.startDate) === parseInt(event.startDate)){
|
if (evt.title === event.title && parseInt(evt.startDate) === parseInt(event.startDate)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,7 +544,7 @@ Module.register("calendar", {
|
|||||||
titleClass: calendarConfig.titleClass,
|
titleClass: calendarConfig.titleClass,
|
||||||
timeClass: calendarConfig.timeClass,
|
timeClass: calendarConfig.timeClass,
|
||||||
auth: auth,
|
auth: auth,
|
||||||
broadcastPastEvents: calendarConfig.broadcastPastEvents || this.config.broadcastPastEvents,
|
broadcastPastEvents: calendarConfig.broadcastPastEvents || this.config.broadcastPastEvents
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -681,8 +671,9 @@ Module.register("calendar", {
|
|||||||
|
|
||||||
for (var i = 0; i < words.length; i++) {
|
for (var i = 0; i < words.length; i++) {
|
||||||
var word = words[i];
|
var word = words[i];
|
||||||
if (currentLine.length + word.length < (typeof maxLength === "number" ? maxLength : 25) - 1) { // max - 1 to account for a space
|
if (currentLine.length + word.length < (typeof maxLength === "number" ? maxLength : 25) - 1) {
|
||||||
currentLine += (word + " ");
|
// max - 1 to account for a space
|
||||||
|
currentLine += word + " ";
|
||||||
} else {
|
} else {
|
||||||
line++;
|
line++;
|
||||||
if (line > maxTitleLines - 1) {
|
if (line > maxTitleLines - 1) {
|
||||||
@ -693,9 +684,9 @@ Module.register("calendar", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentLine.length > 0) {
|
if (currentLine.length > 0) {
|
||||||
temp += (currentLine + "<br>" + word + " ");
|
temp += currentLine + "<br>" + word + " ";
|
||||||
} else {
|
} else {
|
||||||
temp += (word + "<br>");
|
temp += word + "<br>";
|
||||||
}
|
}
|
||||||
currentLine = "";
|
currentLine = "";
|
||||||
}
|
}
|
||||||
@ -734,8 +725,8 @@ Module.register("calendar", {
|
|||||||
|
|
||||||
var regParts = needle.match(/^\/(.+)\/([gim]*)$/);
|
var regParts = needle.match(/^\/(.+)\/([gim]*)$/);
|
||||||
if (regParts) {
|
if (regParts) {
|
||||||
// the parsed pattern is a regexp.
|
// the parsed pattern is a regexp.
|
||||||
needle = new RegExp(regParts[1], regParts[2]);
|
needle = new RegExp(regParts[1], regParts[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
title = title.replace(needle, replacement);
|
title = title.replace(needle, replacement);
|
||||||
@ -763,11 +754,10 @@ Module.register("calendar", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventList.sort(function(a,b) {
|
eventList.sort(function (a, b) {
|
||||||
return a.startDate - b.startDate;
|
return a.startDate - b.startDate;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.sendNotification("CALENDAR_EVENTS", eventList);
|
this.sendNotification("CALENDAR_EVENTS", eventList);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,51 +1,49 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Node Helper: Calendar - CalendarFetcher
|
* Node Helper: Calendar - CalendarFetcher
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var ical = require("./vendor/ical.js");
|
const ical = require("./vendor/ical.js");
|
||||||
var moment = require("moment");
|
const moment = require("moment");
|
||||||
|
|
||||||
var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, includePastEvents) {
|
var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, includePastEvents) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var reloadTimer = null;
|
var reloadTimer = null;
|
||||||
var events = [];
|
var events = [];
|
||||||
|
|
||||||
var fetchFailedCallback = function() {};
|
var fetchFailedCallback = function () {};
|
||||||
var eventsReceivedCallback = function() {};
|
var eventsReceivedCallback = function () {};
|
||||||
|
|
||||||
/* fetchCalendar()
|
/* fetchCalendar()
|
||||||
* Initiates calendar fetch.
|
* Initiates calendar fetch.
|
||||||
*/
|
*/
|
||||||
var fetchCalendar = function() {
|
var fetchCalendar = function () {
|
||||||
|
|
||||||
clearTimeout(reloadTimer);
|
clearTimeout(reloadTimer);
|
||||||
reloadTimer = null;
|
reloadTimer = null;
|
||||||
|
|
||||||
nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
||||||
var opts = {
|
var opts = {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": "Mozilla/5.0 (Node.js "+ nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)"
|
"User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)"
|
||||||
},
|
},
|
||||||
gzip: true
|
gzip: true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auth) {
|
if (auth) {
|
||||||
if(auth.method === "bearer"){
|
if (auth.method === "bearer") {
|
||||||
opts.auth = {
|
opts.auth = {
|
||||||
bearer: auth.pass
|
bearer: auth.pass
|
||||||
};
|
};
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
opts.auth = {
|
opts.auth = {
|
||||||
user: auth.user,
|
user: auth.user,
|
||||||
pass: auth.pass
|
pass: auth.pass
|
||||||
};
|
};
|
||||||
|
|
||||||
if(auth.method === "digest"){
|
if (auth.method === "digest") {
|
||||||
opts.auth.sendImmediately = false;
|
opts.auth.sendImmediately = false;
|
||||||
} else {
|
} else {
|
||||||
opts.auth.sendImmediately = true;
|
opts.auth.sendImmediately = true;
|
||||||
@ -53,7 +51,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ical.fromURL(url, opts, function(err, data) {
|
ical.fromURL(url, opts, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
fetchFailedCallback(self, err);
|
fetchFailedCallback(self, err);
|
||||||
scheduleTimer();
|
scheduleTimer();
|
||||||
@ -61,28 +59,29 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// console.log(data);
|
// console.log(data);
|
||||||
newEvents = [];
|
var newEvents = [];
|
||||||
|
|
||||||
// limitFunction doesn't do much limiting, see comment re: the dates array in rrule section below as to why we need to do the filtering ourselves
|
// limitFunction doesn't do much limiting, see comment re: the dates array in rrule section below as to why we need to do the filtering ourselves
|
||||||
var limitFunction = function(date, i) {return true;};
|
var limitFunction = function (date, i) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
var eventDate = function(event, time) {
|
var eventDate = function (event, time) {
|
||||||
return (event[time].length === 8) ? moment(event[time], "YYYYMMDD") : moment(new Date(event[time]));
|
return event[time].length === 8 ? moment(event[time], "YYYYMMDD") : moment(new Date(event[time]));
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var e in data) {
|
for (var e in data) {
|
||||||
var event = data[e];
|
var event = data[e];
|
||||||
var now = new Date();
|
var now = new Date();
|
||||||
var today = moment().startOf("day").toDate();
|
var today = moment().startOf("day").toDate();
|
||||||
var future = moment().startOf("day").add(maximumNumberOfDays, "days").subtract(1,"seconds").toDate(); // Subtract 1 second so that events that start on the middle of the night will not repeat.
|
var future = moment().startOf("day").add(maximumNumberOfDays, "days").subtract(1, "seconds").toDate(); // Subtract 1 second so that events that start on the middle of the night will not repeat.
|
||||||
var past = today;
|
var past = today;
|
||||||
|
|
||||||
if (includePastEvents) {
|
if (includePastEvents) {
|
||||||
past = moment().startOf("day").subtract(maximumNumberOfDays, "days").toDate();
|
past = moment().startOf("day").subtract(maximumNumberOfDays, "days").toDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME:
|
// FIXME: Ugly fix to solve the facebook birthday issue.
|
||||||
// Ugly fix to solve the facebook birthday issue.
|
|
||||||
// Otherwise, the recurring events only show the birthday for next year.
|
// Otherwise, the recurring events only show the birthday for next year.
|
||||||
var isFacebookBirthday = false;
|
var isFacebookBirthday = false;
|
||||||
if (typeof event.uid !== "undefined") {
|
if (typeof event.uid !== "undefined") {
|
||||||
@ -92,13 +91,12 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.type === "VEVENT") {
|
if (event.type === "VEVENT") {
|
||||||
|
|
||||||
var startDate = eventDate(event, "start");
|
var startDate = eventDate(event, "start");
|
||||||
var endDate;
|
var endDate;
|
||||||
if (typeof event.end !== "undefined") {
|
if (typeof event.end !== "undefined") {
|
||||||
endDate = eventDate(event, "end");
|
endDate = eventDate(event, "end");
|
||||||
} else if(typeof event.duration !== "undefined") {
|
} else if (typeof event.duration !== "undefined") {
|
||||||
dur=moment.duration(event.duration);
|
var dur = moment.duration(event.duration);
|
||||||
endDate = startDate.clone().add(dur);
|
endDate = startDate.clone().add(dur);
|
||||||
} else {
|
} else {
|
||||||
if (!isFacebookBirthday) {
|
if (!isFacebookBirthday) {
|
||||||
@ -176,8 +174,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
var addedEvents = 0;
|
var addedEvents = 0;
|
||||||
|
|
||||||
// can cause problems with e.g. birthdays before 1900
|
// can cause problems with e.g. birthdays before 1900
|
||||||
if(rule.options && rule.origOptions && rule.origOptions.dtstart && rule.origOptions.dtstart.getFullYear() < 1900 ||
|
if ((rule.options && rule.origOptions && rule.origOptions.dtstart && rule.origOptions.dtstart.getFullYear() < 1900) || (rule.options && rule.options.dtstart && rule.options.dtstart.getFullYear() < 1900)) {
|
||||||
rule.options && rule.options.dtstart && rule.options.dtstart.getFullYear() < 1900){
|
|
||||||
rule.origOptions.dtstart.setYear(1900);
|
rule.origOptions.dtstart.setYear(1900);
|
||||||
rule.options.dtstart.setYear(1900);
|
rule.options.dtstart.setYear(1900);
|
||||||
}
|
}
|
||||||
@ -188,7 +185,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
var pastLocal = moment(past).subtract(past.getTimezoneOffset(), "minutes").toDate();
|
var pastLocal = moment(past).subtract(past.getTimezoneOffset(), "minutes").toDate();
|
||||||
var futureLocal = moment(future).subtract(future.getTimezoneOffset(), "minutes").toDate();
|
var futureLocal = moment(future).subtract(future.getTimezoneOffset(), "minutes").toDate();
|
||||||
var datesLocal = rule.between(pastLocal, futureLocal, true, limitFunction);
|
var datesLocal = rule.between(pastLocal, futureLocal, true, limitFunction);
|
||||||
var dates = datesLocal.map(function(dateLocal) {
|
var dates = datesLocal.map(function (dateLocal) {
|
||||||
var date = moment(dateLocal).add(dateLocal.getTimezoneOffset(), "minutes").toDate();
|
var date = moment(dateLocal).add(dateLocal.getTimezoneOffset(), "minutes").toDate();
|
||||||
return date;
|
return date;
|
||||||
});
|
});
|
||||||
@ -200,17 +197,14 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
// because the logic below will filter out any recurrences that don"t actually belong within
|
// because the logic below will filter out any recurrences that don"t actually belong within
|
||||||
// our display range.
|
// our display range.
|
||||||
// Would be great if there was a better way to handle this.
|
// Would be great if there was a better way to handle this.
|
||||||
if (event.recurrences != undefined)
|
if (event.recurrences !== undefined) {
|
||||||
{
|
|
||||||
var pastMoment = moment(past);
|
var pastMoment = moment(past);
|
||||||
var futureMoment = moment(future);
|
var futureMoment = moment(future);
|
||||||
|
|
||||||
for (var r in event.recurrences)
|
for (var r in event.recurrences) {
|
||||||
{
|
|
||||||
// Only add dates that weren't already in the range we added from the rrule so that
|
// Only add dates that weren't already in the range we added from the rrule so that
|
||||||
// we don"t double-add those events.
|
// we don"t double-add those events.
|
||||||
if (moment(new Date(r)).isBetween(pastMoment, futureMoment) != true)
|
if (moment(new Date(r)).isBetween(pastMoment, futureMoment) !== true) {
|
||||||
{
|
|
||||||
dates.push(new Date(r));
|
dates.push(new Date(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,7 +216,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
// ical.js started returning recurrences and exdates as ISOStrings without time information.
|
// ical.js started returning recurrences and exdates as ISOStrings without time information.
|
||||||
// .toISOString().substring(0,10) is the method they use to calculate keys, so we'll do the same
|
// .toISOString().substring(0,10) is the method they use to calculate keys, so we'll do the same
|
||||||
// (see https://github.com/peterbraden/ical.js/pull/84 )
|
// (see https://github.com/peterbraden/ical.js/pull/84 )
|
||||||
var dateKey = date.toISOString().substring(0,10);
|
var dateKey = date.toISOString().substring(0, 10);
|
||||||
var curEvent = event;
|
var curEvent = event;
|
||||||
var showRecurrence = true;
|
var showRecurrence = true;
|
||||||
|
|
||||||
@ -235,22 +229,20 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
startDate = moment(date);
|
startDate = moment(date);
|
||||||
|
|
||||||
// For each date that we"re checking, it"s possible that there is a recurrence override for that one day.
|
// For each date that we"re checking, it"s possible that there is a recurrence override for that one day.
|
||||||
if ((curEvent.recurrences != undefined) && (curEvent.recurrences[dateKey] != undefined))
|
if (curEvent.recurrences !== undefined && curEvent.recurrences[dateKey] !== undefined) {
|
||||||
{
|
|
||||||
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
|
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
|
||||||
curEvent = curEvent.recurrences[dateKey];
|
curEvent = curEvent.recurrences[dateKey];
|
||||||
startDate = moment(curEvent.start);
|
startDate = moment(curEvent.start);
|
||||||
duration = parseInt(moment(curEvent.end).format("x")) - parseInt(startDate.format("x"));
|
duration = parseInt(moment(curEvent.end).format("x")) - parseInt(startDate.format("x"));
|
||||||
}
|
}
|
||||||
// If there"s no recurrence override, check for an exception date. Exception dates represent exceptions to the rule.
|
// If there"s no recurrence override, check for an exception date. Exception dates represent exceptions to the rule.
|
||||||
else if ((curEvent.exdate != undefined) && (curEvent.exdate[dateKey] != undefined))
|
else if (curEvent.exdate !== undefined && curEvent.exdate[dateKey] !== undefined) {
|
||||||
{
|
|
||||||
// This date is an exception date, which means we should skip it in the recurrence pattern.
|
// This date is an exception date, which means we should skip it in the recurrence pattern.
|
||||||
showRecurrence = false;
|
showRecurrence = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
endDate = moment(parseInt(startDate.format("x")) + duration, "x");
|
endDate = moment(parseInt(startDate.format("x")) + duration, "x");
|
||||||
if (startDate.format("x") == endDate.format("x")) {
|
if (startDate.format("x") === endDate.format("x")) {
|
||||||
endDate = endDate.endOf("day");
|
endDate = endDate.endOf("day");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +258,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
showRecurrence = false;
|
showRecurrence = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((showRecurrence === true) && (addedEvents < maximumEntries)) {
|
if (showRecurrence === true && addedEvents < maximumEntries) {
|
||||||
addedEvents++;
|
addedEvents++;
|
||||||
newEvents.push({
|
newEvents.push({
|
||||||
title: recurrenceTitle,
|
title: recurrenceTitle,
|
||||||
@ -285,7 +277,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
} else {
|
} else {
|
||||||
// console.log("Single event ...");
|
// console.log("Single event ...");
|
||||||
// Single event.
|
// Single event.
|
||||||
var fullDayEvent = (isFacebookBirthday) ? true : isFullDayEvent(event);
|
var fullDayEvent = isFacebookBirthday ? true : isFullDayEvent(event);
|
||||||
|
|
||||||
if (includePastEvents) {
|
if (includePastEvents) {
|
||||||
if (endDate < past) {
|
if (endDate < past) {
|
||||||
@ -330,12 +322,11 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
geo: geo,
|
geo: geo,
|
||||||
description: description
|
description: description
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newEvents.sort(function(a, b) {
|
newEvents.sort(function (a, b) {
|
||||||
return a.startDate - b.startDate;
|
return a.startDate - b.startDate;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -351,10 +342,10 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
/* scheduleTimer()
|
/* scheduleTimer()
|
||||||
* Schedule the timer for the next update.
|
* Schedule the timer for the next update.
|
||||||
*/
|
*/
|
||||||
var scheduleTimer = function() {
|
var scheduleTimer = function () {
|
||||||
//console.log('Schedule update timer.');
|
//console.log('Schedule update timer.');
|
||||||
clearTimeout(reloadTimer);
|
clearTimeout(reloadTimer);
|
||||||
reloadTimer = setTimeout(function() {
|
reloadTimer = setTimeout(function () {
|
||||||
fetchCalendar();
|
fetchCalendar();
|
||||||
}, reloadInterval);
|
}, reloadInterval);
|
||||||
};
|
};
|
||||||
@ -366,7 +357,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
*
|
*
|
||||||
* return bool - The event is a fullday event.
|
* return bool - The event is a fullday event.
|
||||||
*/
|
*/
|
||||||
var isFullDayEvent = function(event) {
|
var isFullDayEvent = function (event) {
|
||||||
if (event.start.length === 8 || event.start.dateOnly) {
|
if (event.start.length === 8 || event.start.dateOnly) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -374,7 +365,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
var start = event.start || 0;
|
var start = event.start || 0;
|
||||||
var startDate = new Date(start);
|
var startDate = new Date(start);
|
||||||
var end = event.end || 0;
|
var end = event.end || 0;
|
||||||
if (((end - start) % (24 * 60 * 60 * 1000)) === 0 && startDate.getHours() === 0 && startDate.getMinutes() === 0) {
|
if ((end - start) % (24 * 60 * 60 * 1000) === 0 && startDate.getHours() === 0 && startDate.getMinutes() === 0) {
|
||||||
// Is 24 hours, and starts on the middle of the night.
|
// Is 24 hours, and starts on the middle of the night.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -391,7 +382,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
*
|
*
|
||||||
* return bool - The event should be filtered out
|
* return bool - The event should be filtered out
|
||||||
*/
|
*/
|
||||||
var timeFilterApplies = function(now, endDate, filter) {
|
var timeFilterApplies = function (now, endDate, filter) {
|
||||||
if (filter) {
|
if (filter) {
|
||||||
var until = filter.split(" "),
|
var until = filter.split(" "),
|
||||||
value = parseInt(until[0]),
|
value = parseInt(until[0]),
|
||||||
@ -405,16 +396,16 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* getTitleFromEvent(event)
|
/* getTitleFromEvent(event)
|
||||||
* Gets the title from the event.
|
* Gets the title from the event.
|
||||||
*
|
*
|
||||||
* argument event object - The event object to check.
|
* argument event object - The event object to check.
|
||||||
*
|
*
|
||||||
* return string - The title of the event, or "Event" if no title is found.
|
* return string - The title of the event, or "Event" if no title is found.
|
||||||
*/
|
*/
|
||||||
var getTitleFromEvent = function (event) {
|
var getTitleFromEvent = function (event) {
|
||||||
var title = "Event";
|
var title = "Event";
|
||||||
if (event.summary) {
|
if (event.summary) {
|
||||||
title = (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary;
|
title = typeof event.summary.val !== "undefined" ? event.summary.val : event.summary;
|
||||||
} else if (event.description) {
|
} else if (event.description) {
|
||||||
title = event.description;
|
title = event.description;
|
||||||
}
|
}
|
||||||
@ -443,14 +434,14 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
/* startFetch()
|
/* startFetch()
|
||||||
* Initiate fetchCalendar();
|
* Initiate fetchCalendar();
|
||||||
*/
|
*/
|
||||||
this.startFetch = function() {
|
this.startFetch = function () {
|
||||||
fetchCalendar();
|
fetchCalendar();
|
||||||
};
|
};
|
||||||
|
|
||||||
/* broadcastItems()
|
/* broadcastItems()
|
||||||
* Broadcast the existing events.
|
* Broadcast the existing events.
|
||||||
*/
|
*/
|
||||||
this.broadcastEvents = function() {
|
this.broadcastEvents = function () {
|
||||||
//console.log('Broadcasting ' + events.length + ' events.');
|
//console.log('Broadcasting ' + events.length + ' events.');
|
||||||
eventsReceivedCallback(self);
|
eventsReceivedCallback(self);
|
||||||
};
|
};
|
||||||
@ -460,7 +451,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
*
|
*
|
||||||
* argument callback function - The on success callback.
|
* argument callback function - The on success callback.
|
||||||
*/
|
*/
|
||||||
this.onReceive = function(callback) {
|
this.onReceive = function (callback) {
|
||||||
eventsReceivedCallback = callback;
|
eventsReceivedCallback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -469,7 +460,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
*
|
*
|
||||||
* argument callback function - The on error callback.
|
* argument callback function - The on error callback.
|
||||||
*/
|
*/
|
||||||
this.onError = function(callback) {
|
this.onError = function (callback) {
|
||||||
fetchFailedCallback = callback;
|
fetchFailedCallback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -478,7 +469,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
*
|
*
|
||||||
* return string - The url of this fetcher.
|
* return string - The url of this fetcher.
|
||||||
*/
|
*/
|
||||||
this.url = function() {
|
this.url = function () {
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -487,7 +478,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
|
|||||||
*
|
*
|
||||||
* return array - The current available events for this fetcher.
|
* return array - The current available events for this fetcher.
|
||||||
*/
|
*/
|
||||||
this.events = function() {
|
this.events = function () {
|
||||||
return events;
|
return events;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* use this script with `node debug.js` to test the fetcher without the need
|
* use this script with `node debug.js` to test the fetcher without the need
|
||||||
* of starting the MagicMirror core. Adjust the values below to your desire.
|
* of starting the MagicMirror core. Adjust the values below to your desire.
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -15,8 +15,6 @@ var maximumEntries = 10;
|
|||||||
var maximumNumberOfDays = 365;
|
var maximumNumberOfDays = 365;
|
||||||
var user = "magicmirror";
|
var user = "magicmirror";
|
||||||
var pass = "MyStrongPass";
|
var pass = "MyStrongPass";
|
||||||
var broadcastPastEvents = false;
|
|
||||||
|
|
||||||
var auth = {
|
var auth = {
|
||||||
user: user,
|
user: user,
|
||||||
pass: pass
|
pass: pass
|
||||||
@ -24,14 +22,14 @@ var auth = {
|
|||||||
|
|
||||||
console.log("Create fetcher ...");
|
console.log("Create fetcher ...");
|
||||||
|
|
||||||
fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maximumNumberOfDays, auth);
|
var fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maximumNumberOfDays, auth);
|
||||||
|
|
||||||
fetcher.onReceive(function(fetcher) {
|
fetcher.onReceive(function (fetcher) {
|
||||||
console.log(fetcher.events());
|
console.log(fetcher.events());
|
||||||
console.log("------------------------------------------------------------");
|
console.log("------------------------------------------------------------");
|
||||||
});
|
});
|
||||||
|
|
||||||
fetcher.onError(function(fetcher, error) {
|
fetcher.onError(function (fetcher, error) {
|
||||||
console.log("Fetcher error:");
|
console.log("Fetcher error:");
|
||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Node Helper: Calendar
|
* Node Helper: Calendar
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -11,17 +11,16 @@ var CalendarFetcher = require("./calendarfetcher.js");
|
|||||||
|
|
||||||
module.exports = NodeHelper.create({
|
module.exports = NodeHelper.create({
|
||||||
// Override start method.
|
// Override start method.
|
||||||
start: function() {
|
start: function () {
|
||||||
var events = [];
|
var events = [];
|
||||||
|
|
||||||
this.fetchers = [];
|
this.fetchers = [];
|
||||||
|
|
||||||
console.log("Starting node helper for: " + this.name);
|
console.log("Starting node helper for: " + this.name);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Override socketNotificationReceived method.
|
// Override socketNotificationReceived method.
|
||||||
socketNotificationReceived: function(notification, payload) {
|
socketNotificationReceived: function (notification, payload) {
|
||||||
if (notification === "ADD_CALENDAR") {
|
if (notification === "ADD_CALENDAR") {
|
||||||
//console.log('ADD_CALENDAR: ');
|
//console.log('ADD_CALENDAR: ');
|
||||||
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents);
|
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents);
|
||||||
@ -36,11 +35,11 @@ module.exports = NodeHelper.create({
|
|||||||
* attribute reloadInterval number - Reload interval in milliseconds.
|
* attribute reloadInterval number - Reload interval in milliseconds.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
createFetcher: function(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents) {
|
createFetcher: function (url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (!validUrl.isUri(url)) {
|
if (!validUrl.isUri(url)) {
|
||||||
self.sendSocketNotification("INCORRECT_URL", {url: url});
|
self.sendSocketNotification("INCORRECT_URL", { url: url });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ module.exports = NodeHelper.create({
|
|||||||
console.log("Create new calendar fetcher for url: " + url + " - Interval: " + fetchInterval);
|
console.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);
|
||||||
|
|
||||||
fetcher.onReceive(function(fetcher) {
|
fetcher.onReceive(function (fetcher) {
|
||||||
//console.log('Broadcast events.');
|
//console.log('Broadcast events.');
|
||||||
//console.log(fetcher.events());
|
//console.log(fetcher.events());
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ module.exports = NodeHelper.create({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
fetcher.onError(function(fetcher, error) {
|
fetcher.onError(function (fetcher, error) {
|
||||||
console.error("Calendar Error. Could not fetch calendar: ", fetcher.url(), error);
|
console.error("Calendar Error. Could not fetch calendar: ", fetcher.url(), error);
|
||||||
self.sendSocketNotification("FETCH_ERROR", {
|
self.sendSocketNotification("FETCH_ERROR", {
|
||||||
url: fetcher.url(),
|
url: fetcher.url(),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Module: Clock
|
# Module: Clock
|
||||||
|
|
||||||
The `clock` module is one of the default modules of the MagicMirror.
|
The `clock` module is one of the default modules of the MagicMirror.
|
||||||
This module displays the current date and time. The information will be updated realtime.
|
This module displays the current date and time. The information will be updated realtime.
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
/* global Log, Module, moment, config */
|
/* global SunCalc */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: Clock
|
* Module: Clock
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
Module.register("clock",{
|
Module.register("clock", {
|
||||||
// Module config defaults.
|
// Module config defaults.
|
||||||
defaults: {
|
defaults: {
|
||||||
displayType: "digital", // options: digital, analog, both
|
displayType: "digital", // options: digital, analog, both
|
||||||
@ -30,18 +31,18 @@ Module.register("clock",{
|
|||||||
showSunTimes: false,
|
showSunTimes: false,
|
||||||
showMoonTimes: false,
|
showMoonTimes: false,
|
||||||
lat: 47.630539,
|
lat: 47.630539,
|
||||||
lon: -122.344147,
|
lon: -122.344147
|
||||||
},
|
},
|
||||||
// Define required scripts.
|
// Define required scripts.
|
||||||
getScripts: function() {
|
getScripts: function () {
|
||||||
return ["moment.js", "moment-timezone.js", "suncalc.js"];
|
return ["moment.js", "moment-timezone.js", "suncalc.js"];
|
||||||
},
|
},
|
||||||
// Define styles.
|
// Define styles.
|
||||||
getStyles: function() {
|
getStyles: function () {
|
||||||
return ["clock_styles.css"];
|
return ["clock_styles.css"];
|
||||||
},
|
},
|
||||||
// Define start sequence.
|
// Define start sequence.
|
||||||
start: function() {
|
start: function () {
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
|
|
||||||
// Schedule update interval.
|
// Schedule update interval.
|
||||||
@ -50,16 +51,16 @@ Module.register("clock",{
|
|||||||
self.minute = moment().minute();
|
self.minute = moment().minute();
|
||||||
|
|
||||||
//Calculate how many ms should pass until next update depending on if seconds is displayed or not
|
//Calculate how many ms should pass until next update depending on if seconds is displayed or not
|
||||||
var delayCalculator = function(reducedSeconds) {
|
var delayCalculator = function (reducedSeconds) {
|
||||||
if (self.config.displaySeconds) {
|
if (self.config.displaySeconds) {
|
||||||
return 1000 - moment().milliseconds();
|
return 1000 - moment().milliseconds();
|
||||||
} else {
|
} else {
|
||||||
return ((60 - reducedSeconds) * 1000) - moment().milliseconds();
|
return (60 - reducedSeconds) * 1000 - moment().milliseconds();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//A recursive timeout function instead of interval to avoid drifting
|
//A recursive timeout function instead of interval to avoid drifting
|
||||||
var notificationTimer = function() {
|
var notificationTimer = function () {
|
||||||
self.updateDom();
|
self.updateDom();
|
||||||
|
|
||||||
//If seconds is displayed CLOCK_SECOND-notification should be sent (but not when CLOCK_MINUTE-notification is sent)
|
//If seconds is displayed CLOCK_SECOND-notification should be sent (but not when CLOCK_MINUTE-notification is sent)
|
||||||
@ -83,11 +84,9 @@ Module.register("clock",{
|
|||||||
|
|
||||||
// Set locale.
|
// Set locale.
|
||||||
moment.locale(config.language);
|
moment.locale(config.language);
|
||||||
|
|
||||||
},
|
},
|
||||||
// Override dom generator.
|
// Override dom generator.
|
||||||
getDom: function() {
|
getDom: function () {
|
||||||
|
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement("div");
|
||||||
|
|
||||||
/************************************
|
/************************************
|
||||||
@ -126,12 +125,12 @@ Module.register("clock",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.clockBold === true) {
|
if (this.config.clockBold === true) {
|
||||||
timeString = now.format(hourSymbol + "[<span class=\"bold\">]mm[</span>]");
|
timeString = now.format(hourSymbol + '[<span class="bold">]mm[</span>]');
|
||||||
} else {
|
} else {
|
||||||
timeString = now.format(hourSymbol + ":mm");
|
timeString = now.format(hourSymbol + ":mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.config.showDate){
|
if (this.config.showDate) {
|
||||||
dateWrapper.innerHTML = now.format(this.config.dateFormat);
|
dateWrapper.innerHTML = now.format(this.config.dateFormat);
|
||||||
}
|
}
|
||||||
if (this.config.showWeek) {
|
if (this.config.showWeek) {
|
||||||
@ -172,9 +171,18 @@ Module.register("clock",{
|
|||||||
}
|
}
|
||||||
const untilNextEvent = moment.duration(moment(nextEvent).diff(now));
|
const untilNextEvent = moment.duration(moment(nextEvent).diff(now));
|
||||||
const untilNextEventString = untilNextEvent.hours() + "h " + untilNextEvent.minutes() + "m";
|
const untilNextEventString = untilNextEvent.hours() + "h " + untilNextEvent.minutes() + "m";
|
||||||
sunWrapper.innerHTML = "<span class=\"" + (isVisible ? "bright" : "") + "\"><i class=\"fa fa-sun-o\" aria-hidden=\"true\"></i> " + untilNextEventString + "</span>" +
|
sunWrapper.innerHTML =
|
||||||
"<span><i class=\"fa fa-arrow-up\" aria-hidden=\"true\"></i>" + formatTime(this.config, sunTimes.sunrise) + "</span>" +
|
'<span class="' +
|
||||||
"<span><i class=\"fa fa-arrow-down\" aria-hidden=\"true\"></i>" + formatTime(this.config, sunTimes.sunset) + "</span>";
|
(isVisible ? "bright" : "") +
|
||||||
|
'"><i class="fa fa-sun-o" aria-hidden="true"></i> ' +
|
||||||
|
untilNextEventString +
|
||||||
|
"</span>" +
|
||||||
|
'<span><i class="fa fa-arrow-up" aria-hidden="true"></i>' +
|
||||||
|
formatTime(this.config, sunTimes.sunrise) +
|
||||||
|
"</span>" +
|
||||||
|
'<span><i class="fa fa-arrow-down" aria-hidden="true"></i>' +
|
||||||
|
formatTime(this.config, sunTimes.sunset) +
|
||||||
|
"</span>";
|
||||||
}
|
}
|
||||||
if (this.config.showMoonTimes) {
|
if (this.config.showMoonTimes) {
|
||||||
const moonIllumination = SunCalc.getMoonIllumination(now.toDate());
|
const moonIllumination = SunCalc.getMoonIllumination(now.toDate());
|
||||||
@ -189,24 +197,32 @@ Module.register("clock",{
|
|||||||
}
|
}
|
||||||
const isVisible = now.isBetween(moonRise, moonSet) || moonTimes.alwaysUp === true;
|
const isVisible = now.isBetween(moonRise, moonSet) || moonTimes.alwaysUp === true;
|
||||||
const illuminatedFractionString = Math.round(moonIllumination.fraction * 100) + "%";
|
const illuminatedFractionString = Math.round(moonIllumination.fraction * 100) + "%";
|
||||||
moonWrapper.innerHTML = "<span class=\"" + (isVisible ? "bright" : "") + "\"><i class=\"fa fa-moon-o\" aria-hidden=\"true\"></i> " + illuminatedFractionString + "</span>" +
|
moonWrapper.innerHTML =
|
||||||
"<span><i class=\"fa fa-arrow-up\" aria-hidden=\"true\"></i> " + (moonRise ? formatTime(this.config, moonRise) : "...") + "</span>"+
|
'<span class="' +
|
||||||
"<span><i class=\"fa fa-arrow-down\" aria-hidden=\"true\"></i> " + (moonSet ? formatTime(this.config, moonSet) : "...") + "</span>";
|
(isVisible ? "bright" : "") +
|
||||||
|
'"><i class="fa fa-moon-o" aria-hidden="true"></i> ' +
|
||||||
|
illuminatedFractionString +
|
||||||
|
"</span>" +
|
||||||
|
'<span><i class="fa fa-arrow-up" aria-hidden="true"></i> ' +
|
||||||
|
(moonRise ? formatTime(this.config, moonRise) : "...") +
|
||||||
|
"</span>" +
|
||||||
|
'<span><i class="fa fa-arrow-down" aria-hidden="true"></i> ' +
|
||||||
|
(moonSet ? formatTime(this.config, moonSet) : "...") +
|
||||||
|
"</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Create wrappers for ANALOG clock, only if specified in config
|
* Create wrappers for ANALOG clock, only if specified in config
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (this.config.displayType !== "digital") {
|
if (this.config.displayType !== "digital") {
|
||||||
// If it isn't 'digital', then an 'analog' clock was also requested
|
// If it isn't 'digital', then an 'analog' clock was also requested
|
||||||
|
|
||||||
// Calculate the degree offset for each hand of the clock
|
// Calculate the degree offset for each hand of the clock
|
||||||
var now = moment();
|
|
||||||
if (this.config.timezone) {
|
if (this.config.timezone) {
|
||||||
now.tz(this.config.timezone);
|
now.tz(this.config.timezone);
|
||||||
}
|
}
|
||||||
var second = now.seconds() * 6,
|
var second = now.seconds() * 6,
|
||||||
minute = now.minute() * 6 + second / 60,
|
minute = now.minute() * 6 + second / 60,
|
||||||
hour = ((now.hours() % 12) / 12) * 360 + 90 + minute / 12;
|
hour = ((now.hours() % 12) / 12) * 360 + 90 + minute / 12;
|
||||||
|
|
||||||
@ -217,13 +233,12 @@ Module.register("clock",{
|
|||||||
clockCircle.style.height = this.config.analogSize;
|
clockCircle.style.height = this.config.analogSize;
|
||||||
|
|
||||||
if (this.config.analogFace !== "" && this.config.analogFace !== "simple" && this.config.analogFace !== "none") {
|
if (this.config.analogFace !== "" && this.config.analogFace !== "simple" && this.config.analogFace !== "none") {
|
||||||
clockCircle.style.background = "url("+ this.data.path + "faces/" + this.config.analogFace + ".svg)";
|
clockCircle.style.background = "url(" + this.data.path + "faces/" + this.config.analogFace + ".svg)";
|
||||||
clockCircle.style.backgroundSize = "100%";
|
clockCircle.style.backgroundSize = "100%";
|
||||||
|
|
||||||
// The following line solves issue: https://github.com/MichMich/MagicMirror/issues/611
|
// The following line solves issue: https://github.com/MichMich/MagicMirror/issues/611
|
||||||
// clockCircle.style.border = "1px solid black";
|
// clockCircle.style.border = "1px solid black";
|
||||||
clockCircle.style.border = "rgba(0, 0, 0, 0.1)"; //Updated fix for Issue 611 where non-black backgrounds are used
|
clockCircle.style.border = "rgba(0, 0, 0, 0.1)"; //Updated fix for Issue 611 where non-black backgrounds are used
|
||||||
|
|
||||||
} else if (this.config.analogFace !== "none") {
|
} else if (this.config.analogFace !== "none") {
|
||||||
clockCircle.style.border = "2px solid white";
|
clockCircle.style.border = "2px solid white";
|
||||||
}
|
}
|
||||||
@ -289,11 +304,12 @@ Module.register("clock",{
|
|||||||
// Both clocks have been configured, check position
|
// Both clocks have been configured, check position
|
||||||
var placement = this.config.analogPlacement;
|
var placement = this.config.analogPlacement;
|
||||||
|
|
||||||
analogWrapper = document.createElement("div");
|
var analogWrapper = document.createElement("div");
|
||||||
analogWrapper.id = "analog";
|
analogWrapper.id = "analog";
|
||||||
analogWrapper.style.cssFloat = "none";
|
analogWrapper.style.cssFloat = "none";
|
||||||
analogWrapper.appendChild(clockCircle);
|
analogWrapper.appendChild(clockCircle);
|
||||||
digitalWrapper = document.createElement("div");
|
|
||||||
|
var digitalWrapper = document.createElement("div");
|
||||||
digitalWrapper.id = "digital";
|
digitalWrapper.id = "digital";
|
||||||
digitalWrapper.style.cssFloat = "none";
|
digitalWrapper.style.cssFloat = "none";
|
||||||
digitalWrapper.appendChild(dateWrapper);
|
digitalWrapper.appendChild(dateWrapper);
|
||||||
@ -302,9 +318,9 @@ Module.register("clock",{
|
|||||||
digitalWrapper.appendChild(moonWrapper);
|
digitalWrapper.appendChild(moonWrapper);
|
||||||
digitalWrapper.appendChild(weekWrapper);
|
digitalWrapper.appendChild(weekWrapper);
|
||||||
|
|
||||||
var appendClocks = function(condition, pos1, pos2) {
|
var appendClocks = function (condition, pos1, pos2) {
|
||||||
var padding = [0,0,0,0];
|
var padding = [0, 0, 0, 0];
|
||||||
padding[(placement === condition) ? pos1 : pos2] = "20px";
|
padding[placement === condition ? pos1 : pos2] = "20px";
|
||||||
analogWrapper.style.padding = padding.join(" ");
|
analogWrapper.style.padding = padding.join(" ");
|
||||||
if (placement === condition) {
|
if (placement === condition) {
|
||||||
wrapper.appendChild(analogWrapper);
|
wrapper.appendChild(analogWrapper);
|
||||||
|
@ -29,11 +29,9 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -2px 0 -2px -25%; /* numbers much match negative length & thickness */
|
margin: -2px 0 -2px -25%; /* numbers much match negative length & thickness */
|
||||||
padding: 2px 0 2px 25%; /* indicator length & thickness */
|
padding: 2px 0 2px 25%; /* indicator length & thickness */
|
||||||
background: white;
|
background: white;
|
||||||
-webkit-transform-origin: 100% 50%;
|
|
||||||
-ms-transform-origin: 100% 50%;
|
|
||||||
transform-origin: 100% 50%;
|
transform-origin: 100% 50%;
|
||||||
border-radius: 3px 0 0 3px;
|
border-radius: 3px 0 0 3px;
|
||||||
}
|
}
|
||||||
@ -44,11 +42,9 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -35% -2px 0; /* numbers must match negative length & thickness */
|
margin: -35% -2px 0; /* numbers must match negative length & thickness */
|
||||||
padding: 35% 2px 0; /* indicator length & thickness */
|
padding: 35% 2px 0; /* indicator length & thickness */
|
||||||
background: white;
|
background: white;
|
||||||
-webkit-transform-origin: 50% 100%;
|
|
||||||
-ms-transform-origin: 50% 100%;
|
|
||||||
transform-origin: 50% 100%;
|
transform-origin: 50% 100%;
|
||||||
border-radius: 3px 0 0 3px;
|
border-radius: 3px 0 0 3px;
|
||||||
}
|
}
|
||||||
@ -59,11 +55,9 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -38% -1px 0 0; /* numbers must match negative length & thickness */
|
margin: -38% -1px 0 0; /* numbers must match negative length & thickness */
|
||||||
padding: 38% 1px 0 0; /* indicator length & thickness */
|
padding: 38% 1px 0 0; /* indicator length & thickness */
|
||||||
background: #888;
|
background: #888;
|
||||||
-webkit-transform-origin: 50% 100%;
|
|
||||||
-ms-transform-origin: 50% 100%;
|
|
||||||
transform-origin: 50% 100%;
|
transform-origin: 50% 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
<svg id="Hour_Markers_-_Singlets" data-name="Hour Markers - Singlets" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 250"><defs><style>.cls-1,.cls-2{fill:none;stroke:#fff;stroke-linecap:round;stroke-miterlimit:10;}.cls-2{stroke-width:0.5px;}</style></defs><title>face-001</title><line class="cls-1" x1="125" y1="1.25" x2="125" y2="16.23"/><line class="cls-1" x1="186.87" y1="17.83" x2="179.39" y2="30.8"/><line class="cls-1" x1="232.17" y1="63.12" x2="219.2" y2="70.61"/><line class="cls-1" x1="248.75" y1="125" x2="233.77" y2="125"/><line class="cls-1" x1="232.17" y1="186.87" x2="219.2" y2="179.39"/><line class="cls-1" x1="186.88" y1="232.17" x2="179.39" y2="219.2"/><line class="cls-1" x1="125" y1="248.75" x2="125" y2="233.77"/><line class="cls-1" x1="63.13" y1="232.17" x2="70.61" y2="219.2"/><line class="cls-1" x1="17.83" y1="186.88" x2="30.8" y2="179.39"/><line class="cls-1" x1="1.25" y1="125" x2="16.23" y2="125"/><line class="cls-1" x1="17.83" y1="63.13" x2="30.8" y2="70.61"/><line class="cls-1" x1="63.12" y1="17.83" x2="70.61" y2="30.8"/><line class="cls-2" x1="138.01" y1="1.25" x2="136.96" y2="11.23"/><line class="cls-2" x1="150.87" y1="3.29" x2="148.78" y2="13.11"/><line class="cls-2" x1="163.45" y1="6.66" x2="160.35" y2="16.21"/><line class="cls-2" x1="175.61" y1="11.33" x2="171.53" y2="20.5"/><line class="cls-2" x1="198.14" y1="24.33" x2="192.24" y2="32.45"/><line class="cls-2" x1="208.26" y1="32.53" x2="201.54" y2="39.99"/><line class="cls-2" x1="217.47" y1="41.74" x2="210.01" y2="48.46"/><line class="cls-2" x1="225.67" y1="51.86" x2="217.55" y2="57.76"/><line class="cls-2" x1="238.67" y1="74.39" x2="229.5" y2="78.47"/><line class="cls-2" x1="243.34" y1="86.55" x2="233.79" y2="89.65"/><line class="cls-2" x1="246.71" y1="99.13" x2="236.89" y2="101.22"/><line class="cls-2" x1="248.75" y1="111.99" x2="238.77" y2="113.04"/><line class="cls-2" x1="248.75" y1="138.01" x2="238.77" y2="136.96"/><line class="cls-2" x1="246.71" y1="150.87" x2="236.89" y2="148.78"/><line class="cls-2" x1="243.34" y1="163.45" x2="233.79" y2="160.35"/><line class="cls-2" x1="238.67" y1="175.61" x2="229.5" y2="171.53"/><line class="cls-2" x1="225.67" y1="198.14" x2="217.55" y2="192.24"/><line class="cls-2" x1="217.47" y1="208.26" x2="210.01" y2="201.54"/><line class="cls-2" x1="208.26" y1="217.47" x2="201.54" y2="210.01"/><line class="cls-2" x1="198.14" y1="225.67" x2="192.24" y2="217.55"/><line class="cls-2" x1="175.61" y1="238.67" x2="171.53" y2="229.5"/><line class="cls-2" x1="163.45" y1="243.34" x2="160.35" y2="233.79"/><line class="cls-2" x1="150.87" y1="246.71" x2="148.78" y2="236.89"/><line class="cls-2" x1="138.01" y1="248.75" x2="136.96" y2="238.77"/><line class="cls-2" x1="111.99" y1="248.75" x2="113.04" y2="238.77"/><line class="cls-2" x1="99.13" y1="246.71" x2="101.22" y2="236.89"/><line class="cls-2" x1="86.55" y1="243.34" x2="89.65" y2="233.79"/><line class="cls-2" x1="74.39" y1="238.67" x2="78.47" y2="229.5"/><line class="cls-2" x1="51.86" y1="225.67" x2="57.76" y2="217.55"/><line class="cls-2" x1="41.74" y1="217.47" x2="48.46" y2="210.01"/><line class="cls-2" x1="32.53" y1="208.26" x2="39.99" y2="201.54"/><line class="cls-2" x1="24.33" y1="198.14" x2="32.45" y2="192.24"/><line class="cls-2" x1="11.33" y1="175.61" x2="20.5" y2="171.53"/><line class="cls-2" x1="6.66" y1="163.45" x2="16.21" y2="160.35"/><line class="cls-2" x1="3.29" y1="150.87" x2="13.11" y2="148.78"/><line class="cls-2" x1="1.25" y1="138.01" x2="11.23" y2="136.96"/><line class="cls-2" x1="1.25" y1="111.99" x2="11.23" y2="113.04"/><line class="cls-2" x1="3.29" y1="99.13" x2="13.11" y2="101.22"/><line class="cls-2" x1="6.66" y1="86.55" x2="16.21" y2="89.65"/><line class="cls-2" x1="11.33" y1="74.39" x2="20.5" y2="78.47"/><line class="cls-2" x1="24.33" y1="51.86" x2="32.45" y2="57.76"/><line class="cls-2" x1="32.53" y1="41.74" x2="39.99" y2="48.46"/><line class="cls-2" x1="41.74" y1="32.53" x2="48.46" y2="39.99"/><line class="cls-2" x1="51.86" y1="24.33" x2="57.76" y2="32.45"/><line class="cls-2" x1="74.39" y1="11.33" x2="78.47" y2="20.5"/><line class="cls-2" x1="86.55" y1="6.66" x2="89.65" y2="16.21"/><line class="cls-2" x1="99.13" y1="3.29" x2="101.22" y2="13.11"/><line class="cls-2" x1="111.99" y1="1.25" x2="113.04" y2="11.23"/></svg>
|
<svg id="Hour_Markers_-_Singlets" data-name="Hour Markers - Singlets" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 250 250"><defs><style>.cls-1,.cls-2{fill:none;stroke:#fff;stroke-linecap:round;stroke-miterlimit:10;}.cls-2{stroke-width:0.5px;}</style></defs><title>face-001</title><line class="cls-1" x1="125" y1="1.25" x2="125" y2="16.23"/><line class="cls-1" x1="186.87" y1="17.83" x2="179.39" y2="30.8"/><line class="cls-1" x1="232.17" y1="63.12" x2="219.2" y2="70.61"/><line class="cls-1" x1="248.75" y1="125" x2="233.77" y2="125"/><line class="cls-1" x1="232.17" y1="186.87" x2="219.2" y2="179.39"/><line class="cls-1" x1="186.88" y1="232.17" x2="179.39" y2="219.2"/><line class="cls-1" x1="125" y1="248.75" x2="125" y2="233.77"/><line class="cls-1" x1="63.13" y1="232.17" x2="70.61" y2="219.2"/><line class="cls-1" x1="17.83" y1="186.88" x2="30.8" y2="179.39"/><line class="cls-1" x1="1.25" y1="125" x2="16.23" y2="125"/><line class="cls-1" x1="17.83" y1="63.13" x2="30.8" y2="70.61"/><line class="cls-1" x1="63.12" y1="17.83" x2="70.61" y2="30.8"/><line class="cls-2" x1="138.01" y1="1.25" x2="136.96" y2="11.23"/><line class="cls-2" x1="150.87" y1="3.29" x2="148.78" y2="13.11"/><line class="cls-2" x1="163.45" y1="6.66" x2="160.35" y2="16.21"/><line class="cls-2" x1="175.61" y1="11.33" x2="171.53" y2="20.5"/><line class="cls-2" x1="198.14" y1="24.33" x2="192.24" y2="32.45"/><line class="cls-2" x1="208.26" y1="32.53" x2="201.54" y2="39.99"/><line class="cls-2" x1="217.47" y1="41.74" x2="210.01" y2="48.46"/><line class="cls-2" x1="225.67" y1="51.86" x2="217.55" y2="57.76"/><line class="cls-2" x1="238.67" y1="74.39" x2="229.5" y2="78.47"/><line class="cls-2" x1="243.34" y1="86.55" x2="233.79" y2="89.65"/><line class="cls-2" x1="246.71" y1="99.13" x2="236.89" y2="101.22"/><line class="cls-2" x1="248.75" y1="111.99" x2="238.77" y2="113.04"/><line class="cls-2" x1="248.75" y1="138.01" x2="238.77" y2="136.96"/><line class="cls-2" x1="246.71" y1="150.87" x2="236.89" y2="148.78"/><line class="cls-2" x1="243.34" y1="163.45" x2="233.79" y2="160.35"/><line class="cls-2" x1="238.67" y1="175.61" x2="229.5" y2="171.53"/><line class="cls-2" x1="225.67" y1="198.14" x2="217.55" y2="192.24"/><line class="cls-2" x1="217.47" y1="208.26" x2="210.01" y2="201.54"/><line class="cls-2" x1="208.26" y1="217.47" x2="201.54" y2="210.01"/><line class="cls-2" x1="198.14" y1="225.67" x2="192.24" y2="217.55"/><line class="cls-2" x1="175.61" y1="238.67" x2="171.53" y2="229.5"/><line class="cls-2" x1="163.45" y1="243.34" x2="160.35" y2="233.79"/><line class="cls-2" x1="150.87" y1="246.71" x2="148.78" y2="236.89"/><line class="cls-2" x1="138.01" y1="248.75" x2="136.96" y2="238.77"/><line class="cls-2" x1="111.99" y1="248.75" x2="113.04" y2="238.77"/><line class="cls-2" x1="99.13" y1="246.71" x2="101.22" y2="236.89"/><line class="cls-2" x1="86.55" y1="243.34" x2="89.65" y2="233.79"/><line class="cls-2" x1="74.39" y1="238.67" x2="78.47" y2="229.5"/><line class="cls-2" x1="51.86" y1="225.67" x2="57.76" y2="217.55"/><line class="cls-2" x1="41.74" y1="217.47" x2="48.46" y2="210.01"/><line class="cls-2" x1="32.53" y1="208.26" x2="39.99" y2="201.54"/><line class="cls-2" x1="24.33" y1="198.14" x2="32.45" y2="192.24"/><line class="cls-2" x1="11.33" y1="175.61" x2="20.5" y2="171.53"/><line class="cls-2" x1="6.66" y1="163.45" x2="16.21" y2="160.35"/><line class="cls-2" x1="3.29" y1="150.87" x2="13.11" y2="148.78"/><line class="cls-2" x1="1.25" y1="138.01" x2="11.23" y2="136.96"/><line class="cls-2" x1="1.25" y1="111.99" x2="11.23" y2="113.04"/><line class="cls-2" x1="3.29" y1="99.13" x2="13.11" y2="101.22"/><line class="cls-2" x1="6.66" y1="86.55" x2="16.21" y2="89.65"/><line class="cls-2" x1="11.33" y1="74.39" x2="20.5" y2="78.47"/><line class="cls-2" x1="24.33" y1="51.86" x2="32.45" y2="57.76"/><line class="cls-2" x1="32.53" y1="41.74" x2="39.99" y2="48.46"/><line class="cls-2" x1="41.74" y1="32.53" x2="48.46" y2="39.99"/><line class="cls-2" x1="51.86" y1="24.33" x2="57.76" y2="32.45"/><line class="cls-2" x1="74.39" y1="11.33" x2="78.47" y2="20.5"/><line class="cls-2" x1="86.55" y1="6.66" x2="89.65" y2="16.21"/><line class="cls-2" x1="99.13" y1="3.29" x2="101.22" y2="13.11"/><line class="cls-2" x1="111.99" y1="1.25" x2="113.04" y2="11.23"/></svg>
|
||||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
@ -1 +1 @@
|
|||||||
<svg id="Hour_Markers_-_Doubles" data-name="Hour Markers - Doubles" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 250"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-linecap:round;stroke-miterlimit:10;stroke-width:2.98px;}</style></defs><title>face-002</title><line class="cls-1" x1="122.01" y1="1.75" x2="122.01" y2="16.67"/><line class="cls-1" x1="186.62" y1="18.26" x2="179.17" y2="31.18"/><line class="cls-1" x1="231.74" y1="63.37" x2="218.82" y2="70.83"/><line class="cls-1" x1="248.25" y1="127.99" x2="233.33" y2="127.99"/><line class="cls-1" x1="231.74" y1="186.62" x2="218.82" y2="179.17"/><line class="cls-1" x1="186.63" y1="231.74" x2="179.17" y2="218.82"/><line class="cls-1" x1="127.99" y1="248.25" x2="127.99" y2="233.33"/><line class="cls-1" x1="63.38" y1="231.74" x2="70.83" y2="218.82"/><line class="cls-1" x1="18.26" y1="186.63" x2="31.18" y2="179.17"/><line class="cls-1" x1="1.75" y1="122.01" x2="16.67" y2="122.01"/><line class="cls-1" x1="18.26" y1="63.38" x2="31.18" y2="70.83"/><line class="cls-1" x1="63.37" y1="18.26" x2="70.83" y2="31.18"/><line class="cls-1" x1="127.99" y1="1.75" x2="127.99" y2="16.67"/><line class="cls-1" x1="248.25" y1="122.01" x2="233.33" y2="122.01"/><line class="cls-1" x1="122.01" y1="248.25" x2="122.01" y2="233.33"/><line class="cls-1" x1="1.75" y1="127.99" x2="16.67" y2="127.99"/></svg>
|
<svg id="Hour_Markers_-_Doubles" data-name="Hour Markers - Doubles" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 250 250"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-linecap:round;stroke-miterlimit:10;stroke-width:2.98px;}</style></defs><title>face-002</title><line class="cls-1" x1="122.01" y1="1.75" x2="122.01" y2="16.67"/><line class="cls-1" x1="186.62" y1="18.26" x2="179.17" y2="31.18"/><line class="cls-1" x1="231.74" y1="63.37" x2="218.82" y2="70.83"/><line class="cls-1" x1="248.25" y1="127.99" x2="233.33" y2="127.99"/><line class="cls-1" x1="231.74" y1="186.62" x2="218.82" y2="179.17"/><line class="cls-1" x1="186.63" y1="231.74" x2="179.17" y2="218.82"/><line class="cls-1" x1="127.99" y1="248.25" x2="127.99" y2="233.33"/><line class="cls-1" x1="63.38" y1="231.74" x2="70.83" y2="218.82"/><line class="cls-1" x1="18.26" y1="186.63" x2="31.18" y2="179.17"/><line class="cls-1" x1="1.75" y1="122.01" x2="16.67" y2="122.01"/><line class="cls-1" x1="18.26" y1="63.38" x2="31.18" y2="70.83"/><line class="cls-1" x1="63.37" y1="18.26" x2="70.83" y2="31.18"/><line class="cls-1" x1="127.99" y1="1.75" x2="127.99" y2="16.67"/><line class="cls-1" x1="248.25" y1="122.01" x2="233.33" y2="122.01"/><line class="cls-1" x1="122.01" y1="248.25" x2="122.01" y2="233.33"/><line class="cls-1" x1="1.75" y1="127.99" x2="16.67" y2="127.99"/></svg>
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
@ -1,4 +1,5 @@
|
|||||||
# Module: Compliments
|
# Module: Compliments
|
||||||
|
|
||||||
The `compliments` module is one of the default modules of the MagicMirror.
|
The `compliments` module is one of the default modules of the MagicMirror.
|
||||||
This module displays a random compliment.
|
This module displays a random compliment.
|
||||||
|
|
||||||
|
@ -1,37 +1,18 @@
|
|||||||
/* global Log, Module, moment */
|
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: Compliments
|
* Module: Compliments
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
Module.register("compliments", {
|
Module.register("compliments", {
|
||||||
|
|
||||||
// Module config defaults.
|
// Module config defaults.
|
||||||
defaults: {
|
defaults: {
|
||||||
compliments: {
|
compliments: {
|
||||||
anytime: [
|
anytime: ["Hey there sexy!"],
|
||||||
"Hey there sexy!"
|
morning: ["Good morning, handsome!", "Enjoy your day!", "How was your sleep?"],
|
||||||
],
|
afternoon: ["Hello, beauty!", "You look sexy!", "Looking good today!"],
|
||||||
morning: [
|
evening: ["Wow, you look hot!", "You look nice!", "Hi, sexy!"],
|
||||||
"Good morning, handsome!",
|
"....-01-01": ["Happy new year!"]
|
||||||
"Enjoy your day!",
|
|
||||||
"How was your sleep?"
|
|
||||||
],
|
|
||||||
afternoon: [
|
|
||||||
"Hello, beauty!",
|
|
||||||
"You look sexy!",
|
|
||||||
"Looking good today!"
|
|
||||||
],
|
|
||||||
evening: [
|
|
||||||
"Wow, you look hot!",
|
|
||||||
"You look nice!",
|
|
||||||
"Hi, sexy!"
|
|
||||||
],
|
|
||||||
"....-01-01": [
|
|
||||||
"Happy new year!"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
updateInterval: 30000,
|
updateInterval: 30000,
|
||||||
remoteFile: null,
|
remoteFile: null,
|
||||||
@ -41,33 +22,46 @@ Module.register("compliments", {
|
|||||||
afternoonStartTime: 12,
|
afternoonStartTime: 12,
|
||||||
afternoonEndTime: 17,
|
afternoonEndTime: 17,
|
||||||
random: true,
|
random: true,
|
||||||
mockDate: null
|
mockDate: null,
|
||||||
|
advice: false
|
||||||
},
|
},
|
||||||
lastIndexUsed:-1,
|
lastIndexUsed: -1,
|
||||||
// Set currentweather from module
|
// Set currentweather from module
|
||||||
currentWeatherType: "",
|
currentWeatherType: "",
|
||||||
|
|
||||||
// Define required scripts.
|
// Define required scripts.
|
||||||
getScripts: function() {
|
getScripts: function () {
|
||||||
return ["moment.js"];
|
return ["moment.js"];
|
||||||
},
|
},
|
||||||
|
|
||||||
// Define start sequence.
|
// Define start sequence.
|
||||||
start: function() {
|
start: function () {
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
|
|
||||||
this.lastComplimentIndex = -1;
|
this.lastComplimentIndex = -1;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if (this.config.remoteFile !== null) {
|
if (this.config.remoteFile !== null) {
|
||||||
this.complimentFile(function(response) {
|
this.complimentFile(function (response) {
|
||||||
self.config.compliments = JSON.parse(response);
|
self.config.compliments = JSON.parse(response);
|
||||||
self.updateDom();
|
self.updateDom();
|
||||||
});
|
});
|
||||||
|
} else if (this.config.advice) {
|
||||||
|
var xobj = new XMLHttpRequest();
|
||||||
|
xobj.overrideMimeType("application/json");
|
||||||
|
xobj.open("GET", "https://api.adviceslip.com/advice", true);
|
||||||
|
xobj.onreadystatechange = function () {
|
||||||
|
if (xobj.readyState === 4 && xobj.status === 200) {
|
||||||
|
const adviceResp = JSON.parse(xobj.responseText);
|
||||||
|
self.config.compliments = adviceResp.slip.advice;
|
||||||
|
self.updateDom();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xobj.send(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule update timer.
|
// Schedule update timer.
|
||||||
setInterval(function() {
|
setInterval(function () {
|
||||||
self.updateDom(self.config.fadeSpeed);
|
self.updateDom(self.config.fadeSpeed);
|
||||||
}, this.config.updateInterval);
|
}, this.config.updateInterval);
|
||||||
},
|
},
|
||||||
@ -79,12 +73,12 @@ Module.register("compliments", {
|
|||||||
*
|
*
|
||||||
* return Number - Random index.
|
* return Number - Random index.
|
||||||
*/
|
*/
|
||||||
randomIndex: function(compliments) {
|
randomIndex: function (compliments) {
|
||||||
if (compliments.length === 1) {
|
if (compliments.length === 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var generate = function() {
|
var generate = function () {
|
||||||
return Math.floor(Math.random() * compliments.length);
|
return Math.floor(Math.random() * compliments.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,7 +98,7 @@ Module.register("compliments", {
|
|||||||
*
|
*
|
||||||
* return compliments Array<String> - Array with compliments for the time of the day.
|
* return compliments Array<String> - Array with compliments for the time of the day.
|
||||||
*/
|
*/
|
||||||
complimentArray: function() {
|
complimentArray: function () {
|
||||||
var hour = moment().hour();
|
var hour = moment().hour();
|
||||||
var date = this.config.mockDate ? this.config.mockDate : moment().format("YYYY-MM-DD");
|
var date = this.config.mockDate ? this.config.mockDate : moment().format("YYYY-MM-DD");
|
||||||
var compliments;
|
var compliments;
|
||||||
@ -113,7 +107,7 @@ Module.register("compliments", {
|
|||||||
compliments = this.config.compliments.morning.slice(0);
|
compliments = this.config.compliments.morning.slice(0);
|
||||||
} else if (hour >= this.config.afternoonStartTime && hour < this.config.afternoonEndTime && this.config.compliments.hasOwnProperty("afternoon")) {
|
} else if (hour >= this.config.afternoonStartTime && hour < this.config.afternoonEndTime && this.config.compliments.hasOwnProperty("afternoon")) {
|
||||||
compliments = this.config.compliments.afternoon.slice(0);
|
compliments = this.config.compliments.afternoon.slice(0);
|
||||||
} else if(this.config.compliments.hasOwnProperty("evening")) {
|
} else if (this.config.compliments.hasOwnProperty("evening")) {
|
||||||
compliments = this.config.compliments.evening.slice(0);
|
compliments = this.config.compliments.evening.slice(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +121,7 @@ Module.register("compliments", {
|
|||||||
|
|
||||||
compliments.push.apply(compliments, this.config.compliments.anytime);
|
compliments.push.apply(compliments, this.config.compliments.anytime);
|
||||||
|
|
||||||
for (entry in this.config.compliments) {
|
for (var entry in this.config.compliments) {
|
||||||
if (new RegExp(entry).test(date)) {
|
if (new RegExp(entry).test(date)) {
|
||||||
compliments.push.apply(compliments, this.config.compliments[entry]);
|
compliments.push.apply(compliments, this.config.compliments[entry]);
|
||||||
}
|
}
|
||||||
@ -139,13 +133,13 @@ Module.register("compliments", {
|
|||||||
/* complimentFile(callback)
|
/* complimentFile(callback)
|
||||||
* Retrieve a file from the local filesystem
|
* Retrieve a file from the local filesystem
|
||||||
*/
|
*/
|
||||||
complimentFile: function(callback) {
|
complimentFile: function (callback) {
|
||||||
var xobj = new XMLHttpRequest(),
|
var xobj = new XMLHttpRequest(),
|
||||||
isRemote = this.config.remoteFile.indexOf("http://") === 0 || this.config.remoteFile.indexOf("https://") === 0,
|
isRemote = this.config.remoteFile.indexOf("http://") === 0 || this.config.remoteFile.indexOf("https://") === 0,
|
||||||
path = isRemote ? this.config.remoteFile : this.file(this.config.remoteFile);
|
path = isRemote ? this.config.remoteFile : this.file(this.config.remoteFile);
|
||||||
xobj.overrideMimeType("application/json");
|
xobj.overrideMimeType("application/json");
|
||||||
xobj.open("GET", path, true);
|
xobj.open("GET", path, true);
|
||||||
xobj.onreadystatechange = function() {
|
xobj.onreadystatechange = function () {
|
||||||
if (xobj.readyState === 4 && xobj.status === 200) {
|
if (xobj.readyState === 4 && xobj.status === 200) {
|
||||||
callback(xobj.responseText);
|
callback(xobj.responseText);
|
||||||
}
|
}
|
||||||
@ -158,27 +152,26 @@ Module.register("compliments", {
|
|||||||
*
|
*
|
||||||
* return compliment string - A compliment.
|
* return compliment string - A compliment.
|
||||||
*/
|
*/
|
||||||
randomCompliment: function() {
|
randomCompliment: function () {
|
||||||
// get the current time of day compliments list
|
// get the current time of day compliments list
|
||||||
var compliments = this.complimentArray();
|
var compliments = this.complimentArray();
|
||||||
// variable for index to next message to display
|
// variable for index to next message to display
|
||||||
let index = 0;
|
let index = 0;
|
||||||
// are we randomizing
|
// are we randomizing
|
||||||
if(this.config.random){
|
if (this.config.random) {
|
||||||
// yes
|
// yes
|
||||||
index = this.randomIndex(compliments);
|
index = this.randomIndex(compliments);
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
// no, sequential
|
// no, sequential
|
||||||
// if doing sequential, don't fall off the end
|
// if doing sequential, don't fall off the end
|
||||||
index = (this.lastIndexUsed >= (compliments.length-1))?0: ++this.lastIndexUsed;
|
index = this.lastIndexUsed >= compliments.length - 1 ? 0 : ++this.lastIndexUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
return compliments[index] || "";
|
return compliments[index] || "";
|
||||||
},
|
},
|
||||||
|
|
||||||
// Override dom generator.
|
// Override dom generator.
|
||||||
getDom: function() {
|
getDom: function () {
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement("div");
|
||||||
wrapper.className = this.config.classes ? this.config.classes : "thin xlarge bright pre-line";
|
wrapper.className = this.config.classes ? this.config.classes : "thin xlarge bright pre-line";
|
||||||
// get the compliment text
|
// get the compliment text
|
||||||
@ -188,7 +181,7 @@ Module.register("compliments", {
|
|||||||
// create a span to hold it all
|
// create a span to hold it all
|
||||||
var compliment = document.createElement("span");
|
var compliment = document.createElement("span");
|
||||||
// process all the parts of the compliment text
|
// process all the parts of the compliment text
|
||||||
for (part of parts){
|
for (var part of parts) {
|
||||||
// create a text element for each part
|
// create a text element for each part
|
||||||
compliment.appendChild(document.createTextNode(part));
|
compliment.appendChild(document.createTextNode(part));
|
||||||
// add a break `
|
// add a break `
|
||||||
@ -202,7 +195,7 @@ Module.register("compliments", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// From data currentweather set weather type
|
// From data currentweather set weather type
|
||||||
setCurrentWeatherType: function(data) {
|
setCurrentWeatherType: function (data) {
|
||||||
var weatherIconTable = {
|
var weatherIconTable = {
|
||||||
"01d": "day_sunny",
|
"01d": "day_sunny",
|
||||||
"02d": "day_cloudy",
|
"02d": "day_cloudy",
|
||||||
@ -227,10 +220,9 @@ Module.register("compliments", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Override notification handler.
|
// Override notification handler.
|
||||||
notificationReceived: function(notification, payload, sender) {
|
notificationReceived: function (notification, payload, sender) {
|
||||||
if (notification === "CURRENTWEATHER_DATA") {
|
if (notification === "CURRENTWEATHER_DATA") {
|
||||||
this.setCurrentWeatherType(payload.data);
|
this.setCurrentWeatherType(payload.data);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Module: Current Weather
|
# Module: Current Weather
|
||||||
|
|
||||||
The `currentweather` module is one of the default modules of the MagicMirror.
|
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.
|
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,8 +3,6 @@
|
|||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
line-height: 65px;
|
line-height: 65px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
-ms-transform: translate(0, -3px); /* IE 9 */
|
|
||||||
-webkit-transform: translate(0, -3px); /* Safari */
|
|
||||||
transform: translate(0, -3px);
|
transform: translate(0, -3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
/* global Module */
|
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: CurrentWeather
|
* Module: CurrentWeather
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
Module.register("currentweather", {
|
||||||
Module.register("currentweather",{
|
|
||||||
|
|
||||||
// Default module config.
|
// Default module config.
|
||||||
defaults: {
|
defaults: {
|
||||||
location: false,
|
location: false,
|
||||||
@ -23,7 +19,6 @@ Module.register("currentweather",{
|
|||||||
showWindDirection: true,
|
showWindDirection: true,
|
||||||
showWindDirectionAsArrow: false,
|
showWindDirectionAsArrow: false,
|
||||||
useBeaufort: true,
|
useBeaufort: true,
|
||||||
appendLocationNameToHeader: false,
|
|
||||||
useKMPHwind: false,
|
useKMPHwind: false,
|
||||||
lang: config.language,
|
lang: config.language,
|
||||||
decimalSymbol: ".",
|
decimalSymbol: ".",
|
||||||
@ -67,7 +62,7 @@ Module.register("currentweather",{
|
|||||||
"11n": "wi-night-thunderstorm",
|
"11n": "wi-night-thunderstorm",
|
||||||
"13n": "wi-night-snow",
|
"13n": "wi-night-snow",
|
||||||
"50n": "wi-night-alt-cloudy-windy"
|
"50n": "wi-night-alt-cloudy-windy"
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// create a variable for the first upcoming calendar event. Used if no location is specified.
|
// create a variable for the first upcoming calendar event. Used if no location is specified.
|
||||||
@ -77,17 +72,17 @@ Module.register("currentweather",{
|
|||||||
fetchedLocationName: "",
|
fetchedLocationName: "",
|
||||||
|
|
||||||
// Define required scripts.
|
// Define required scripts.
|
||||||
getScripts: function() {
|
getScripts: function () {
|
||||||
return ["moment.js"];
|
return ["moment.js"];
|
||||||
},
|
},
|
||||||
|
|
||||||
// Define required scripts.
|
// Define required scripts.
|
||||||
getStyles: function() {
|
getStyles: function () {
|
||||||
return ["weather-icons.css", "currentweather.css"];
|
return ["weather-icons.css", "currentweather.css"];
|
||||||
},
|
},
|
||||||
|
|
||||||
// Define required translations.
|
// Define required translations.
|
||||||
getTranslations: function() {
|
getTranslations: function () {
|
||||||
// The translations for the default modules are defined in the core translation files.
|
// The translations for the default modules are defined in the core translation files.
|
||||||
// Therefor we can just return false. Otherwise we should have returned a dictionary.
|
// Therefor we can just return false. Otherwise we should have returned a dictionary.
|
||||||
// If you're trying to build your own module including translations, check out the documentation.
|
// If you're trying to build your own module including translations, check out the documentation.
|
||||||
@ -95,7 +90,7 @@ Module.register("currentweather",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Define start sequence.
|
// Define start sequence.
|
||||||
start: function() {
|
start: function () {
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
|
|
||||||
// Set locale.
|
// Set locale.
|
||||||
@ -113,13 +108,11 @@ Module.register("currentweather",{
|
|||||||
this.feelsLike = null;
|
this.feelsLike = null;
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.scheduleUpdate(this.config.initialLoadDelay);
|
this.scheduleUpdate(this.config.initialLoadDelay);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// add extra information of current weather
|
// add extra information of current weather
|
||||||
// windDirection, humidity, sunrise and sunset
|
// windDirection, humidity, sunrise and sunset
|
||||||
addExtraInfoWeather: function(wrapper) {
|
addExtraInfoWeather: function (wrapper) {
|
||||||
|
|
||||||
var small = document.createElement("div");
|
var small = document.createElement("div");
|
||||||
small.className = "normal medium";
|
small.className = "normal medium";
|
||||||
|
|
||||||
@ -134,8 +127,8 @@ Module.register("currentweather",{
|
|||||||
if (this.config.showWindDirection) {
|
if (this.config.showWindDirection) {
|
||||||
var windDirection = document.createElement("sup");
|
var windDirection = document.createElement("sup");
|
||||||
if (this.config.showWindDirectionAsArrow) {
|
if (this.config.showWindDirectionAsArrow) {
|
||||||
if(this.windDeg !== null) {
|
if (this.windDeg !== null) {
|
||||||
windDirection.innerHTML = " <i class=\"fa fa-long-arrow-down\" style=\"transform:rotate("+this.windDeg+"deg);\"></i> ";
|
windDirection.innerHTML = ' <i class="fa fa-long-arrow-down" style="transform:rotate(' + this.windDeg + 'deg);"></i> ';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
windDirection.innerHTML = " " + this.translate(this.windDirection);
|
windDirection.innerHTML = " " + this.translate(this.windDirection);
|
||||||
@ -150,15 +143,15 @@ Module.register("currentweather",{
|
|||||||
var humidity = document.createElement("span");
|
var humidity = document.createElement("span");
|
||||||
humidity.innerHTML = this.humidity;
|
humidity.innerHTML = this.humidity;
|
||||||
|
|
||||||
var spacer = document.createElement("sup");
|
var supspacer = document.createElement("sup");
|
||||||
spacer.innerHTML = " ";
|
supspacer.innerHTML = " ";
|
||||||
|
|
||||||
var humidityIcon = document.createElement("sup");
|
var humidityIcon = document.createElement("sup");
|
||||||
humidityIcon.className = "wi wi-humidity humidityIcon";
|
humidityIcon.className = "wi wi-humidity humidityIcon";
|
||||||
humidityIcon.innerHTML = " ";
|
humidityIcon.innerHTML = " ";
|
||||||
|
|
||||||
small.appendChild(humidity);
|
small.appendChild(humidity);
|
||||||
small.appendChild(spacer);
|
small.appendChild(supspacer);
|
||||||
small.appendChild(humidityIcon);
|
small.appendChild(humidityIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +167,7 @@ Module.register("currentweather",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Override dom generator.
|
// Override dom generator.
|
||||||
getDom: function() {
|
getDom: function () {
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement("div");
|
||||||
wrapper.className = this.config.tableClass;
|
wrapper.className = this.config.tableClass;
|
||||||
|
|
||||||
@ -201,17 +194,17 @@ Module.register("currentweather",{
|
|||||||
if (this.config.units === "metric" || this.config.units === "imperial") {
|
if (this.config.units === "metric" || this.config.units === "imperial") {
|
||||||
degreeLabel += "°";
|
degreeLabel += "°";
|
||||||
}
|
}
|
||||||
if(this.config.degreeLabel) {
|
if (this.config.degreeLabel) {
|
||||||
switch(this.config.units) {
|
switch (this.config.units) {
|
||||||
case "metric":
|
case "metric":
|
||||||
degreeLabel += "C";
|
degreeLabel += "C";
|
||||||
break;
|
break;
|
||||||
case "imperial":
|
case "imperial":
|
||||||
degreeLabel += "F";
|
degreeLabel += "F";
|
||||||
break;
|
break;
|
||||||
case "default":
|
case "default":
|
||||||
degreeLabel += "K";
|
degreeLabel += "K";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +247,7 @@ Module.register("currentweather",{
|
|||||||
|
|
||||||
wrapper.appendChild(large);
|
wrapper.appendChild(large);
|
||||||
|
|
||||||
if (this.config.showFeelsLike && this.config.onlyTemp === false){
|
if (this.config.showFeelsLike && this.config.onlyTemp === false) {
|
||||||
var small = document.createElement("div");
|
var small = document.createElement("div");
|
||||||
small.className = "normal medium";
|
small.className = "normal medium";
|
||||||
|
|
||||||
@ -270,7 +263,7 @@ Module.register("currentweather",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Override getHeader method.
|
// Override getHeader method.
|
||||||
getHeader: function() {
|
getHeader: function () {
|
||||||
if (this.config.appendLocationNameToHeader && this.data.header !== undefined) {
|
if (this.config.appendLocationNameToHeader && this.data.header !== undefined) {
|
||||||
return this.data.header + " " + this.fetchedLocationName;
|
return this.data.header + " " + this.fetchedLocationName;
|
||||||
}
|
}
|
||||||
@ -283,10 +276,10 @@ Module.register("currentweather",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Override notification handler.
|
// Override notification handler.
|
||||||
notificationReceived: function(notification, payload, sender) {
|
notificationReceived: function (notification, payload, sender) {
|
||||||
if (notification === "DOM_OBJECTS_CREATED") {
|
if (notification === "DOM_OBJECTS_CREATED") {
|
||||||
if (this.config.appendLocationNameToHeader) {
|
if (this.config.appendLocationNameToHeader) {
|
||||||
this.hide(0, {lockString: this.identifier});
|
this.hide(0, { lockString: this.identifier });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (notification === "CALENDAR_EVENTS") {
|
if (notification === "CALENDAR_EVENTS") {
|
||||||
@ -318,7 +311,7 @@ Module.register("currentweather",{
|
|||||||
* Requests new data from openweather.org.
|
* Requests new data from openweather.org.
|
||||||
* Calls processWeather on succesfull response.
|
* Calls processWeather on succesfull response.
|
||||||
*/
|
*/
|
||||||
updateWeather: function() {
|
updateWeather: function () {
|
||||||
if (this.config.appid === "") {
|
if (this.config.appid === "") {
|
||||||
Log.error("CurrentWeather: APPID not set!");
|
Log.error("CurrentWeather: APPID not set!");
|
||||||
return;
|
return;
|
||||||
@ -330,7 +323,7 @@ Module.register("currentweather",{
|
|||||||
|
|
||||||
var weatherRequest = new XMLHttpRequest();
|
var weatherRequest = new XMLHttpRequest();
|
||||||
weatherRequest.open("GET", url, true);
|
weatherRequest.open("GET", url, true);
|
||||||
weatherRequest.onreadystatechange = function() {
|
weatherRequest.onreadystatechange = function () {
|
||||||
if (this.readyState === 4) {
|
if (this.readyState === 4) {
|
||||||
if (this.status === 200) {
|
if (this.status === 200) {
|
||||||
self.processWeather(JSON.parse(this.response));
|
self.processWeather(JSON.parse(this.response));
|
||||||
@ -344,7 +337,7 @@ Module.register("currentweather",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (retry) {
|
if (retry) {
|
||||||
self.scheduleUpdate((self.loaded) ? -1 : self.config.retryDelay);
|
self.scheduleUpdate(self.loaded ? -1 : self.config.retryDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -356,18 +349,18 @@ Module.register("currentweather",{
|
|||||||
*
|
*
|
||||||
* return String - URL params.
|
* return String - URL params.
|
||||||
*/
|
*/
|
||||||
getParams: function() {
|
getParams: function () {
|
||||||
var params = "?";
|
var params = "?";
|
||||||
if(this.config.locationID) {
|
if (this.config.locationID) {
|
||||||
params += "id=" + this.config.locationID;
|
params += "id=" + this.config.locationID;
|
||||||
} else if(this.config.location) {
|
} else if (this.config.location) {
|
||||||
params += "q=" + this.config.location;
|
params += "q=" + this.config.location;
|
||||||
} else if (this.firstEvent && this.firstEvent.geo) {
|
} else if (this.firstEvent && this.firstEvent.geo) {
|
||||||
params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon;
|
params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon;
|
||||||
} else if (this.firstEvent && this.firstEvent.location) {
|
} else if (this.firstEvent && this.firstEvent.location) {
|
||||||
params += "q=" + this.firstEvent.location;
|
params += "q=" + this.firstEvent.location;
|
||||||
} else {
|
} else {
|
||||||
this.hide(this.config.animationSpeed, {lockString:this.identifier});
|
this.hide(this.config.animationSpeed, { lockString: this.identifier });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,8 +376,7 @@ Module.register("currentweather",{
|
|||||||
*
|
*
|
||||||
* argument data object - Weather information received form openweather.org.
|
* argument data object - Weather information received form openweather.org.
|
||||||
*/
|
*/
|
||||||
processWeather: function(data) {
|
processWeather: function (data) {
|
||||||
|
|
||||||
if (!data || !data.main || typeof data.main.temp === "undefined") {
|
if (!data || !data.main || typeof data.main.temp === "undefined") {
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
// Maybe this needs a better check?
|
// Maybe this needs a better check?
|
||||||
@ -396,7 +388,7 @@ Module.register("currentweather",{
|
|||||||
this.fetchedLocationName = data.name;
|
this.fetchedLocationName = data.name;
|
||||||
this.feelsLike = 0;
|
this.feelsLike = 0;
|
||||||
|
|
||||||
if (this.config.useBeaufort){
|
if (this.config.useBeaufort) {
|
||||||
this.windSpeed = this.ms2Beaufort(this.roundValue(data.wind.speed));
|
this.windSpeed = this.ms2Beaufort(this.roundValue(data.wind.speed));
|
||||||
} else if (this.config.useKMPHwind) {
|
} else if (this.config.useKMPHwind) {
|
||||||
this.windSpeed = parseFloat((data.wind.speed * 60 * 60) / 1000).toFixed(0);
|
this.windSpeed = parseFloat((data.wind.speed * 60 * 60) / 1000).toFixed(0);
|
||||||
@ -408,52 +400,59 @@ Module.register("currentweather",{
|
|||||||
var windInMph = parseFloat(data.wind.speed * 2.23694);
|
var windInMph = parseFloat(data.wind.speed * 2.23694);
|
||||||
|
|
||||||
var tempInF = 0;
|
var tempInF = 0;
|
||||||
switch (this.config.units){
|
switch (this.config.units) {
|
||||||
case "metric": tempInF = 1.8 * this.temperature + 32;
|
case "metric":
|
||||||
break;
|
tempInF = 1.8 * this.temperature + 32;
|
||||||
case "imperial": tempInF = this.temperature;
|
break;
|
||||||
break;
|
case "imperial":
|
||||||
case "default":
|
tempInF = this.temperature;
|
||||||
var tc = this.temperature - 273.15;
|
break;
|
||||||
tempInF = 1.8 * tc + 32;
|
case "default":
|
||||||
break;
|
tempInF = 1.8 * (this.temperature - 273.15) + 32;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windInMph > 3 && tempInF < 50){
|
if (windInMph > 3 && tempInF < 50) {
|
||||||
// windchill
|
// windchill
|
||||||
var windChillInF = Math.round(35.74+0.6215*tempInF-35.75*Math.pow(windInMph,0.16)+0.4275*tempInF*Math.pow(windInMph,0.16));
|
var windChillInF = Math.round(35.74 + 0.6215 * tempInF - 35.75 * Math.pow(windInMph, 0.16) + 0.4275 * tempInF * Math.pow(windInMph, 0.16));
|
||||||
var windChillInC = (windChillInF - 32) * (5/9);
|
var windChillInC = (windChillInF - 32) * (5 / 9);
|
||||||
// this.feelsLike = windChillInC.toFixed(0);
|
// this.feelsLike = windChillInC.toFixed(0);
|
||||||
|
|
||||||
switch (this.config.units){
|
switch (this.config.units) {
|
||||||
case "metric": this.feelsLike = windChillInC.toFixed(0);
|
case "metric":
|
||||||
break;
|
this.feelsLike = windChillInC.toFixed(0);
|
||||||
case "imperial": this.feelsLike = windChillInF.toFixed(0);
|
break;
|
||||||
break;
|
case "imperial":
|
||||||
case "default":
|
this.feelsLike = windChillInF.toFixed(0);
|
||||||
var tc = windChillInC + 273.15;
|
break;
|
||||||
this.feelsLike = tc.toFixed(0);
|
case "default":
|
||||||
break;
|
this.feelsLike = (windChillInC + 273.15).toFixed(0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (tempInF > 80 && this.humidity > 40) {
|
||||||
} else if (tempInF > 80 && this.humidity > 40){
|
|
||||||
// heat index
|
// heat index
|
||||||
var Hindex = -42.379 + 2.04901523*tempInF + 10.14333127*this.humidity
|
var Hindex =
|
||||||
- 0.22475541*tempInF*this.humidity - 6.83783*Math.pow(10,-3)*tempInF*tempInF
|
-42.379 +
|
||||||
- 5.481717*Math.pow(10,-2)*this.humidity*this.humidity
|
2.04901523 * tempInF +
|
||||||
+ 1.22874*Math.pow(10,-3)*tempInF*tempInF*this.humidity
|
10.14333127 * this.humidity -
|
||||||
+ 8.5282*Math.pow(10,-4)*tempInF*this.humidity*this.humidity
|
0.22475541 * tempInF * this.humidity -
|
||||||
- 1.99*Math.pow(10,-6)*tempInF*tempInF*this.humidity*this.humidity;
|
6.83783 * Math.pow(10, -3) * tempInF * tempInF -
|
||||||
|
5.481717 * Math.pow(10, -2) * this.humidity * this.humidity +
|
||||||
|
1.22874 * Math.pow(10, -3) * tempInF * tempInF * this.humidity +
|
||||||
|
8.5282 * Math.pow(10, -4) * tempInF * this.humidity * this.humidity -
|
||||||
|
1.99 * Math.pow(10, -6) * tempInF * tempInF * this.humidity * this.humidity;
|
||||||
|
|
||||||
switch (this.config.units){
|
switch (this.config.units) {
|
||||||
case "metric": this.feelsLike = parseFloat((Hindex - 32) / 1.8).toFixed(0);
|
case "metric":
|
||||||
break;
|
this.feelsLike = parseFloat((Hindex - 32) / 1.8).toFixed(0);
|
||||||
case "imperial": this.feelsLike = Hindex.toFixed(0);
|
break;
|
||||||
break;
|
case "imperial":
|
||||||
case "default":
|
this.feelsLike = Hindex.toFixed(0);
|
||||||
var tc = parseFloat((Hindex - 32) / 1.8) + 273.15;
|
break;
|
||||||
this.feelsLike = tc.toFixed(0);
|
case "default":
|
||||||
break;
|
var tc = parseFloat((Hindex - 32) / 1.8) + 273.15;
|
||||||
|
this.feelsLike = tc.toFixed(0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.feelsLike = parseFloat(this.temperature).toFixed(0);
|
this.feelsLike = parseFloat(this.temperature).toFixed(0);
|
||||||
@ -470,7 +469,7 @@ Module.register("currentweather",{
|
|||||||
// The moment().format('h') method has a bug on the Raspberry Pi.
|
// The moment().format('h') method has a bug on the Raspberry Pi.
|
||||||
// So we need to generate the timestring manually.
|
// So we need to generate the timestring manually.
|
||||||
// See issue: https://github.com/MichMich/MagicMirror/issues/181
|
// See issue: https://github.com/MichMich/MagicMirror/issues/181
|
||||||
var sunriseSunsetDateObject = (sunrise < now && sunset > now) ? sunset : sunrise;
|
var sunriseSunsetDateObject = sunrise < now && sunset > now ? sunset : sunrise;
|
||||||
var timeString = moment(sunriseSunsetDateObject).format("HH:mm");
|
var timeString = moment(sunriseSunsetDateObject).format("HH:mm");
|
||||||
if (this.config.timeFormat !== 24) {
|
if (this.config.timeFormat !== 24) {
|
||||||
//var hours = sunriseSunsetDateObject.getHours() % 12 || 12;
|
//var hours = sunriseSunsetDateObject.getHours() % 12 || 12;
|
||||||
@ -489,12 +488,12 @@ Module.register("currentweather",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.sunriseSunsetTime = timeString;
|
this.sunriseSunsetTime = timeString;
|
||||||
this.sunriseSunsetIcon = (sunrise < now && sunset > now) ? "wi-sunset" : "wi-sunrise";
|
this.sunriseSunsetIcon = sunrise < now && sunset > now ? "wi-sunset" : "wi-sunrise";
|
||||||
|
|
||||||
this.show(this.config.animationSpeed, {lockString:this.identifier});
|
this.show(this.config.animationSpeed, { lockString: this.identifier });
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
this.updateDom(this.config.animationSpeed);
|
this.updateDom(this.config.animationSpeed);
|
||||||
this.sendNotification("CURRENTWEATHER_DATA", {data: data});
|
this.sendNotification("CURRENTWEATHER_DATA", { data: data });
|
||||||
},
|
},
|
||||||
|
|
||||||
/* scheduleUpdate()
|
/* scheduleUpdate()
|
||||||
@ -502,14 +501,14 @@ Module.register("currentweather",{
|
|||||||
*
|
*
|
||||||
* argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used.
|
* argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used.
|
||||||
*/
|
*/
|
||||||
scheduleUpdate: function(delay) {
|
scheduleUpdate: function (delay) {
|
||||||
var nextLoad = this.config.updateInterval;
|
var nextLoad = this.config.updateInterval;
|
||||||
if (typeof delay !== "undefined" && delay >= 0) {
|
if (typeof delay !== "undefined" && delay >= 0) {
|
||||||
nextLoad = delay;
|
nextLoad = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
self.updateWeather();
|
self.updateWeather();
|
||||||
}, nextLoad);
|
}, nextLoad);
|
||||||
},
|
},
|
||||||
@ -518,15 +517,15 @@ Module.register("currentweather",{
|
|||||||
* Converts m2 to beaufort (windspeed).
|
* Converts m2 to beaufort (windspeed).
|
||||||
*
|
*
|
||||||
* see:
|
* see:
|
||||||
* http://www.spc.noaa.gov/faq/tornado/beaufort.html
|
* https://www.spc.noaa.gov/faq/tornado/beaufort.html
|
||||||
* https://en.wikipedia.org/wiki/Beaufort_scale#Modern_scale
|
* https://en.wikipedia.org/wiki/Beaufort_scale#Modern_scale
|
||||||
*
|
*
|
||||||
* argument ms number - Windspeed in m/s.
|
* argument ms number - Windspeed in m/s.
|
||||||
*
|
*
|
||||||
* return number - Windspeed in beaufort.
|
* return number - Windspeed in beaufort.
|
||||||
*/
|
*/
|
||||||
ms2Beaufort: function(ms) {
|
ms2Beaufort: function (ms) {
|
||||||
var kmh = ms * 60 * 60 / 1000;
|
var kmh = (ms * 60 * 60) / 1000;
|
||||||
var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
|
var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000];
|
||||||
for (var beaufort in speeds) {
|
for (var beaufort in speeds) {
|
||||||
var speed = speeds[beaufort];
|
var speed = speeds[beaufort];
|
||||||
@ -537,8 +536,8 @@ Module.register("currentweather",{
|
|||||||
return 12;
|
return 12;
|
||||||
},
|
},
|
||||||
|
|
||||||
deg2Cardinal: function(deg) {
|
deg2Cardinal: function (deg) {
|
||||||
if (deg>11.25 && deg<=33.75){
|
if (deg > 11.25 && deg <= 33.75) {
|
||||||
return "NNE";
|
return "NNE";
|
||||||
} else if (deg > 33.75 && deg <= 56.25) {
|
} else if (deg > 33.75 && deg <= 56.25) {
|
||||||
return "NE";
|
return "NE";
|
||||||
@ -580,9 +579,8 @@ Module.register("currentweather",{
|
|||||||
*
|
*
|
||||||
* return string - Rounded Temperature.
|
* return string - Rounded Temperature.
|
||||||
*/
|
*/
|
||||||
roundValue: function(temperature) {
|
roundValue: function (temperature) {
|
||||||
var decimals = this.config.roundTemp ? 0 : 1;
|
var decimals = this.config.roundTemp ? 0 : 1;
|
||||||
return parseFloat(temperature).toFixed(decimals);
|
return parseFloat(temperature).toFixed(decimals);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,24 +1,15 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Default Modules List
|
* Default Modules List
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Modules listed below can be loaded without the 'default/' prefix. Omitting the default folder name.
|
// Modules listed below can be loaded without the 'default/' prefix. Omitting the default folder name.
|
||||||
|
|
||||||
var defaultModules = [
|
var defaultModules = ["alert", "calendar", "clock", "compliments", "currentweather", "helloworld", "newsfeed", "weatherforecast", "updatenotification", "weather"];
|
||||||
"alert",
|
|
||||||
"calendar",
|
|
||||||
"clock",
|
|
||||||
"compliments",
|
|
||||||
"currentweather",
|
|
||||||
"helloworld",
|
|
||||||
"newsfeed",
|
|
||||||
"weatherforecast",
|
|
||||||
"updatenotification",
|
|
||||||
"weather"
|
|
||||||
];
|
|
||||||
|
|
||||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||||
if (typeof module !== "undefined") {module.exports = defaultModules;}
|
if (typeof module !== "undefined") {
|
||||||
|
module.exports = defaultModules;
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Module: Hello World
|
# Module: Hello World
|
||||||
|
|
||||||
The `helloworld` module is one of the default modules of the MagicMirror. It is a simple way to display a static text on the mirror.
|
The `helloworld` module is one of the default modules of the MagicMirror. It is a simple way to display a static text on the mirror.
|
||||||
|
|
||||||
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/helloworld.html).
|
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/helloworld.html).
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
/* global Module */
|
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: HelloWorld
|
* Module: HelloWorld
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
Module.register("helloworld", {
|
||||||
Module.register("helloworld",{
|
|
||||||
|
|
||||||
// Default module config.
|
// Default module config.
|
||||||
defaults: {
|
defaults: {
|
||||||
text: "Hello World!"
|
text: "Hello World!"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Module: News Feed
|
# Module: News Feed
|
||||||
The `newsfeed ` module is one of the default modules of the MagicMirror.
|
|
||||||
This module displays news headlines based on an RSS feed. Scrolling through news headlines happens time-based (````updateInterval````), but can also be controlled by sending news feed specific notifications to the module.
|
The `newsfeed` module is one of the default modules of the MagicMirror.
|
||||||
|
This module displays news headlines based on an RSS feed. Scrolling through news headlines happens time-based (`updateInterval`), but can also be controlled by sending news feed specific notifications to the module.
|
||||||
|
|
||||||
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/newsfeed.html).
|
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/newsfeed.html).
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Fetcher
|
* Fetcher
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ var iconv = require("iconv-lite");
|
|||||||
* attribute logFeedWarnings boolean - Log warnings when there is an error parsing a news article.
|
* attribute logFeedWarnings boolean - Log warnings when there is an error parsing a news article.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Fetcher = function(url, reloadInterval, encoding, logFeedWarnings) {
|
var Fetcher = function (url, reloadInterval, encoding, logFeedWarnings) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (reloadInterval < 1000) {
|
if (reloadInterval < 1000) {
|
||||||
reloadInterval = 1000;
|
reloadInterval = 1000;
|
||||||
@ -26,8 +26,8 @@ var Fetcher = function(url, reloadInterval, encoding, logFeedWarnings) {
|
|||||||
var reloadTimer = null;
|
var reloadTimer = null;
|
||||||
var items = [];
|
var items = [];
|
||||||
|
|
||||||
var fetchFailedCallback = function() {};
|
var fetchFailedCallback = function () {};
|
||||||
var itemsReceivedCallback = function() {};
|
var itemsReceivedCallback = function () {};
|
||||||
|
|
||||||
/* private methods */
|
/* private methods */
|
||||||
|
|
||||||
@ -35,32 +35,29 @@ var Fetcher = function(url, reloadInterval, encoding, logFeedWarnings) {
|
|||||||
* Request the new items.
|
* Request the new items.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var fetchNews = function() {
|
var fetchNews = function () {
|
||||||
clearTimeout(reloadTimer);
|
clearTimeout(reloadTimer);
|
||||||
reloadTimer = null;
|
reloadTimer = null;
|
||||||
items = [];
|
items = [];
|
||||||
|
|
||||||
var parser = new FeedMe();
|
var parser = new FeedMe();
|
||||||
|
|
||||||
parser.on("item", function(item) {
|
parser.on("item", function (item) {
|
||||||
|
|
||||||
var title = item.title;
|
var title = item.title;
|
||||||
var description = item.description || item.summary || item.content || "";
|
var description = item.description || item.summary || item.content || "";
|
||||||
var pubdate = item.pubdate || item.published || item.updated || item["dc:date"];
|
var pubdate = item.pubdate || item.published || item.updated || item["dc:date"];
|
||||||
var url = item.url || item.link || "";
|
var url = item.url || item.link || "";
|
||||||
|
|
||||||
if (title && pubdate) {
|
if (title && pubdate) {
|
||||||
|
var regex = /(<([^>]+)>)/gi;
|
||||||
var regex = /(<([^>]+)>)/ig;
|
|
||||||
description = description.toString().replace(regex, "");
|
description = description.toString().replace(regex, "");
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
title: title,
|
title: title,
|
||||||
description: description,
|
description: description,
|
||||||
pubdate: pubdate,
|
pubdate: pubdate,
|
||||||
url: url,
|
url: url
|
||||||
});
|
});
|
||||||
|
|
||||||
} else if (logFeedWarnings) {
|
} else if (logFeedWarnings) {
|
||||||
console.log("Can't parse feed item:");
|
console.log("Can't parse feed item:");
|
||||||
console.log(item);
|
console.log(item);
|
||||||
@ -70,39 +67,37 @@ var Fetcher = function(url, reloadInterval, encoding, logFeedWarnings) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.on("end", function() {
|
parser.on("end", function () {
|
||||||
//console.log("end parsing - " + url);
|
//console.log("end parsing - " + url);
|
||||||
self.broadcastItems();
|
self.broadcastItems();
|
||||||
scheduleTimer();
|
scheduleTimer();
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.on("error", function(error) {
|
parser.on("error", function (error) {
|
||||||
fetchFailedCallback(self, error);
|
fetchFailedCallback(self, error);
|
||||||
scheduleTimer();
|
scheduleTimer();
|
||||||
});
|
});
|
||||||
|
|
||||||
nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
||||||
headers = {"User-Agent": "Mozilla/5.0 (Node.js "+ nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)",
|
var headers = { "User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)", "Cache-Control": "max-age=0, no-cache, no-store, must-revalidate", Pragma: "no-cache" };
|
||||||
"Cache-Control": "max-age=0, no-cache, no-store, must-revalidate",
|
|
||||||
"Pragma": "no-cache"};
|
|
||||||
|
|
||||||
request({uri: url, encoding: null, headers: headers})
|
request({ uri: url, encoding: null, headers: headers })
|
||||||
.on("error", function(error) {
|
.on("error", function (error) {
|
||||||
fetchFailedCallback(self, error);
|
fetchFailedCallback(self, error);
|
||||||
scheduleTimer();
|
scheduleTimer();
|
||||||
})
|
})
|
||||||
.pipe(iconv.decodeStream(encoding)).pipe(parser);
|
.pipe(iconv.decodeStream(encoding))
|
||||||
|
.pipe(parser);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* scheduleTimer()
|
/* scheduleTimer()
|
||||||
* Schedule the timer for the next update.
|
* Schedule the timer for the next update.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var scheduleTimer = function() {
|
var scheduleTimer = function () {
|
||||||
//console.log('Schedule update timer.');
|
//console.log('Schedule update timer.');
|
||||||
clearTimeout(reloadTimer);
|
clearTimeout(reloadTimer);
|
||||||
reloadTimer = setTimeout(function() {
|
reloadTimer = setTimeout(function () {
|
||||||
fetchNews();
|
fetchNews();
|
||||||
}, reloadInterval);
|
}, reloadInterval);
|
||||||
};
|
};
|
||||||
@ -114,7 +109,7 @@ var Fetcher = function(url, reloadInterval, encoding, logFeedWarnings) {
|
|||||||
*
|
*
|
||||||
* attribute interval number - Interval for the update in milliseconds.
|
* attribute interval number - Interval for the update in milliseconds.
|
||||||
*/
|
*/
|
||||||
this.setReloadInterval = function(interval) {
|
this.setReloadInterval = function (interval) {
|
||||||
if (interval > 1000 && interval < reloadInterval) {
|
if (interval > 1000 && interval < reloadInterval) {
|
||||||
reloadInterval = interval;
|
reloadInterval = interval;
|
||||||
}
|
}
|
||||||
@ -123,14 +118,14 @@ var Fetcher = function(url, reloadInterval, encoding, logFeedWarnings) {
|
|||||||
/* startFetch()
|
/* startFetch()
|
||||||
* Initiate fetchNews();
|
* Initiate fetchNews();
|
||||||
*/
|
*/
|
||||||
this.startFetch = function() {
|
this.startFetch = function () {
|
||||||
fetchNews();
|
fetchNews();
|
||||||
};
|
};
|
||||||
|
|
||||||
/* broadcastItems()
|
/* broadcastItems()
|
||||||
* Broadcast the existing items.
|
* Broadcast the existing items.
|
||||||
*/
|
*/
|
||||||
this.broadcastItems = function() {
|
this.broadcastItems = function () {
|
||||||
if (items.length <= 0) {
|
if (items.length <= 0) {
|
||||||
//console.log('No items to broadcast yet.');
|
//console.log('No items to broadcast yet.');
|
||||||
return;
|
return;
|
||||||
@ -139,19 +134,19 @@ var Fetcher = function(url, reloadInterval, encoding, logFeedWarnings) {
|
|||||||
itemsReceivedCallback(self);
|
itemsReceivedCallback(self);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onReceive = function(callback) {
|
this.onReceive = function (callback) {
|
||||||
itemsReceivedCallback = callback;
|
itemsReceivedCallback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onError = function(callback) {
|
this.onError = function (callback) {
|
||||||
fetchFailedCallback = callback;
|
fetchFailedCallback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.url = function() {
|
this.url = function () {
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.items = function() {
|
this.items = function () {
|
||||||
return items;
|
return items;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
/* global Module */
|
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: NewsFeed
|
* Module: NewsFeed
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
Module.register("newsfeed", {
|
||||||
Module.register("newsfeed",{
|
|
||||||
|
|
||||||
// Default module config.
|
// Default module config.
|
||||||
defaults: {
|
defaults: {
|
||||||
feeds: [
|
feeds: [
|
||||||
{
|
{
|
||||||
title: "New York Times",
|
title: "New York Times",
|
||||||
url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml",
|
url: "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml",
|
||||||
encoding: "UTF-8" //ISO-8859-1
|
encoding: "UTF-8" //ISO-8859-1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -44,12 +40,12 @@ Module.register("newsfeed",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Define required scripts.
|
// Define required scripts.
|
||||||
getScripts: function() {
|
getScripts: function () {
|
||||||
return ["moment.js"];
|
return ["moment.js"];
|
||||||
},
|
},
|
||||||
|
|
||||||
// Define required translations.
|
// Define required translations.
|
||||||
getTranslations: function() {
|
getTranslations: function () {
|
||||||
// The translations for the default modules are defined in the core translation files.
|
// The translations for the default modules are defined in the core translation files.
|
||||||
// Therefor we can just return false. Otherwise we should have returned a dictionary.
|
// Therefor we can just return false. Otherwise we should have returned a dictionary.
|
||||||
// If you're trying to build your own module including translations, check out the documentation.
|
// If you're trying to build your own module including translations, check out the documentation.
|
||||||
@ -57,7 +53,7 @@ Module.register("newsfeed",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Define start sequence.
|
// Define start sequence.
|
||||||
start: function() {
|
start: function () {
|
||||||
Log.info("Starting module: " + this.name);
|
Log.info("Starting module: " + this.name);
|
||||||
|
|
||||||
// Set locale.
|
// Set locale.
|
||||||
@ -74,7 +70,7 @@ Module.register("newsfeed",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Override socket notification handler.
|
// Override socket notification handler.
|
||||||
socketNotificationReceived: function(notification, payload) {
|
socketNotificationReceived: function (notification, payload) {
|
||||||
if (notification === "NEWS_ITEMS") {
|
if (notification === "NEWS_ITEMS") {
|
||||||
this.generateFeed(payload);
|
this.generateFeed(payload);
|
||||||
|
|
||||||
@ -87,7 +83,7 @@ Module.register("newsfeed",{
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Override dom generator.
|
// Override dom generator.
|
||||||
getDom: function() {
|
getDom: function () {
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement("div");
|
||||||
|
|
||||||
if (this.config.feedUrl) {
|
if (this.config.feedUrl) {
|
||||||
@ -101,7 +97,6 @@ Module.register("newsfeed",{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.newsItems.length > 0) {
|
if (this.newsItems.length > 0) {
|
||||||
|
|
||||||
// this.config.showFullArticle is a run-time configuration, triggered by optional notifications
|
// this.config.showFullArticle is a run-time configuration, triggered by optional notifications
|
||||||
if (!this.config.showFullArticle && (this.config.showSourceTitle || this.config.showPublishDate)) {
|
if (!this.config.showFullArticle && (this.config.showSourceTitle || this.config.showPublishDate)) {
|
||||||
var sourceAndTimestamp = document.createElement("div");
|
var sourceAndTimestamp = document.createElement("div");
|
||||||
@ -116,7 +111,7 @@ Module.register("newsfeed",{
|
|||||||
if (this.config.showPublishDate) {
|
if (this.config.showPublishDate) {
|
||||||
sourceAndTimestamp.innerHTML += moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow();
|
sourceAndTimestamp.innerHTML += moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow();
|
||||||
}
|
}
|
||||||
if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "" || this.config.showPublishDate) {
|
if ((this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "") || this.config.showPublishDate) {
|
||||||
sourceAndTimestamp.innerHTML += ":";
|
sourceAndTimestamp.innerHTML += ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,47 +121,42 @@ Module.register("newsfeed",{
|
|||||||
//Remove selected tags from the beginning of rss feed items (title or description)
|
//Remove selected tags from the beginning of rss feed items (title or description)
|
||||||
|
|
||||||
if (this.config.removeStartTags === "title" || this.config.removeStartTags === "both") {
|
if (this.config.removeStartTags === "title" || this.config.removeStartTags === "both") {
|
||||||
|
for (let f = 0; f < this.config.startTags.length; f++) {
|
||||||
for (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]) {
|
||||||
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);
|
||||||
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.config.removeStartTags === "description" || this.config.removeStartTags === "both") {
|
||||||
|
|
||||||
if (this.isShowingDescription) {
|
if (this.isShowingDescription) {
|
||||||
for (f=0; f<this.config.startTags.length;f++) {
|
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]) {
|
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);
|
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)
|
//Remove selected tags from the end of rss feed items (title or description)
|
||||||
|
|
||||||
if (this.config.removeEndTags) {
|
if (this.config.removeEndTags) {
|
||||||
for (f=0; f<this.config.endTags.length;f++) {
|
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]) {
|
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);
|
this.newsItems[this.activeItem].title = this.newsItems[this.activeItem].title.slice(0, -this.config.endTags[f].length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isShowingDescription) {
|
if (this.isShowingDescription) {
|
||||||
for (f=0; f<this.config.endTags.length;f++) {
|
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]) {
|
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);
|
this.newsItems[this.activeItem].description = this.newsItems[this.activeItem].description.slice(0, -this.config.endTags[f].length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this.config.showFullArticle){
|
if (!this.config.showFullArticle) {
|
||||||
var title = document.createElement("div");
|
var title = document.createElement("div");
|
||||||
title.className = "newsfeed-title bright medium light" + (!this.config.wrapTitle ? " no-wrap" : "");
|
title.className = "newsfeed-title bright medium light" + (!this.config.wrapTitle ? " no-wrap" : "");
|
||||||
title.innerHTML = this.newsItems[this.activeItem].title;
|
title.innerHTML = this.newsItems[this.activeItem].title;
|
||||||
@ -177,7 +167,7 @@ Module.register("newsfeed",{
|
|||||||
var description = document.createElement("div");
|
var description = document.createElement("div");
|
||||||
description.className = "newsfeed-desc small light" + (!this.config.wrapDescription ? " no-wrap" : "");
|
description.className = "newsfeed-desc small light" + (!this.config.wrapDescription ? " no-wrap" : "");
|
||||||
var txtDesc = this.newsItems[this.activeItem].description;
|
var txtDesc = this.newsItems[this.activeItem].description;
|
||||||
description.innerHTML = (this.config.truncDescription ? (txtDesc.length > this.config.lengthDescription ? txtDesc.substring(0, this.config.lengthDescription) + "..." : txtDesc) : txtDesc);
|
description.innerHTML = this.config.truncDescription ? (txtDesc.length > this.config.lengthDescription ? txtDesc.substring(0, this.config.lengthDescription) + "..." : txtDesc) : txtDesc;
|
||||||
wrapper.appendChild(description);
|
wrapper.appendChild(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +189,6 @@ Module.register("newsfeed",{
|
|||||||
if (this.config.hideLoading) {
|
if (this.config.hideLoading) {
|
||||||
this.show();
|
this.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (this.config.hideLoading) {
|
if (this.config.hideLoading) {
|
||||||
this.hide();
|
this.hide();
|
||||||
@ -212,14 +201,14 @@ Module.register("newsfeed",{
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
},
|
},
|
||||||
|
|
||||||
getActiveItemURL: function() {
|
getActiveItemURL: function () {
|
||||||
return typeof this.newsItems[this.activeItem].url === "string" ? this.newsItems[this.activeItem].url : this.newsItems[this.activeItem].url.href;
|
return typeof this.newsItems[this.activeItem].url === "string" ? this.newsItems[this.activeItem].url : this.newsItems[this.activeItem].url.href;
|
||||||
},
|
},
|
||||||
|
|
||||||
/* registerFeeds()
|
/* registerFeeds()
|
||||||
* registers the feeds to be used by the backend.
|
* registers the feeds to be used by the backend.
|
||||||
*/
|
*/
|
||||||
registerFeeds: function() {
|
registerFeeds: function () {
|
||||||
for (var f in this.config.feeds) {
|
for (var f in this.config.feeds) {
|
||||||
var feed = this.config.feeds[f];
|
var feed = this.config.feeds[f];
|
||||||
this.sendSocketNotification("ADD_FEED", {
|
this.sendSocketNotification("ADD_FEED", {
|
||||||
@ -234,7 +223,7 @@ Module.register("newsfeed",{
|
|||||||
*
|
*
|
||||||
* attribute feeds object - An object with feeds returned by the node helper.
|
* attribute feeds object - An object with feeds returned by the node helper.
|
||||||
*/
|
*/
|
||||||
generateFeed: function(feeds) {
|
generateFeed: function (feeds) {
|
||||||
var newsItems = [];
|
var newsItems = [];
|
||||||
for (var feed in feeds) {
|
for (var feed in feeds) {
|
||||||
var feedItems = feeds[feed];
|
var feedItems = feeds[feed];
|
||||||
@ -242,24 +231,24 @@ Module.register("newsfeed",{
|
|||||||
for (var i in feedItems) {
|
for (var i in feedItems) {
|
||||||
var item = feedItems[i];
|
var item = feedItems[i];
|
||||||
item.sourceTitle = this.titleForFeed(feed);
|
item.sourceTitle = this.titleForFeed(feed);
|
||||||
if (!(this.config.ignoreOldItems && ((Date.now() - new Date(item.pubdate)) > this.config.ignoreOlderThan))) {
|
if (!(this.config.ignoreOldItems && Date.now() - new Date(item.pubdate) > this.config.ignoreOlderThan)) {
|
||||||
newsItems.push(item);
|
newsItems.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newsItems.sort(function(a,b) {
|
newsItems.sort(function (a, b) {
|
||||||
var dateA = new Date(a.pubdate);
|
var dateA = new Date(a.pubdate);
|
||||||
var dateB = new Date(b.pubdate);
|
var dateB = new Date(b.pubdate);
|
||||||
return dateB - dateA;
|
return dateB - dateA;
|
||||||
});
|
});
|
||||||
if(this.config.maxNewsItems > 0) {
|
if (this.config.maxNewsItems > 0) {
|
||||||
newsItems = newsItems.slice(0, this.config.maxNewsItems);
|
newsItems = newsItems.slice(0, this.config.maxNewsItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.config.prohibitedWords.length > 0) {
|
if (this.config.prohibitedWords.length > 0) {
|
||||||
newsItems = newsItems.filter(function(value){
|
newsItems = newsItems.filter(function (value) {
|
||||||
for (var i=0; i < this.config.prohibitedWords.length; i++) {
|
for (var i = 0; i < this.config.prohibitedWords.length; i++) {
|
||||||
if (value["title"].toLowerCase().indexOf(this.config.prohibitedWords[i].toLowerCase()) > -1) {
|
if (value["title"].toLowerCase().indexOf(this.config.prohibitedWords[i].toLowerCase()) > -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -270,8 +259,8 @@ Module.register("newsfeed",{
|
|||||||
|
|
||||||
// get updated news items and broadcast them
|
// get updated news items and broadcast them
|
||||||
var updatedItems = [];
|
var updatedItems = [];
|
||||||
newsItems.forEach(value => {
|
newsItems.forEach((value) => {
|
||||||
if (this.newsItems.findIndex(value1 => value1 === value) === -1) {
|
if (this.newsItems.findIndex((value1) => value1 === value) === -1) {
|
||||||
// Add item to updated items list
|
// Add item to updated items list
|
||||||
updatedItems.push(value);
|
updatedItems.push(value);
|
||||||
}
|
}
|
||||||
@ -279,7 +268,7 @@ Module.register("newsfeed",{
|
|||||||
|
|
||||||
// check if updated items exist, if so and if we should broadcast these updates, then lets do so
|
// check if updated items exist, if so and if we should broadcast these updates, then lets do so
|
||||||
if (this.config.broadcastNewsUpdates && updatedItems.length > 0) {
|
if (this.config.broadcastNewsUpdates && updatedItems.length > 0) {
|
||||||
this.sendNotification("NEWS_FEED_UPDATE", {items: updatedItems});
|
this.sendNotification("NEWS_FEED_UPDATE", { items: updatedItems });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.newsItems = newsItems;
|
this.newsItems = newsItems;
|
||||||
@ -292,7 +281,7 @@ Module.register("newsfeed",{
|
|||||||
*
|
*
|
||||||
* returns bool
|
* returns bool
|
||||||
*/
|
*/
|
||||||
subscribedToFeed: function(feedUrl) {
|
subscribedToFeed: function (feedUrl) {
|
||||||
for (var f in this.config.feeds) {
|
for (var f in this.config.feeds) {
|
||||||
var feed = this.config.feeds[f];
|
var feed = this.config.feeds[f];
|
||||||
if (feed.url === feedUrl) {
|
if (feed.url === feedUrl) {
|
||||||
@ -309,7 +298,7 @@ Module.register("newsfeed",{
|
|||||||
*
|
*
|
||||||
* returns string
|
* returns string
|
||||||
*/
|
*/
|
||||||
titleForFeed: function(feedUrl) {
|
titleForFeed: function (feedUrl) {
|
||||||
for (var f in this.config.feeds) {
|
for (var f in this.config.feeds) {
|
||||||
var feed = this.config.feeds[f];
|
var feed = this.config.feeds[f];
|
||||||
if (feed.url === feedUrl) {
|
if (feed.url === feedUrl) {
|
||||||
@ -322,23 +311,23 @@ Module.register("newsfeed",{
|
|||||||
/* scheduleUpdateInterval()
|
/* scheduleUpdateInterval()
|
||||||
* Schedule visual update.
|
* Schedule visual update.
|
||||||
*/
|
*/
|
||||||
scheduleUpdateInterval: function() {
|
scheduleUpdateInterval: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.updateDom(self.config.animationSpeed);
|
self.updateDom(self.config.animationSpeed);
|
||||||
|
|
||||||
// Broadcast NewsFeed if needed
|
// Broadcast NewsFeed if needed
|
||||||
if (self.config.broadcastNewsFeeds) {
|
if (self.config.broadcastNewsFeeds) {
|
||||||
self.sendNotification("NEWS_FEED", {items: self.newsItems});
|
self.sendNotification("NEWS_FEED", { items: self.newsItems });
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = setInterval(function() {
|
this.timer = setInterval(function () {
|
||||||
self.activeItem++;
|
self.activeItem++;
|
||||||
self.updateDom(self.config.animationSpeed);
|
self.updateDom(self.config.animationSpeed);
|
||||||
|
|
||||||
// Broadcast NewsFeed if needed
|
// Broadcast NewsFeed if needed
|
||||||
if (self.config.broadcastNewsFeeds) {
|
if (self.config.broadcastNewsFeeds) {
|
||||||
self.sendNotification("NEWS_FEED", {items: self.newsItems});
|
self.sendNotification("NEWS_FEED", { items: self.newsItems });
|
||||||
}
|
}
|
||||||
}, this.config.updateInterval);
|
}, this.config.updateInterval);
|
||||||
},
|
},
|
||||||
@ -350,25 +339,25 @@ Module.register("newsfeed",{
|
|||||||
*
|
*
|
||||||
* return string - Capitalized output string.
|
* return string - Capitalized output string.
|
||||||
*/
|
*/
|
||||||
capitalizeFirstLetter: function(string) {
|
capitalizeFirstLetter: function (string) {
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetDescrOrFullArticleAndTimer: function() {
|
resetDescrOrFullArticleAndTimer: function () {
|
||||||
this.isShowingDescription = this.config.showDescription;
|
this.isShowingDescription = this.config.showDescription;
|
||||||
this.config.showFullArticle = false;
|
this.config.showFullArticle = false;
|
||||||
this.scrollPosition = 0;
|
this.scrollPosition = 0;
|
||||||
// reset bottom bar alignment
|
// reset bottom bar alignment
|
||||||
document.getElementsByClassName("region bottom bar")[0].style.bottom = "0";
|
document.getElementsByClassName("region bottom bar")[0].style.bottom = "0";
|
||||||
document.getElementsByClassName("region bottom bar")[0].style.top = "inherit";
|
document.getElementsByClassName("region bottom bar")[0].style.top = "inherit";
|
||||||
if(!timer){
|
if (!this.timer) {
|
||||||
this.scheduleUpdateInterval();
|
this.scheduleUpdateInterval();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
notificationReceived: function(notification, payload, sender) {
|
notificationReceived: function (notification, payload, sender) {
|
||||||
if(notification === "ARTICLE_NEXT"){
|
var before = this.activeItem;
|
||||||
var before = this.activeItem;
|
if (notification === "ARTICLE_NEXT") {
|
||||||
this.activeItem++;
|
this.activeItem++;
|
||||||
if (this.activeItem >= this.newsItems.length) {
|
if (this.activeItem >= this.newsItems.length) {
|
||||||
this.activeItem = 0;
|
this.activeItem = 0;
|
||||||
@ -376,8 +365,7 @@ Module.register("newsfeed",{
|
|||||||
this.resetDescrOrFullArticleAndTimer();
|
this.resetDescrOrFullArticleAndTimer();
|
||||||
Log.info(this.name + " - going from article #" + before + " to #" + this.activeItem + " (of " + this.newsItems.length + ")");
|
Log.info(this.name + " - going from article #" + before + " to #" + this.activeItem + " (of " + this.newsItems.length + ")");
|
||||||
this.updateDom(100);
|
this.updateDom(100);
|
||||||
} else if(notification === "ARTICLE_PREVIOUS"){
|
} else if (notification === "ARTICLE_PREVIOUS") {
|
||||||
var before = this.activeItem;
|
|
||||||
this.activeItem--;
|
this.activeItem--;
|
||||||
if (this.activeItem < 0) {
|
if (this.activeItem < 0) {
|
||||||
this.activeItem = this.newsItems.length - 1;
|
this.activeItem = this.newsItems.length - 1;
|
||||||
@ -387,58 +375,56 @@ Module.register("newsfeed",{
|
|||||||
this.updateDom(100);
|
this.updateDom(100);
|
||||||
}
|
}
|
||||||
// if "more details" is received the first time: show article summary, on second time show full article
|
// if "more details" is received the first time: show article summary, on second time show full article
|
||||||
else if(notification === "ARTICLE_MORE_DETAILS"){
|
else if (notification === "ARTICLE_MORE_DETAILS") {
|
||||||
// full article is already showing, so scrolling down
|
// full article is already showing, so scrolling down
|
||||||
if(this.config.showFullArticle === true){
|
if (this.config.showFullArticle === true) {
|
||||||
this.scrollPosition += this.config.scrollLength;
|
this.scrollPosition += this.config.scrollLength;
|
||||||
window.scrollTo(0, this.scrollPosition);
|
window.scrollTo(0, this.scrollPosition);
|
||||||
Log.info(this.name + " - scrolling down");
|
Log.info(this.name + " - scrolling down");
|
||||||
Log.info(this.name + " - ARTICLE_MORE_DETAILS, scroll position: " + this.config.scrollLength);
|
Log.info(this.name + " - ARTICLE_MORE_DETAILS, scroll position: " + this.config.scrollLength);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.showFullArticle();
|
this.showFullArticle();
|
||||||
}
|
}
|
||||||
} else if(notification === "ARTICLE_SCROLL_UP"){
|
} else if (notification === "ARTICLE_SCROLL_UP") {
|
||||||
if(this.config.showFullArticle === true){
|
if (this.config.showFullArticle === true) {
|
||||||
this.scrollPosition -= this.config.scrollLength;
|
this.scrollPosition -= this.config.scrollLength;
|
||||||
window.scrollTo(0, this.scrollPosition);
|
window.scrollTo(0, this.scrollPosition);
|
||||||
Log.info(this.name + " - scrolling up");
|
Log.info(this.name + " - scrolling up");
|
||||||
Log.info(this.name + " - ARTICLE_SCROLL_UP, scroll position: " + this.config.scrollLength);
|
Log.info(this.name + " - ARTICLE_SCROLL_UP, scroll position: " + this.config.scrollLength);
|
||||||
}
|
}
|
||||||
} else if(notification === "ARTICLE_LESS_DETAILS"){
|
} else if (notification === "ARTICLE_LESS_DETAILS") {
|
||||||
this.resetDescrOrFullArticleAndTimer();
|
this.resetDescrOrFullArticleAndTimer();
|
||||||
Log.info(this.name + " - showing only article titles again");
|
Log.info(this.name + " - showing only article titles again");
|
||||||
this.updateDom(100);
|
this.updateDom(100);
|
||||||
} else if (notification === "ARTICLE_TOGGLE_FULL"){
|
} else if (notification === "ARTICLE_TOGGLE_FULL") {
|
||||||
if (this.config.showFullArticle){
|
if (this.config.showFullArticle) {
|
||||||
this.activeItem++;
|
this.activeItem++;
|
||||||
this.resetDescrOrFullArticleAndTimer();
|
this.resetDescrOrFullArticleAndTimer();
|
||||||
} else {
|
} else {
|
||||||
this.showFullArticle();
|
this.showFullArticle();
|
||||||
}
|
}
|
||||||
} else if (notification === "ARTICLE_INFO_REQUEST"){
|
} else if (notification === "ARTICLE_INFO_REQUEST") {
|
||||||
this.sendNotification("ARTICLE_INFO_RESPONSE", {
|
this.sendNotification("ARTICLE_INFO_RESPONSE", {
|
||||||
title: this.newsItems[this.activeItem].title,
|
title: this.newsItems[this.activeItem].title,
|
||||||
source: this.newsItems[this.activeItem].sourceTitle,
|
source: this.newsItems[this.activeItem].sourceTitle,
|
||||||
date: this.newsItems[this.activeItem].pubdate,
|
date: this.newsItems[this.activeItem].pubdate,
|
||||||
desc: this.newsItems[this.activeItem].description,
|
desc: this.newsItems[this.activeItem].description,
|
||||||
url: this.getActiveItemURL()
|
url: this.getActiveItemURL()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showFullArticle: function() {
|
showFullArticle: function () {
|
||||||
this.isShowingDescription = !this.isShowingDescription;
|
this.isShowingDescription = !this.isShowingDescription;
|
||||||
this.config.showFullArticle = !this.isShowingDescription;
|
this.config.showFullArticle = !this.isShowingDescription;
|
||||||
// make bottom bar align to top to allow scrolling
|
// make bottom bar align to top to allow scrolling
|
||||||
if(this.config.showFullArticle === true){
|
if (this.config.showFullArticle === true) {
|
||||||
document.getElementsByClassName("region bottom bar")[0].style.bottom = "inherit";
|
document.getElementsByClassName("region bottom bar")[0].style.bottom = "inherit";
|
||||||
document.getElementsByClassName("region bottom bar")[0].style.top = "-90px";
|
document.getElementsByClassName("region bottom bar")[0].style.top = "-90px";
|
||||||
}
|
}
|
||||||
clearInterval(timer);
|
clearInterval(this.timer);
|
||||||
timer = null;
|
this.timer = null;
|
||||||
Log.info(this.name + " - showing " + this.isShowingDescription ? "article description" : "full article");
|
Log.info(this.name + " - showing " + this.isShowingDescription ? "article description" : "full article");
|
||||||
this.updateDom(100);
|
this.updateDom(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Node Helper: Newsfeed
|
* Node Helper: Newsfeed
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -11,13 +11,13 @@ var Fetcher = require("./fetcher.js");
|
|||||||
|
|
||||||
module.exports = NodeHelper.create({
|
module.exports = NodeHelper.create({
|
||||||
// Subclass start method.
|
// Subclass start method.
|
||||||
start: function() {
|
start: function () {
|
||||||
console.log("Starting module: " + this.name);
|
console.log("Starting module: " + this.name);
|
||||||
this.fetchers = [];
|
this.fetchers = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
// Subclass socketNotificationReceived received.
|
// Subclass socketNotificationReceived received.
|
||||||
socketNotificationReceived: function(notification, payload) {
|
socketNotificationReceived: function (notification, payload) {
|
||||||
if (notification === "ADD_FEED") {
|
if (notification === "ADD_FEED") {
|
||||||
this.createFetcher(payload.feed, payload.config);
|
this.createFetcher(payload.feed, payload.config);
|
||||||
return;
|
return;
|
||||||
@ -31,7 +31,7 @@ module.exports = NodeHelper.create({
|
|||||||
* attribute feed object - A feed object.
|
* attribute feed object - A feed object.
|
||||||
* attribute config object - A configuration object containing reload interval in milliseconds.
|
* attribute config object - A configuration object containing reload interval in milliseconds.
|
||||||
*/
|
*/
|
||||||
createFetcher: function(feed, config) {
|
createFetcher: function (feed, config) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var url = feed.url || "";
|
var url = feed.url || "";
|
||||||
@ -48,11 +48,11 @@ module.exports = NodeHelper.create({
|
|||||||
console.log("Create new news fetcher for url: " + url + " - Interval: " + reloadInterval);
|
console.log("Create new news fetcher for url: " + url + " - Interval: " + reloadInterval);
|
||||||
fetcher = new Fetcher(url, reloadInterval, encoding, config.logFeedWarnings);
|
fetcher = new Fetcher(url, reloadInterval, encoding, config.logFeedWarnings);
|
||||||
|
|
||||||
fetcher.onReceive(function(fetcher) {
|
fetcher.onReceive(function (fetcher) {
|
||||||
self.broadcastFeeds();
|
self.broadcastFeeds();
|
||||||
});
|
});
|
||||||
|
|
||||||
fetcher.onError(function(fetcher, error) {
|
fetcher.onError(function (fetcher, error) {
|
||||||
self.sendSocketNotification("FETCH_ERROR", {
|
self.sendSocketNotification("FETCH_ERROR", {
|
||||||
url: fetcher.url(),
|
url: fetcher.url(),
|
||||||
error: error
|
error: error
|
||||||
@ -74,7 +74,7 @@ module.exports = NodeHelper.create({
|
|||||||
* Creates an object with all feed items of the different registered feeds,
|
* Creates an object with all feed items of the different registered feeds,
|
||||||
* and broadcasts these using sendSocketNotification.
|
* and broadcasts these using sendSocketNotification.
|
||||||
*/
|
*/
|
||||||
broadcastFeeds: function() {
|
broadcastFeeds: function () {
|
||||||
var feeds = {};
|
var feeds = {};
|
||||||
for (var f in this.fetchers) {
|
for (var f in this.fetchers) {
|
||||||
feeds[f] = this.fetchers[f].items();
|
feeds[f] = this.fetchers[f].items();
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"configuration_changed": "Die Konfigurationsoptionen für das Newsfeed-Modul haben sich geändert. \nBitte überprüfen Sie die Dokumentation."
|
"configuration_changed": "Die Konfigurationsoptionen für das Newsfeed-Modul haben sich geändert. \nBitte überprüfen Sie die Dokumentation."
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"configuration_changed": "The configuration options for the newsfeed module have changed.\nPlease check the documentation."
|
"configuration_changed": "The configuration options for the newsfeed module have changed.\nPlease check the documentation."
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"configuration_changed": "Las opciones de configuración para el módulo de suministro de noticias han cambiado. \nVerifique la documentación."
|
"configuration_changed": "Las opciones de configuración para el módulo de suministro de noticias han cambiado. \nVerifique la documentación."
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"configuration_changed": "Les options de configuration du module newsfeed ont changé. \nVeuillez consulter la documentation."
|
"configuration_changed": "Les options de configuration du module newsfeed ont changé. \nVeuillez consulter la documentation."
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
# Module: Update Notification
|
# Module: Update Notification
|
||||||
|
|
||||||
The `updatenotification` module is one of the default modules of the MagicMirror.
|
The `updatenotification` module is one of the default modules of the MagicMirror.
|
||||||
This will display a message whenever a new version of the MagicMirror application is available.
|
This will display a message whenever a new version of the MagicMirror application is available.
|
||||||
|
|
||||||
|
@ -6,25 +6,22 @@ var defaultModules = require(__dirname + "/../defaultmodules.js");
|
|||||||
var NodeHelper = require("node_helper");
|
var NodeHelper = require("node_helper");
|
||||||
|
|
||||||
module.exports = NodeHelper.create({
|
module.exports = NodeHelper.create({
|
||||||
|
|
||||||
config: {},
|
config: {},
|
||||||
|
|
||||||
updateTimer: null,
|
updateTimer: null,
|
||||||
updateProcessStarted: false,
|
updateProcessStarted: false,
|
||||||
|
|
||||||
start: function () {
|
start: function () {},
|
||||||
},
|
|
||||||
|
|
||||||
configureModules: function(modules) {
|
|
||||||
|
|
||||||
|
configureModules: function (modules) {
|
||||||
// Push MagicMirror itself , biggest chance it'll show up last in UI and isn't overwritten
|
// Push MagicMirror itself , biggest chance it'll show up last in UI and isn't overwritten
|
||||||
// others will be added in front
|
// others will be added in front
|
||||||
// this method returns promises so we can't wait for every one to resolve before continuing
|
// this method returns promises so we can't wait for every one to resolve before continuing
|
||||||
simpleGits.push({"module": "default", "git": SimpleGit(path.normalize(__dirname + "/../../../"))});
|
simpleGits.push({ module: "default", git: SimpleGit(path.normalize(__dirname + "/../../../")) });
|
||||||
|
|
||||||
var promises = [];
|
var promises = [];
|
||||||
|
|
||||||
for (moduleName in modules) {
|
for (var moduleName in modules) {
|
||||||
if (!this.ignoreUpdateChecking(moduleName)) {
|
if (!this.ignoreUpdateChecking(moduleName)) {
|
||||||
// Default modules are included in the main MagicMirror repo
|
// Default modules are included in the main MagicMirror repo
|
||||||
var moduleFolder = path.normalize(__dirname + "/../../" + moduleName);
|
var moduleFolder = path.normalize(__dirname + "/../../" + moduleName);
|
||||||
@ -33,7 +30,7 @@ module.exports = NodeHelper.create({
|
|||||||
//console.log("checking git for module="+moduleName)
|
//console.log("checking git for module="+moduleName)
|
||||||
let stat = fs.statSync(path.join(moduleFolder, ".git"));
|
let stat = fs.statSync(path.join(moduleFolder, ".git"));
|
||||||
promises.push(this.resolveRemote(moduleName, moduleFolder));
|
promises.push(this.resolveRemote(moduleName, moduleFolder));
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
// Error when directory .git doesn't exist
|
// Error when directory .git doesn't exist
|
||||||
// This module is not managed with git, skip
|
// This module is not managed with git, skip
|
||||||
continue;
|
continue;
|
||||||
@ -47,7 +44,7 @@ module.exports = NodeHelper.create({
|
|||||||
socketNotificationReceived: function (notification, payload) {
|
socketNotificationReceived: function (notification, payload) {
|
||||||
if (notification === "CONFIG") {
|
if (notification === "CONFIG") {
|
||||||
this.config = payload;
|
this.config = payload;
|
||||||
} else if(notification === "MODULES") {
|
} else if (notification === "MODULES") {
|
||||||
// if this is the 1st time thru the update check process
|
// if this is the 1st time thru the update check process
|
||||||
if (!this.updateProcessStarted) {
|
if (!this.updateProcessStarted) {
|
||||||
this.updateProcessStarted = true;
|
this.updateProcessStarted = true;
|
||||||
@ -56,7 +53,7 @@ module.exports = NodeHelper.create({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
resolveRemote: function(moduleName, moduleFolder) {
|
resolveRemote: function (moduleName, moduleFolder) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var git = SimpleGit(moduleFolder);
|
var git = SimpleGit(moduleFolder);
|
||||||
git.getRemotes(true, (err, remotes) => {
|
git.getRemotes(true, (err, remotes) => {
|
||||||
@ -65,19 +62,19 @@ module.exports = NodeHelper.create({
|
|||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
// Folder has .git and has at least one git remote, watch this folder
|
// Folder has .git and has at least one git remote, watch this folder
|
||||||
simpleGits.unshift({"module": moduleName, "git": git});
|
simpleGits.unshift({ module: moduleName, git: git });
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
performFetch: function() {
|
performFetch: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
simpleGits.forEach((sg) => {
|
simpleGits.forEach((sg) => {
|
||||||
sg.git.fetch().status((err, data) => {
|
sg.git.fetch().status((err, data) => {
|
||||||
data.module = sg.module;
|
data.module = sg.module;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
sg.git.log({"-1": null}, (err, data2) => {
|
sg.git.log({ "-1": null }, (err, data2) => {
|
||||||
if (!err && data2.latest && "hash" in data2.latest) {
|
if (!err && data2.latest && "hash" in data2.latest) {
|
||||||
data.hash = data2.latest.hash;
|
data.hash = data2.latest.hash;
|
||||||
self.sendSocketNotification("STATUS", data);
|
self.sendSocketNotification("STATUS", data);
|
||||||
@ -90,19 +87,19 @@ module.exports = NodeHelper.create({
|
|||||||
this.scheduleNextFetch(this.config.updateInterval);
|
this.scheduleNextFetch(this.config.updateInterval);
|
||||||
},
|
},
|
||||||
|
|
||||||
scheduleNextFetch: function(delay) {
|
scheduleNextFetch: function (delay) {
|
||||||
if (delay < 60 * 1000) {
|
if (delay < 60 * 1000) {
|
||||||
delay = 60 * 1000;
|
delay = 60 * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
clearTimeout(this.updateTimer);
|
clearTimeout(this.updateTimer);
|
||||||
this.updateTimer = setTimeout(function() {
|
this.updateTimer = setTimeout(function () {
|
||||||
self.performFetch();
|
self.performFetch();
|
||||||
}, delay);
|
}, delay);
|
||||||
},
|
},
|
||||||
|
|
||||||
ignoreUpdateChecking: function(moduleName) {
|
ignoreUpdateChecking: function (moduleName) {
|
||||||
// Should not check for updates for default modules
|
// Should not check for updates for default modules
|
||||||
if (defaultModules.indexOf(moduleName) >= 0) {
|
if (defaultModules.indexOf(moduleName) >= 0) {
|
||||||
return true;
|
return true;
|
||||||
@ -116,5 +113,4 @@ module.exports = NodeHelper.create({
|
|||||||
// The rest of the modules that passes should check for updates
|
// The rest of the modules that passes should check for updates
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
|
/* Magic Mirror
|
||||||
|
* Module: UpdateNotification
|
||||||
|
*
|
||||||
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
|
* MIT Licensed.
|
||||||
|
*/
|
||||||
Module.register("updatenotification", {
|
Module.register("updatenotification", {
|
||||||
|
|
||||||
defaults: {
|
defaults: {
|
||||||
updateInterval: 10 * 60 * 1000, // every 10 minutes
|
updateInterval: 10 * 60 * 1000, // every 10 minutes
|
||||||
refreshInterval: 24 * 60 * 60 * 1000, // one day
|
refreshInterval: 24 * 60 * 60 * 1000, // one day
|
||||||
@ -12,7 +17,10 @@ Module.register("updatenotification", {
|
|||||||
start: function () {
|
start: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
Log.log("Start updatenotification");
|
Log.log("Start updatenotification");
|
||||||
setInterval( () => { self.moduleList = {};self.updateDom(2); } , self.config.refreshInterval);
|
setInterval(() => {
|
||||||
|
self.moduleList = {};
|
||||||
|
self.updateDom(2);
|
||||||
|
}, self.config.refreshInterval);
|
||||||
},
|
},
|
||||||
|
|
||||||
notificationReceived: function (notification, payload, sender) {
|
notificationReceived: function (notification, payload, sender) {
|
||||||
@ -33,16 +41,15 @@ Module.register("updatenotification", {
|
|||||||
var self = this;
|
var self = this;
|
||||||
if (payload && payload.behind > 0) {
|
if (payload && payload.behind > 0) {
|
||||||
// if we haven't seen info for this module
|
// if we haven't seen info for this module
|
||||||
if(this.moduleList[payload.module] == undefined){
|
if (this.moduleList[payload.module] === undefined) {
|
||||||
// save it
|
// save it
|
||||||
this.moduleList[payload.module]=payload;
|
this.moduleList[payload.module] = payload;
|
||||||
self.updateDom(2);
|
self.updateDom(2);
|
||||||
}
|
}
|
||||||
//self.show(1000, { lockString: self.identifier });
|
//self.show(1000, { lockString: self.identifier });
|
||||||
|
} else if (payload && payload.behind === 0) {
|
||||||
} else if (payload && payload.behind == 0){
|
|
||||||
// if the module WAS in the list, but shouldn't be
|
// if the module WAS in the list, but shouldn't be
|
||||||
if(this.moduleList[payload.module] != undefined){
|
if (this.moduleList[payload.module] !== undefined) {
|
||||||
// remove it
|
// remove it
|
||||||
delete this.moduleList[payload.module];
|
delete this.moduleList[payload.module];
|
||||||
self.updateDom(2);
|
self.updateDom(2);
|
||||||
@ -50,24 +57,19 @@ Module.register("updatenotification", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
diffLink: function(module, text) {
|
diffLink: function (module, text) {
|
||||||
var localRef = module.hash;
|
var localRef = module.hash;
|
||||||
var remoteRef = module.tracking.replace(/.*\//, "");
|
var remoteRef = module.tracking.replace(/.*\//, "");
|
||||||
return "<a href=\"https://github.com/MichMich/MagicMirror/compare/"+localRef+"..."+remoteRef+"\" "+
|
return '<a href="https://github.com/MichMich/MagicMirror/compare/' + localRef + "..." + remoteRef + '" ' + 'class="xsmall dimmed" ' + 'style="text-decoration: none;" ' + 'target="_blank" >' + text + "</a>";
|
||||||
"class=\"xsmall dimmed\" "+
|
|
||||||
"style=\"text-decoration: none;\" "+
|
|
||||||
"target=\"_blank\" >" +
|
|
||||||
text +
|
|
||||||
"</a>";
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Override dom generator.
|
// Override dom generator.
|
||||||
getDom: function () {
|
getDom: function () {
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement("div");
|
||||||
if(this.suspended==false){
|
if (this.suspended === false) {
|
||||||
// process the hash of module info found
|
// process the hash of module info found
|
||||||
for(key of Object.keys(this.moduleList)){
|
for (var key of Object.keys(this.moduleList)) {
|
||||||
let m= this.moduleList[key];
|
let m = this.moduleList[key];
|
||||||
|
|
||||||
var message = document.createElement("div");
|
var message = document.createElement("div");
|
||||||
message.className = "small bright";
|
message.className = "small bright";
|
||||||
@ -77,7 +79,7 @@ Module.register("updatenotification", {
|
|||||||
icon.innerHTML = " ";
|
icon.innerHTML = " ";
|
||||||
message.appendChild(icon);
|
message.appendChild(icon);
|
||||||
|
|
||||||
var updateInfoKeyName = m.behind == 1 ? "UPDATE_INFO_SINGLE" : "UPDATE_INFO_MULTIPLE";
|
var updateInfoKeyName = m.behind === 1 ? "UPDATE_INFO_SINGLE" : "UPDATE_INFO_MULTIPLE";
|
||||||
|
|
||||||
var subtextHtml = this.translate(updateInfoKeyName, {
|
var subtextHtml = this.translate(updateInfoKeyName, {
|
||||||
COMMIT_COUNT: m.behind,
|
COMMIT_COUNT: m.behind,
|
||||||
@ -85,9 +87,9 @@ Module.register("updatenotification", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var text = document.createElement("span");
|
var text = document.createElement("span");
|
||||||
if (m.module == "default") {
|
if (m.module === "default") {
|
||||||
text.innerHTML = this.translate("UPDATE_NOTIFICATION");
|
text.innerHTML = this.translate("UPDATE_NOTIFICATION");
|
||||||
subtextHtml = this.diffLink(m,subtextHtml);
|
subtextHtml = this.diffLink(m, subtextHtml);
|
||||||
} else {
|
} else {
|
||||||
text.innerHTML = this.translate("UPDATE_NOTIFICATION_MODULE", {
|
text.innerHTML = this.translate("UPDATE_NOTIFICATION_MODULE", {
|
||||||
MODULE_NAME: m.module
|
MODULE_NAME: m.module
|
||||||
@ -106,11 +108,11 @@ Module.register("updatenotification", {
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
},
|
},
|
||||||
|
|
||||||
suspend: function() {
|
suspend: function () {
|
||||||
this.suspended=true;
|
this.suspended = true;
|
||||||
},
|
},
|
||||||
resume: function() {
|
resume: function () {
|
||||||
this.suspended=false;
|
this.suspended = false;
|
||||||
this.updateDom(2);
|
this.updateDom(2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Weather Module
|
# Weather Module
|
||||||
|
|
||||||
This module is aimed to be the replacement for the current `currentweather` and `weatherforcast` modules. The module will be configurable to be used as a current weather view, or to show the forecast. This way the module can be used twice to fullfil both purposes.
|
This module aims to be the replacement for the current `currentweather` and `weatherforcast` modules. The module will be configurable to be used as a current weather view, or to show the forecast. This way the module can be used twice to fullfil both purposes.
|
||||||
|
|
||||||
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/weather.html).
|
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/weather.html).
|
||||||
|
@ -13,17 +13,17 @@ Table of Contents:
|
|||||||
|
|
||||||
## The weather provider file: yourprovider.js
|
## The weather provider file: yourprovider.js
|
||||||
|
|
||||||
This is the script in which the weather provider will be defined. In it's most simple form, the weather provider must implement the following:
|
This is the script in which the weather provider will be defined. In its most simple form, the weather provider must implement the following:
|
||||||
|
|
||||||
````javascript
|
```javascript
|
||||||
WeatherProvider.register("yourprovider", {
|
WeatherProvider.register("yourprovider", {
|
||||||
providerName: "YourProvider",
|
providerName: "YourProvider",
|
||||||
|
|
||||||
fetchCurrentWeather() {},
|
fetchCurrentWeather() {},
|
||||||
|
|
||||||
fetchWeatherForecast() {}
|
fetchWeatherForecast() {}
|
||||||
});
|
});
|
||||||
````
|
```
|
||||||
|
|
||||||
### Weather provider methods to implement
|
### Weather provider methods to implement
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ It will then automatically refresh the module DOM with the new data.
|
|||||||
|
|
||||||
#### `fetchWeatherForecast()`
|
#### `fetchWeatherForecast()`
|
||||||
|
|
||||||
This method is called when the weather module tries to fetch the weather 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.
|
||||||
The implementation can make use of the already implemented function `this.fetchData(url, method, data);`, which is returning a promise.
|
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.setCurrentWeather(forecast);`.
|
||||||
It will then automatically refresh the module DOM with the new data.
|
It will then automatically refresh the module DOM with the new data.
|
||||||
@ -89,24 +89,24 @@ A convenience function to make requests. It returns a promise.
|
|||||||
|
|
||||||
### WeatherObject
|
### WeatherObject
|
||||||
|
|
||||||
| Property | Type | Value/Unit |
|
| Property | Type | Value/Unit |
|
||||||
| --- | --- | --- |
|
| -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
|
||||||
| units | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
|
| units | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
|
||||||
| tempUnits | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
|
| tempUnits | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
|
||||||
| windUnits | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
|
| windUnits | `string` | Gets initialized with the constructor. <br> Possible values: `metric`, `imperial` |
|
||||||
| date | `object` | [Moment.js](https://momentjs.com/) object of the time/date. |
|
| date | `object` | [Moment.js](https://momentjs.com/) object of the time/date. |
|
||||||
| windSpeed |`number` | Metric: `meter/second` <br> Imperial: `miles/hour` |
|
| windSpeed | `number` | Metric: `meter/second` <br> Imperial: `miles/hour` |
|
||||||
| windDirection |`number` | Direction of the wind in degrees. |
|
| windDirection | `number` | Direction of the wind in degrees. |
|
||||||
| sunrise |`object` | [Moment.js](https://momentjs.com/) object of sunrise. |
|
| sunrise | `object` | [Moment.js](https://momentjs.com/) object of sunrise. |
|
||||||
| sunset |`object` | [Moment.js](https://momentjs.com/) object of sunset. |
|
| sunset | `object` | [Moment.js](https://momentjs.com/) object of sunset. |
|
||||||
| temperature | `number` | Current temperature |
|
| temperature | `number` | Current temperature |
|
||||||
| minTemperature | `number` | Lowest temperature of the day. |
|
| minTemperature | `number` | Lowest temperature of the day. |
|
||||||
| maxTemperature | `number` | Highest temperature of the day. |
|
| maxTemperature | `number` | Highest temperature of the day. |
|
||||||
| weatherType | `string` | Icon name of the weather type. <br> Possible values: [WeatherIcons](https://www.npmjs.com/package/weathericons) |
|
| weatherType | `string` | Icon name of the weather type. <br> Possible values: [WeatherIcons](https://www.npmjs.com/package/weathericons) |
|
||||||
| humidity | `number` | Percentage of humidity |
|
| humidity | `number` | Percentage of humidity |
|
||||||
| rain | `number` | Metric: `millimeters` <br> Imperial: `inches` |
|
| rain | `number` | Metric: `millimeters` <br> Imperial: `inches` |
|
||||||
| snow | `number` | Metric: `millimeters` <br> Imperial: `inches` |
|
| snow | `number` | Metric: `millimeters` <br> Imperial: `inches` |
|
||||||
| precipitation | `number` | Metric: `millimeters` <br> Imperial: `inches` <br> UK Met Office provider: `percent` |
|
| precipitation | `number` | Metric: `millimeters` <br> Imperial: `inches` <br> UK Met Office provider: `percent` |
|
||||||
|
|
||||||
#### Current weather
|
#### Current weather
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* global WeatherProvider, WeatherDay */
|
/* global WeatherProvider, WeatherObject */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: Weather
|
* Module: Weather
|
||||||
@ -16,40 +16,42 @@ WeatherProvider.register("darksky", {
|
|||||||
providerName: "Dark Sky",
|
providerName: "Dark Sky",
|
||||||
|
|
||||||
units: {
|
units: {
|
||||||
imperial: 'us',
|
imperial: "us",
|
||||||
metric: 'si'
|
metric: "si"
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
if(!data || !data.currently || typeof data.currently.temperature === "undefined") {
|
if (!data || !data.currently || typeof data.currently.temperature === "undefined") {
|
||||||
// No usable data?
|
// No usable data?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentWeather = this.generateWeatherDayFromCurrentWeather(data);
|
const currentWeather = this.generateWeatherDayFromCurrentWeather(data);
|
||||||
this.setCurrentWeather(currentWeather);
|
this.setCurrentWeather(currentWeather);
|
||||||
}).catch(function(request) {
|
})
|
||||||
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
})
|
})
|
||||||
.finally(() => this.updateAvailable())
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchWeatherForecast() {
|
fetchWeatherForecast() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
if(!data || !data.daily || !data.daily.data.length) {
|
if (!data || !data.daily || !data.daily.data.length) {
|
||||||
// No usable data?
|
// No usable data?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const forecast = this.generateWeatherObjectsFromForecast(data.daily.data);
|
const forecast = this.generateWeatherObjectsFromForecast(data.daily.data);
|
||||||
this.setWeatherForecast(forecast);
|
this.setWeatherForecast(forecast);
|
||||||
}).catch(function(request) {
|
})
|
||||||
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
})
|
})
|
||||||
.finally(() => this.updateAvailable())
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
// Create a URL from the config and base URL.
|
// Create a URL from the config and base URL.
|
||||||
@ -109,12 +111,12 @@ WeatherProvider.register("darksky", {
|
|||||||
const weatherTypes = {
|
const weatherTypes = {
|
||||||
"clear-day": "day-sunny",
|
"clear-day": "day-sunny",
|
||||||
"clear-night": "night-clear",
|
"clear-night": "night-clear",
|
||||||
"rain": "rain",
|
rain: "rain",
|
||||||
"snow": "snow",
|
snow: "snow",
|
||||||
"sleet": "snow",
|
sleet: "snow",
|
||||||
"wind": "wind",
|
wind: "wind",
|
||||||
"fog": "fog",
|
fog: "fog",
|
||||||
"cloudy": "cloudy",
|
cloudy: "cloudy",
|
||||||
"partly-cloudy-day": "day-cloudy",
|
"partly-cloudy-day": "day-cloudy",
|
||||||
"partly-cloudy-night": "night-cloudy"
|
"partly-cloudy-night": "night-cloudy"
|
||||||
};
|
};
|
||||||
|
@ -3,14 +3,12 @@
|
|||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: Weather
|
* Module: Weather
|
||||||
*
|
*
|
||||||
* By Michael Teeuw http://michaelteeuw.nl
|
* By Michael Teeuw https://michaelteeuw.nl
|
||||||
* MIT Licensed.
|
* MIT Licensed.
|
||||||
*
|
*
|
||||||
* This class is the blueprint for a weather provider.
|
* This class is the blueprint for a weather provider.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
WeatherProvider.register("openweathermap", {
|
WeatherProvider.register("openweathermap", {
|
||||||
|
|
||||||
// Set the name of the provider.
|
// Set the name of the provider.
|
||||||
// This isn't strictly necessary, since it will fallback to the provider identifier
|
// This isn't strictly necessary, since it will fallback to the provider identifier
|
||||||
// But for debugging (and future alerts) it would be nice to have the real name.
|
// But for debugging (and future alerts) it would be nice to have the real name.
|
||||||
@ -19,7 +17,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
// Overwrite the fetchCurrentWeather method.
|
// Overwrite the fetchCurrentWeather method.
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
if (!data || !data.main || typeof data.main.temp === "undefined") {
|
if (!data || !data.main || typeof data.main.temp === "undefined") {
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
// Maybe this needs a better check?
|
// Maybe this needs a better check?
|
||||||
@ -31,16 +29,16 @@ WeatherProvider.register("openweathermap", {
|
|||||||
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
|
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
|
||||||
this.setCurrentWeather(currentWeather);
|
this.setCurrentWeather(currentWeather);
|
||||||
})
|
})
|
||||||
.catch(function(request) {
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
})
|
})
|
||||||
.finally(() => this.updateAvailable())
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
// Overwrite the fetchCurrentWeather method.
|
// Overwrite the fetchCurrentWeather method.
|
||||||
fetchWeatherForecast() {
|
fetchWeatherForecast() {
|
||||||
this.fetchData(this.getUrl())
|
this.fetchData(this.getUrl())
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
if (!data || !data.list || !data.list.length) {
|
if (!data || !data.list || !data.list.length) {
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
// Maybe this needs a better check?
|
// Maybe this needs a better check?
|
||||||
@ -52,10 +50,10 @@ WeatherProvider.register("openweathermap", {
|
|||||||
const forecast = this.generateWeatherObjectsFromForecast(data.list);
|
const forecast = this.generateWeatherObjectsFromForecast(data.list);
|
||||||
this.setWeatherForecast(forecast);
|
this.setWeatherForecast(forecast);
|
||||||
})
|
})
|
||||||
.catch(function(request) {
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
})
|
})
|
||||||
.finally(() => this.updateAvailable())
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
/** OpenWeatherMap Specific Methods - These are not part of the default provider methods */
|
/** OpenWeatherMap Specific Methods - These are not part of the default provider methods */
|
||||||
@ -87,7 +85,6 @@ WeatherProvider.register("openweathermap", {
|
|||||||
* Generate WeatherObjects based on forecast information
|
* Generate WeatherObjects based on forecast information
|
||||||
*/
|
*/
|
||||||
generateWeatherObjectsFromForecast(forecasts) {
|
generateWeatherObjectsFromForecast(forecasts) {
|
||||||
|
|
||||||
if (this.config.weatherEndpoint === "/forecast") {
|
if (this.config.weatherEndpoint === "/forecast") {
|
||||||
return this.fetchForecastHourly(forecasts);
|
return this.fetchForecastHourly(forecasts);
|
||||||
} else if (this.config.weatherEndpoint === "/forecast/daily") {
|
} else if (this.config.weatherEndpoint === "/forecast/daily") {
|
||||||
@ -114,7 +111,6 @@ WeatherProvider.register("openweathermap", {
|
|||||||
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||||
|
|
||||||
for (const forecast of forecasts) {
|
for (const forecast of forecasts) {
|
||||||
|
|
||||||
if (date !== moment(forecast.dt, "X").format("YYYY-MM-DD")) {
|
if (date !== moment(forecast.dt, "X").format("YYYY-MM-DD")) {
|
||||||
// calculate minimum/maximum temperature, specify rain amount
|
// calculate minimum/maximum temperature, specify rain amount
|
||||||
weather.minTemperature = Math.min.apply(null, minTemp);
|
weather.minTemperature = Math.min.apply(null, minTemp);
|
||||||
@ -140,7 +136,6 @@ WeatherProvider.register("openweathermap", {
|
|||||||
|
|
||||||
// If the first value of today is later than 17:00, we have an icon at least!
|
// If the first value of today is later than 17:00, we have an icon at least!
|
||||||
weather.weatherType = this.convertWeatherType(forecast.weather[0].icon);
|
weather.weatherType = this.convertWeatherType(forecast.weather[0].icon);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moment(forecast.dt, "X").format("H") >= 8 && moment(forecast.dt, "X").format("H") <= 17) {
|
if (moment(forecast.dt, "X").format("H") >= 8 && moment(forecast.dt, "X").format("H") <= 17) {
|
||||||
@ -223,7 +218,7 @@ WeatherProvider.register("openweathermap", {
|
|||||||
days.push(weather);
|
days.push(weather);
|
||||||
}
|
}
|
||||||
|
|
||||||
return days;
|
return days;
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -261,16 +256,16 @@ WeatherProvider.register("openweathermap", {
|
|||||||
*/
|
*/
|
||||||
getParams() {
|
getParams() {
|
||||||
let params = "?";
|
let params = "?";
|
||||||
if(this.config.locationID) {
|
if (this.config.locationID) {
|
||||||
params += "id=" + this.config.locationID;
|
params += "id=" + this.config.locationID;
|
||||||
} else if(this.config.location) {
|
} else if (this.config.location) {
|
||||||
params += "q=" + this.config.location;
|
params += "q=" + this.config.location;
|
||||||
} else if (this.firstEvent && this.firstEvent.geo) {
|
} else if (this.firstEvent && this.firstEvent.geo) {
|
||||||
params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon;
|
params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon;
|
||||||
} else if (this.firstEvent && this.firstEvent.location) {
|
} else if (this.firstEvent && this.firstEvent.location) {
|
||||||
params += "q=" + this.firstEvent.location;
|
params += "q=" + this.firstEvent.location;
|
||||||
} else {
|
} else {
|
||||||
this.hide(this.config.animationSpeed, {lockString:this.identifier});
|
this.hide(this.config.animationSpeed, { lockString: this.identifier });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* global WeatherProvider, WeatherObject */
|
/* global WeatherProvider, WeatherObject, SunCalc */
|
||||||
|
|
||||||
/* Magic Mirror
|
/* Magic Mirror
|
||||||
* Module: Weather
|
* Module: Weather
|
||||||
@ -8,10 +8,7 @@
|
|||||||
*
|
*
|
||||||
* This class is a provider for UK Met Office Datapoint.
|
* This class is a provider for UK Met Office Datapoint.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
WeatherProvider.register("ukmetoffice", {
|
WeatherProvider.register("ukmetoffice", {
|
||||||
|
|
||||||
// Set the name of the provider.
|
// Set the name of the provider.
|
||||||
// This isn't strictly necessary, since it will fallback to the provider identifier
|
// This isn't strictly necessary, since it will fallback to the provider identifier
|
||||||
// But for debugging (and future alerts) it would be nice to have the real name.
|
// But for debugging (and future alerts) it would be nice to have the real name.
|
||||||
@ -25,9 +22,8 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
// Overwrite the fetchCurrentWeather method.
|
// Overwrite the fetchCurrentWeather method.
|
||||||
fetchCurrentWeather() {
|
fetchCurrentWeather() {
|
||||||
this.fetchData(this.getUrl("3hourly"))
|
this.fetchData(this.getUrl("3hourly"))
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location ||
|
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
|
||||||
!data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length == 0) {
|
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
// Maybe this needs a better check?
|
// Maybe this needs a better check?
|
||||||
return;
|
return;
|
||||||
@ -38,18 +34,17 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
|
const currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
|
||||||
this.setCurrentWeather(currentWeather);
|
this.setCurrentWeather(currentWeather);
|
||||||
})
|
})
|
||||||
.catch(function(request) {
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
})
|
})
|
||||||
.finally(() => this.updateAvailable())
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
// Overwrite the fetchCurrentWeather method.
|
// Overwrite the fetchCurrentWeather method.
|
||||||
fetchWeatherForecast() {
|
fetchWeatherForecast() {
|
||||||
this.fetchData(this.getUrl("daily"))
|
this.fetchData(this.getUrl("daily"))
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location ||
|
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
|
||||||
!data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length == 0) {
|
|
||||||
// Did not receive usable new data.
|
// Did not receive usable new data.
|
||||||
// Maybe this needs a better check?
|
// Maybe this needs a better check?
|
||||||
return;
|
return;
|
||||||
@ -60,14 +55,12 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
const forecast = this.generateWeatherObjectsFromForecast(data);
|
const forecast = this.generateWeatherObjectsFromForecast(data);
|
||||||
this.setWeatherForecast(forecast);
|
this.setWeatherForecast(forecast);
|
||||||
})
|
})
|
||||||
.catch(function(request) {
|
.catch(function (request) {
|
||||||
Log.error("Could not load data ... ", request);
|
Log.error("Could not load data ... ", request);
|
||||||
})
|
})
|
||||||
.finally(() => this.updateAvailable())
|
.finally(() => this.updateAvailable());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** UK Met Office Specific Methods - These are not part of the default provider methods */
|
/** UK Met Office Specific Methods - These are not part of the default provider methods */
|
||||||
/*
|
/*
|
||||||
* Gets the complete url for the request
|
* Gets the complete url for the request
|
||||||
@ -83,24 +76,23 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||||
|
|
||||||
// data times are always UTC
|
// data times are always UTC
|
||||||
let nowUtc = moment.utc()
|
let nowUtc = moment.utc();
|
||||||
let midnightUtc = nowUtc.clone().startOf("day")
|
let midnightUtc = nowUtc.clone().startOf("day");
|
||||||
let timeInMins = nowUtc.diff(midnightUtc, "minutes");
|
let timeInMins = nowUtc.diff(midnightUtc, "minutes");
|
||||||
|
|
||||||
// loop round each of the (5) periods, look for today (the first period may be yesterday)
|
// loop round each of the (5) periods, look for today (the first period may be yesterday)
|
||||||
for (i in currentWeatherData.SiteRep.DV.Location.Period) {
|
for (var i in currentWeatherData.SiteRep.DV.Location.Period) {
|
||||||
let periodDate = moment.utc(currentWeatherData.SiteRep.DV.Location.Period[i].value.substr(0,10), "YYYY-MM-DD")
|
let periodDate = moment.utc(currentWeatherData.SiteRep.DV.Location.Period[i].value.substr(0, 10), "YYYY-MM-DD");
|
||||||
|
|
||||||
// ignore if period is before today
|
// ignore if period is before today
|
||||||
if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
|
if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
|
||||||
|
|
||||||
// check this is the period we want, after today the diff will be -ve
|
// check this is the period we want, after today the diff will be -ve
|
||||||
if (moment().diff(periodDate, "minutes") > 0) {
|
if (moment().diff(periodDate, "minutes") > 0) {
|
||||||
// loop round the reports looking for the one we are in
|
// loop round the reports looking for the one we are in
|
||||||
// $ value specifies the time in minutes-of-the-day: 0, 180, 360,...1260
|
// $ value specifies the time in minutes-of-the-day: 0, 180, 360,...1260
|
||||||
for (j in currentWeatherData.SiteRep.DV.Location.Period[i].Rep){
|
for (var j in currentWeatherData.SiteRep.DV.Location.Period[i].Rep) {
|
||||||
let p = currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].$;
|
let p = currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].$;
|
||||||
if (timeInMins >= p && timeInMins-180 < p) {
|
if (timeInMins >= p && timeInMins - 180 < p) {
|
||||||
// finally got the one we want, so populate weather object
|
// finally got the one we want, so populate weather object
|
||||||
currentWeather.humidity = currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].H;
|
currentWeather.humidity = currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].H;
|
||||||
currentWeather.temperature = this.convertTemp(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].T);
|
currentWeather.temperature = this.convertTemp(currentWeatherData.SiteRep.DV.Location.Period[i].Rep[j].T);
|
||||||
@ -116,7 +108,7 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// determine the sunrise/sunset times - not supplied in UK Met Office data
|
// determine the sunrise/sunset times - not supplied in UK Met Office data
|
||||||
let times = this.calcAstroData(currentWeatherData.SiteRep.DV.Location)
|
let times = this.calcAstroData(currentWeatherData.SiteRep.DV.Location);
|
||||||
currentWeather.sunrise = times[0];
|
currentWeather.sunrise = times[0];
|
||||||
currentWeather.sunset = times[1];
|
currentWeather.sunset = times[1];
|
||||||
|
|
||||||
@ -127,22 +119,21 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
* Generate WeatherObjects based on forecast information
|
* Generate WeatherObjects based on forecast information
|
||||||
*/
|
*/
|
||||||
generateWeatherObjectsFromForecast(forecasts) {
|
generateWeatherObjectsFromForecast(forecasts) {
|
||||||
|
|
||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
// loop round the (5) periods getting the data
|
// loop round the (5) periods getting the data
|
||||||
// for each period array, Day is [0], Night is [1]
|
// for each period array, Day is [0], Night is [1]
|
||||||
for (j in forecasts.SiteRep.DV.Location.Period) {
|
for (var j in forecasts.SiteRep.DV.Location.Period) {
|
||||||
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits);
|
||||||
|
|
||||||
// data times are always UTC
|
// data times are always UTC
|
||||||
dateStr = forecasts.SiteRep.DV.Location.Period[j].value
|
const dateStr = forecasts.SiteRep.DV.Location.Period[j].value;
|
||||||
let periodDate = moment.utc(dateStr.substr(0,10), "YYYY-MM-DD")
|
let periodDate = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD");
|
||||||
|
|
||||||
// ignore if period is before today
|
// ignore if period is before today
|
||||||
if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
|
if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
|
||||||
// populate the weather object
|
// populate the weather object
|
||||||
weather.date = moment.utc(dateStr.substr(0,10), "YYYY-MM-DD");
|
weather.date = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD");
|
||||||
weather.minTemperature = this.convertTemp(forecasts.SiteRep.DV.Location.Period[j].Rep[1].Nm);
|
weather.minTemperature = this.convertTemp(forecasts.SiteRep.DV.Location.Period[j].Rep[1].Nm);
|
||||||
weather.maxTemperature = this.convertTemp(forecasts.SiteRep.DV.Location.Period[j].Rep[0].Dm);
|
weather.maxTemperature = this.convertTemp(forecasts.SiteRep.DV.Location.Period[j].Rep[0].Dm);
|
||||||
weather.weatherType = this.convertWeatherType(forecasts.SiteRep.DV.Location.Period[j].Rep[0].W);
|
weather.weatherType = this.convertWeatherType(forecasts.SiteRep.DV.Location.Period[j].Rep[0].W);
|
||||||
@ -213,7 +204,7 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
* Convert temp (from degrees C) if required
|
* Convert temp (from degrees C) if required
|
||||||
*/
|
*/
|
||||||
convertTemp(tempInC) {
|
convertTemp(tempInC) {
|
||||||
return this.tempUnits === "imperial" ? tempInC * 9 / 5 + 32 : tempInC;
|
return this.tempUnits === "imperial" ? (tempInC * 9) / 5 + 32 : tempInC;
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -228,22 +219,22 @@ WeatherProvider.register("ukmetoffice", {
|
|||||||
*/
|
*/
|
||||||
convertWindDirection(windDirection) {
|
convertWindDirection(windDirection) {
|
||||||
const windCardinals = {
|
const windCardinals = {
|
||||||
"N": 0,
|
N: 0,
|
||||||
"NNE": 22,
|
NNE: 22,
|
||||||
"NE": 45,
|
NE: 45,
|
||||||
"ENE": 67,
|
ENE: 67,
|
||||||
"E": 90,
|
E: 90,
|
||||||
"ESE": 112,
|
ESE: 112,
|
||||||
"SE": 135,
|
SE: 135,
|
||||||
"SSE": 157,
|
SSE: 157,
|
||||||
"S": 180,
|
S: 180,
|
||||||
"SSW": 202,
|
SSW: 202,
|
||||||
"SW": 225,
|
SW: 225,
|
||||||
"WSW": 247,
|
WSW: 247,
|
||||||
"W": 270,
|
W: 270,
|
||||||
"WNW": 292,
|
WNW: 292,
|
||||||
"NW": 315,
|
NW: 315,
|
||||||
"NNW": 337
|
NNW: 337
|
||||||
};
|
};
|
||||||
|
|
||||||
return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
|
return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
|
||||||
|