Compare commits

...

1307 Commits

Author SHA1 Message Date
Michael Teeuw
018cb91526 Merge pull request #2064 from MichMich/develop
Release 2.12.0
2020-07-01 20:04:36 +02:00
Michael Teeuw
e16db2233f Fix contributor list. 2020-07-01 19:52:38 +02:00
Michael Teeuw
5d90a08011 Prepare release 2.12.0 2020-07-01 19:47:09 +02:00
Michael Teeuw
2d3849a671 Merge pull request #2061 from ZoneMR/patch-1
Fix #2030 - Clock can be off by a minute
2020-07-01 19:38:11 +02:00
Michael Teeuw
e0dcdc2110 Merge pull request #2063 from lyubomirv/develop
Updated the BG translation
2020-07-01 19:31:08 +02:00
Michael Teeuw
22fcee2a16 Merge branch 'develop' into pr/ZoneMR/2061 2020-07-01 19:29:41 +02:00
Michael Teeuw
8c0141367b Fix EOF issue. 2020-07-01 19:25:00 +02:00
Michael Teeuw
6d829fa575 Merge pull request #2059 from bryanzzhu/bryanzzhu-currentweather
added config option to hide sunrise/sunset in Current Weather module
2020-07-01 13:16:48 +02:00
Lyubomir Vasilev
c9d0bd2d7f Updated the BG translation 2020-07-01 10:08:41 +03:00
ZoneMR
ea31d34649 Fix #2030 - Clock can be off by a minute
Set minute/second in our model based on the actual time from moment() rather than our own attempt to track the time - which can drift or fail to respond to time changes.

Also, schedule time refreshes to happen 50ms after the minute/second is expected to change - preventing premature fires and rapid re-firings of notifications due to accuracy limits in setTimeout
2020-06-30 19:51:25 +01:00
Bryan Zhu
7a3ea37798 added config option to hide sunrise/sunset in Current Weather module 2020-06-29 12:44:24 -04:00
Michael Teeuw
fdd389d6b7 Merge pull request #2058 from XBCreepinJesus/develop
UK Met Office DataHub weather provider
2020-06-28 13:40:17 +02:00
CreepinJesus
b91fccc0e3 Update metofficedatahub.js 2020-06-28 12:09:16 +01:00
CreepinJesus
d911b075ab Met Office DataHub weather provider 2020-06-28 11:13:44 +01:00
CreepinJesus
4339cdd8a4 Included check for Met Office DataHub provider.
The new Met Office provider also returns precipitation as a probability percentage.
2020-06-28 11:00:10 +01:00
CreepinJesus
dd32d3a492 New Met Office provider
This is a provider for the Met Office's new DataHub API (which will eventually replace their current DataPoint service).
2020-06-28 10:57:19 +01:00
Michael Teeuw
c4bc3e2687 Merge pull request #2054 from MichMich/revert-pr-2021
Revert PR #2021
2020-06-24 12:36:28 +02:00
Michael Teeuw
2c5909a138 Update CHANGELOG.md 2020-06-24 09:50:25 +02:00
Michael Teeuw
42c13fa584 Update compliments.js 2020-06-24 09:49:14 +02:00
Michael Teeuw
3b442d4bfc Merge pull request #2048 from rejas/issue_1926
Updated ical library to latest version
2020-06-22 18:19:18 +02:00
rejas
9831f81b6e Merge branch 'develop' into issue_1926 2020-06-20 20:43:09 +02:00
Michael Teeuw
d3282506c9 Merge pull request #2052 from chamakura/develop
Bug fix to correctly handle the logic for 'maxEntries' Issue #2050
2020-06-20 20:35:32 +02:00
chamakura
2afff6c432 Updating files to the latest versions from 'develop' branch 2020-06-20 11:18:37 -07:00
chamakura
be3616abe2 Bug fix to correctly handle the logic for 'maxEntries' Issue #2050 2020-06-20 11:01:37 -07:00
rejas
daa6f5051c Use object.entries to iterate over data 2020-06-20 09:01:35 +02:00
rejas
1e5bd98f02 Make calendar debuger use const stuff and add npm script for it 2020-06-20 08:45:46 +02:00
rejas
7e5bfa8dd2 Fix slice parameter type 2020-06-20 08:45:22 +02:00
rejas
53363b0618 Simplify return call to make a better diff 2020-06-20 08:45:03 +02:00
rejas
b2f71a2ce1 Update dependencies 2020-06-20 08:33:19 +02:00
rejas
5d4a575919 Undo switch to fetch, use request like ical did 2020-06-20 08:32:54 +02:00
rejas
7d521ed3ce More var -> let/const conversions 2020-06-18 21:54:51 +02:00
rejas
bb9ad3daa9 Use some const/let instead of var 2020-06-17 21:37:49 +02:00
rejas
442f270ee0 Update CHANGELOG 2020-06-17 21:24:50 +02:00
rejas
7ab74c6cc9 Remove old ical version 2020-06-17 21:17:35 +02:00
rejas
6d60baa2d6 Install latest ical version and use it 2020-06-17 21:17:26 +02:00
Michael Teeuw
6d3308621f Merge pull request #2017 from rejas/config_logger
Make logger a little more configurable
2020-06-14 14:33:06 +02:00
Michael Teeuw
fd49be1d9b Remove unreachable code. 2020-06-14 14:14:30 +02:00
Michael Teeuw
c40a5648dd Merge branch 'develop' into config_logger 2020-06-14 14:02:48 +02:00
Michael Teeuw
d9a8d2627a Merge pull request #2046 from rejas/issue_1928
Throw error when check_config fails
2020-06-14 14:00:19 +02:00
rejas
c7a88e2f12 Throw error when check_config fails 2020-06-14 11:04:11 +02:00
rejas
963b1aa6b1 Final cleanups I think 2020-06-02 15:05:31 +02:00
rejas
008ac2876b More console -> Logger conversions 2020-06-02 15:05:31 +02:00
rejas
2330b166f6 Totall forgot we need a changelog entry 2020-06-02 15:04:58 +02:00
rejas
23c0e01565 Use logger in node_helpers 2020-06-02 15:04:58 +02:00
Veeck
13073bc98d Lint stuff 2020-06-02 15:03:59 +02:00
Veeck
8c319903dd Cleanup outcommented logging 2020-06-02 15:03:59 +02:00
Veeck
2334cbd78a User logger in checkconfig script 2020-06-02 15:03:59 +02:00
rejas
0cae954f80 Use Log in loader too 2020-06-02 15:03:59 +02:00
rejas
c60446a015 Fix tests 2020-06-02 15:03:59 +02:00
Veeck
d0c6a4ee6d Make logger configurable 2020-06-02 15:03:59 +02:00
rejas
f2d03a511e User logger in node files 2020-06-02 15:03:59 +02:00
rejas
367233c318 Add console-stamp to node-logger 2020-06-02 15:03:59 +02:00
rejas
9461c1692a Add node/browser wrapper around logger 2020-06-02 15:03:59 +02:00
Michael Teeuw
3b32605b5e Merge pull request #2036 from DarthBrento/develop
Fix #1109 - multiple calendar instances with different config
2020-06-02 10:16:09 +02:00
Michael Teeuw
4d21f8d022 Merge branch 'develop' into develop 2020-06-02 09:17:43 +02:00
Michael Teeuw
aac67570d4 Merge pull request #2035 from Ekristoffe/develop
Fix for #2018
2020-06-02 09:17:03 +02:00
Michael Teeuw
5f2c465274 Merge pull request #2032 from radokristof/weather-module
[weather] Ability to hide sun details
2020-06-02 09:15:31 +02:00
Michael Teeuw
fdaa0bc876 Merge pull request #2031 from radokristof/calendar-module
[calendar] Use wrapEvents to also truncate the location
2020-06-02 09:13:42 +02:00
Kristof Rado
a692d6be09 Reworked titleTransform. 2020-06-01 22:25:07 +02:00
Kristof Rado
efbb9648c4 Introduce new function for location title shortening. 2020-06-01 20:23:59 +02:00
Kristof Rado
3d73153e59 Revert "Renamed function"
This reverts commit 6aa0a4a4
2020-06-01 20:19:03 +02:00
DarthBrento
8fa2256fb0 linted 2020-06-01 17:19:41 +02:00
DarthBrento
4fe974e7a8 Check identifier for type, too 2020-06-01 13:31:46 +02:00
DarthBrento
21f76a8f27 Attach identifier to socket notifications to allow multiple instances 2020-06-01 13:14:54 +02:00
DarthBrento
aeb287fa1d Attach identifier to socket notifications to allow multiple instances 2020-06-01 13:12:54 +02:00
DarthBrento
1405e8821c Update calendar.js 2020-06-01 00:38:05 +02:00
DarthBrento
37e31bac5b Update node_helper.js 2020-06-01 00:36:47 +02:00
DarthBrento
d31b696846 updated changelog 2020-06-01 00:24:13 +02:00
Chris
cc01c1f0db Update weatherforecast.js 2020-05-31 11:57:53 +09:00
Chris
4a7076e01c Prettier correction 2020-05-31 11:46:50 +09:00
Chris
d306bb25dc Update CHANGELOG.md 2020-05-31 00:20:42 +09:00
Chris
457c80fe76 Correct #2018
Weather forecast need the maxNumberOfDays as argument &cnt=**
The minimum is 1 and the maximum is 17.
2020-05-31 00:15:54 +09:00
Kristof Rado
bb972f8449 Updated CHANGELOG.md 2020-05-30 00:11:14 +02:00
Kristof Rado
e6ef64968b Disable Sunrise/Sunset in Config option 2020-05-30 00:06:20 +02:00
Kristof Rado
6f3b87cfd1 Merge branch 'develop' into weather-module 2020-05-29 23:56:09 +02:00
Kristof Rado
f449feb3f8 Updated CHANGELOG.md 2020-05-29 23:53:07 +02:00
Kristof Rado
b179c8e2b7 Merge branch 'develop' into calendar-module 2020-05-29 23:50:24 +02:00
Kristof Rado
6aa0a4a47f Renamed function 2020-05-29 23:50:01 +02:00
Kristof Rado
766140f483 Ability to hide sun details 2020-05-28 10:57:01 +02:00
Kristof Rado
52aa8b868a Truncate event title 2020-05-28 10:09:34 +02:00
Michael Teeuw
8a3a4d6fae Merge pull request #2027 from rejas/fix_travis_error
Fix travis error
2020-05-25 20:18:37 +02:00
Veeck
94f212a411 Fix travis error due to merge before prettier run 2020-05-25 20:00:59 +02:00
Michael Teeuw
4e1dce70a3 Merge pull request #2013 from rejas/prettier
Add Prettier for an even cleaner code-experience
2020-05-25 18:46:36 +02:00
Michael Teeuw
bbf48a0dd0 Merge pull request #2021 from ndom91/update-compliments-module-advice-api
Update Compliments Module - Add Advice API
2020-05-24 13:47:30 +02:00
ndo@ndo3
a35e8f3315 update: spaces -> tabs 2020-05-14 15:00:09 +02:00
ndo@ndo3
205de7233e add: advice api to compliments module 2020-05-14 14:56:38 +02:00
Veeck
abb5dc5739 Run prettier over ALL files once
No other changes done in this commit
2020-05-11 22:22:32 +02:00
Veeck
3a5a29efc0 Add pretty-quick 2020-05-11 21:59:45 +02:00
rejas
c202c0d705 Add prettier, configs and editorconfig 2020-05-07 14:09:22 +02:00
Michael Teeuw
8a1f9b7de6 Merge pull request #2012 from rejas/issue_2011
Use correct object in browser context
2020-05-07 09:02:17 +02:00
Veeck
18820c383d Use correct object in browser context 2020-05-06 22:19:07 +02:00
Michael Teeuw
b38b879ee3 Merge pull request #2010 from rejas/no_undef_and_more
Cleanup eslints no-undef warnings Part 2
2020-05-05 15:16:27 +02:00
Veeck
7fc7d626bc Add Module to globals, cleanup comments 2020-05-05 14:55:15 +02:00
Veeck
c8a0f1d0de Fix some more undefs that popped up out of nowhere 2020-05-05 14:54:49 +02:00
Michael Teeuw
c8aedc6f29 Merge pull request #1997 from andrezibaia/patch-1
Literal translation (not used in Portuguese)
2020-05-05 14:32:45 +02:00
Michael Teeuw
1e7ce8bb5c Merge pull request #2007 from rejas/no_undef
Cleanup eslints no-undef warnings
2020-05-05 14:31:41 +02:00
Veeck
5386ca1592 Merge branch 'develop' into no_undef 2020-05-05 14:20:24 +02:00
Michael Teeuw
08ed019426 Merge branch 'develop' of https://github.com/MichMich/MagicMirror into develop 2020-05-05 14:18:14 +02:00
Michael Teeuw
55c6a5aa27 remove unused file 2020-05-05 14:17:46 +02:00
rejas
bd6bbf864a Update dependencies 2020-05-03 20:52:58 +02:00
rejas
703335c2f1 Update changelog 2020-05-03 20:50:52 +02:00
rejas
c04fa496bf Second round of undef fixes 2020-05-03 18:59:26 +02:00
rejas
b9d19cfcb4 First round of undef fixes 2020-05-03 12:40:48 +02:00
rejas
d8f093b226 Cleanup some globals 2020-05-02 10:33:24 +02:00
rejas
63a2d83d26 Start checking for undef 2020-05-02 10:32:53 +02:00
Michael Teeuw
7e42e98cb6 Merge pull request #2002 from rejas/https
Replace insecure links with https
2020-04-30 09:19:17 +02:00
rejas
93deebe923 Update changelog 2020-04-28 23:09:29 +02:00
rejas
1eecf4b2c7 Fix docs, grunt is removed 2020-04-28 23:07:14 +02:00
rejas
e7fc4ef1e7 Replace unsecure links with https ones 2020-04-28 23:05:28 +02:00
Michael Teeuw
3c54d4af15 Merge pull request #1996 from rejas/eslint_recommend
Update eslint config to use eslint:recommended
2020-04-23 10:23:40 +02:00
andrezibaia
ebfbf0e1f8 Literal translation (not used in Portuguese) 2020-04-23 04:41:05 +02:00
rejas
14aa4036e0 Some spelling and doc fixes 2020-04-22 22:09:31 +02:00
Veeck
0c60d54c3f Add eqeqeq rule to not confuse == with === 2020-04-21 15:13:06 +02:00
Veeck
e510d279a2 Cleanup some more header comments 2020-04-21 14:58:17 +02:00
Veeck
be6f1f9c4a Move eslint to dependencies, update some devdependcies 2020-04-21 14:41:34 +02:00
rejas
b1fb177e4b Undo "fix" in main.js that broke the tests 2020-04-21 12:38:29 +02:00
Veeck
ec187fe109 Update changelog and commen tags 2020-04-21 12:23:50 +02:00
Veeck
9ec329b7ae Final fixes for eslint:recommended 2020-04-21 12:23:50 +02:00
rejas
d08bd4e866 Fix lots of warnings 2020-04-21 12:23:50 +02:00
rejas
941d5d7cd9 Fix mixed tabs and whitespace errors 2020-04-21 12:23:50 +02:00
rejas
ef8d85773c Run automatic fix 2020-04-21 12:23:50 +02:00
rejas
e668d488b4 Use eslint:recommend 2020-04-21 12:23:50 +02:00
Michael Teeuw
d4eb5facfd Merge pull request #1992 from rejas/update_fonts
Update font package
2020-04-21 11:55:08 +02:00
Veeck
a1285b120b Remove some other prefixed styles since we are at it 2020-04-20 12:13:13 +02:00
Veeck
8650876e2b Remove yarn.locks 2020-04-20 12:10:58 +02:00
Veeck
81ab12c89c Update changelog 2020-04-20 12:10:58 +02:00
Veeck
4ddb8cec85 Update roboto fonts, remove ttf entries 2020-04-20 12:10:58 +02:00
Michael Teeuw
711c566498 Merge pull request #1995 from rejas/cleanup_alert
Cleanup default alert module
2020-04-20 12:06:18 +02:00
Veeck
cc5336900c Update dependencies 2020-04-20 11:34:24 +02:00
Veeck
291a8f5c1f Fix warnings for jsonlint 2020-04-20 11:34:16 +02:00
Veeck
8c0e98ed43 Ignore some other files when linting markdown too 2020-04-20 11:30:05 +02:00
Veeck
7a976c0239 Fix tests, use non-spread object extend version again 2020-04-20 11:24:03 +02:00
Veeck
fb557b9130 Update ignored files for eslint 2020-04-20 11:15:11 +02:00
Veeck
b56a930f60 Update changelog 2020-04-20 10:59:04 +02:00
Veeck
5819ef346b Rename stylesheet for clarity that its about the notificationFX 2020-04-20 10:58:27 +02:00
Veeck
b3dcc82c71 Remove old webkit prefix styles 2020-04-20 10:52:53 +02:00
Veeck
06e8308dc2 Replace old js files with modern code 2020-04-20 10:51:27 +02:00
Michael Teeuw
c8a9c9b84e Merge pull request #1991 from rejas/cleanup_config_check
Cleanup config check script
2020-04-19 09:10:41 +02:00
Veeck
e85b49c573 Update changelog 2020-04-19 08:22:48 +02:00
Veeck
c7c6dc4e67 Move config check into js folder, cleanup var usage 2020-04-19 07:55:56 +02:00
Michael Teeuw
172d668416 Merge pull request #1963 from AndreKoepke/feature/client_https
add https support for clientonly-mode
2020-04-15 09:57:53 +02:00
AndreKoepke
b651dc845b no single quotes 2020-04-14 14:10:29 +02:00
Michael Teeuw
c755f44153 Merge pull request #1981 from rejas/remove_grunt
Remove grunt, use non-grunt linters instead
2020-04-10 21:55:41 +02:00
rejas
ed28ce1874 Update changelog and lock 2020-04-10 16:12:51 +02:00
rejas
194af0e985 Run linter and npm audit 2020-04-10 15:09:08 +02:00
rejas
ab3015df6b Remove rest of grunt calls 2020-04-10 14:43:58 +02:00
rejas
f36df159e0 Replace grunt-jsonlint with jsonlint 2020-04-10 12:24:08 +02:00
rejas
61462cf57e Replace grunt-eslint with eslint 2020-04-10 07:48:28 +02:00
rejas
427d186c86 Replace grunt-markdownlint with markdownlint-cli 2020-04-10 07:48:28 +02:00
rejas
84e9c47a67 Replace grunt-stylelint with stylelint 2020-04-10 07:48:28 +02:00
rejas
18989d593a Replace grunt-yamllint with yaml-lint 2020-04-10 07:48:28 +02:00
Michael Teeuw
fc624359c5 Merge pull request #1980 from khassel/socketclient_fix
socketclient.js: add backward compatibility for old module code
2020-04-09 13:50:38 +02:00
Karsten Hassel
1914573634 fixed again ... 2020-04-07 20:26:09 +02:00
Karsten Hassel
1fd36458a6 update CHANGELOG.md 2020-04-07 19:42:16 +02:00
Karsten Hassel
37ee0e568f socketclient.js: add backward compatibility for old module code 2020-04-07 19:35:21 +02:00
Michael Teeuw
3f8363a5b2 Merge pull request #1976 from Legion2/develop
Added basename config
2020-04-06 21:55:10 +02:00
Leon Kiefer
e6c0011789 renamed basename to basePath 2020-04-06 21:29:55 +02:00
Leon Kiefer
eb37a495a2 changed headings in Changelog 2020-04-05 23:18:00 +02:00
Leon Kiefer
54542f7f07 added basename config
use basename in socket.io path fix #1973
2020-04-05 23:00:38 +02:00
AndreKoepke
8e38910dd8 Merge branch 'develop' into feature/client_https 2020-04-03 14:22:41 +02:00
Andre
31b3f778fc no single quotes 2020-04-03 12:37:33 +02:00
Michael Teeuw
ca3275757b Fix release date. 2020-04-01 15:40:14 +02:00
Michael Teeuw
501a314597 Start of 2.12.0-develop 2020-04-01 12:28:40 +02:00
Michael Teeuw
447c0bffdc Merge pull request #1968 from MichMich/develop
Release 2.11.0
2020-04-01 12:21:33 +02:00
Michael Teeuw
46df59d77a Prepare release 2.11.0 2020-04-01 11:52:39 +02:00
Michael Teeuw
8c85e240b7 Merge pull request #1967 from MichMich/rejas-date
Rejas date
2020-04-01 11:15:31 +02:00
Michael Teeuw
2464d01891 Fix date test. 2020-04-01 10:57:50 +02:00
Michael Teeuw
66642a19c5 Merge branch 'date' of https://github.com/rejas/MagicMirror into rejas-date 2020-04-01 10:08:33 +02:00
Michael Teeuw
f7f4e92e0a Merge branch 'develop' of https://github.com/MichMich/MagicMirror into develop 2020-04-01 09:58:55 +02:00
Michael Teeuw
2674bf22d8 Let's use sensible defaults. :) 2020-04-01 09:44:22 +02:00
Andre
351e0f3a0b add https support 2020-03-28 12:37:50 +01:00
rejas
ff7dc95e93 Implement suggestions from Michael 2020-03-28 09:24:30 +01:00
rejas
4e4d3418b3 LInt mockdate helper 2020-03-25 06:53:09 +01:00
rejas
3659b5b5c9 Update mockdate info 2020-03-25 06:40:23 +01:00
rejas
65e1b60fb7 Fix error when no compliments are set 2020-03-25 06:40:23 +01:00
rejas
e2427fe299 Try out a mockdate class 2020-03-25 06:40:23 +01:00
rejas
b08f882324 Add (failing) test for new date field 2020-03-25 06:40:23 +01:00
rejas
2a31ece0c6 Refactor code 2020-03-25 06:40:23 +01:00
rejas
cafa4211a6 Update changelog and add another birtday 2020-03-25 06:40:23 +01:00
rejas
82b50d3059 Add basic compliment on a specific day of the year 2020-03-25 06:39:24 +01:00
Michael Teeuw
39cb582e07 Merge pull request #1960 from effelle/develop
Update pt-br.json
2020-03-24 21:16:41 +01:00
Michael Teeuw
fe6645a420 Merge pull request #1955 from rejas/jshint
Remove jshint dependency
2020-03-24 21:16:12 +01:00
Michael Teeuw
a49816f4eb Merge pull request #1948 from rejas/lint
Run linter tests on travis (was: Run linter before commit)
2020-03-24 21:15:41 +01:00
Michael Teeuw
7ac97f854c Merge pull request #1937 from Legion2/develop
use relative path for socket.io
2020-03-24 21:13:36 +01:00
Federico Leoni
8f203852ca Update CHANGELOG.md 2020-03-24 10:06:12 -03:00
Federico Leoni
c342f7bce6 Update pt-br.json 2020-03-23 14:55:36 -03:00
Michael Teeuw
fe1c5df9d5 Merge pull request #1958 from bugsounet/master
issue #1956
2020-03-19 19:17:03 +01:00
bugsounet
8aa7a55559 issue #1956 2020-03-19 19:03:25 +01:00
rejas
e9461586cb Update changelog 2020-03-15 21:25:11 +01:00
rejas
a91f2de26a Remove jshint dependency, use eslint for config verification 2020-03-15 20:38:52 +01:00
rejas
5a4ae99283 Add no-multi-spaces rule to eslint and run it 2020-03-15 15:49:34 +01:00
rejas
437d030502 Remove some dead files, fix stylelint error 2020-03-11 12:44:44 +01:00
rejas
f3d45eff69 Fix js error but add a stylelint error 2020-03-11 11:43:45 +01:00
rejas
f22e39e22b Add switch to auto fix eslint and stylelint issues 2020-03-11 11:29:59 +01:00
rejas
7470a3b813 Dont fix eslint errors automatically 2020-03-11 10:48:43 +01:00
rejas
0b2e836e3d Commit a faulty js to see if travis complains 2020-03-11 09:01:21 +01:00
rejas
c3d57eef4f Remove husky again, move lint as test to travis 2020-03-11 08:52:25 +01:00
rejas
ca2571b438 Update changelog 2020-03-08 16:31:34 +01:00
rejas
6c926b8876 Add husky for pre-commit hook 2020-03-08 16:25:26 +01:00
rejas
5517a913d4 Run linter manually 2020-03-08 16:20:54 +01:00
Michael Teeuw
ef7720ff06 Merge pull request #1939 from dtreskunov/dtreskunov/fix-moon-illumination-percent-calc
fix floating point bug in moon illumination calc
2020-02-27 16:35:38 +01:00
Michael Teeuw
daa13b4b30 Merge pull request #1941 from bibaldo/bibaldo-currentweather
Add new default config to 'current weather' module
2020-02-27 16:34:26 +01:00
Michael Teeuw
9d4e237c09 Merge pull request #1938 from tosbaha/develop
Turkish translation update
2020-02-27 16:32:40 +01:00
Michael Teeuw
883c169ef7 Merge branch 'develop' into develop 2020-02-27 16:31:10 +01:00
Michael Teeuw
2b2b07f6b4 Merge pull request #1936 from buxxi/develop
Using promises to resolve which modules has a git remote
2020-02-27 16:30:23 +01:00
Jose Forte
f338b68f36 Update CHANGELOG.md 2020-02-21 10:31:40 -03:00
Jose Forte
c877b5fc70 Add new default config to 'current weather' module 2020-02-21 10:17:05 -03:00
Leon Kiefer
6aeec81072 removed additional slash from the socket.io path 2020-02-19 20:58:58 +01:00
Denis Treskunov
3f78c664eb fix floating point bug in moon illumination calc 2020-02-19 09:31:02 -08:00
mustafa
3b7df1d5c2 Changelog updated 2020-02-19 15:25:46 +03:00
mustafa
b6fc063c75 Turkish translation updated 2020-02-19 15:21:25 +03:00
Leon Kiefer
7b56817ae6 use relative path for socket.io fix #1934 2020-02-18 17:09:25 +01:00
buxxi
75c8c3f50b Using promises to resolve which modules has a git remote so the modules wont be skipped on the first check 2020-02-17 22:56:06 +01:00
Michael Teeuw
be07ff2129 Merge pull request #1923 from wast/patch-1
Fix Croatian translation for Calendar module word FEELS.
2020-02-12 16:34:45 +01:00
Michael Teeuw
56846b258c Merge branch 'develop' into patch-1 2020-02-12 16:34:33 +01:00
Michael Teeuw
f67310c8fa Merge pull request #1927 from fewieden/fix/weather-tests
1840 fix weather tests
2020-02-12 16:33:31 +01:00
Michael Teeuw
3dff3a1d4a Merge branch 'develop' into fix/weather-tests 2020-02-12 16:33:19 +01:00
Michael Teeuw
142d30b1c6 Merge pull request #1929 from buxxi/develop
Adding support for ignoring update check for certain modules
2020-02-11 19:21:46 +01:00
buxxi
c925e88475 Adding support for ignoring update check for certain modules 2020-02-11 18:13:39 +01:00
fewieden
56392e41d0 Add 1840 to changelog 2020-02-10 22:05:43 +01:00
fewieden
cd7b6450c6 Run tests also on lts and last stable version of nodejs 2020-02-10 21:51:29 +01:00
Felix Wiedenbach
de6a9f5811 fix timing issue in weather tests => returning response by url instead of index 2020-02-10 18:56:55 +01:00
Michael Teeuw
d7295948fd Merge pull request #1925 from dtreskunov/dtreskunov/fix-clock-module-moon-widget
fix bugs in showMoonTimes in clock module
2020-02-10 07:40:10 +01:00
Denis Treskunov
f4c3e412a2 fix bugs in showMoonTimes in clock module
1. as reported on https://github.com/MichMich/MagicMirror/pull/1885,
toLocaleString is not supported on old iPad Safari

2. SunCalc.getMoonTimes returns moonRise/moonSet times for the given date,
so moonRise can be after moonSet. We want to display the most relevant
times, which are today's moonRise and the next moonSet.
2020-02-09 22:03:35 -08:00
Stjepan
0d461e14d9 Merge pull request #1 from wast/patch-2
Update CHANGELOG.md
2020-02-09 10:26:54 +01:00
Stjepan
845c2571fe Update CHANGELOG.md
Fix FEELS translation in Croatian
2020-02-09 10:24:20 +01:00
Stjepan
d5c02d1031 Update hr.json
Fix FEELS translation in Croatian.
2020-02-09 10:22:41 +01:00
Michael Teeuw
30e93a9372 Merge pull request #1915 from normankong/develop
Support HTTPS Magicmirror (resubmit)
2020-02-06 10:10:06 +01:00
Michael Teeuw
e5cdcd190c Merge pull request #1918 from sergge1/develop
to make logic of parameter name to its actual behavior
2020-02-06 10:09:22 +01:00
sergge1
271f1cd71b to make logic of name to actual behaviour
hideTemp = false -> temp shold appear at the MM
hideTemp === true -> should not appear.
This is the logic. Worked vise versa, just corrected in the code
2020-02-06 00:04:48 +02:00
Michael Teeuw
4abb790e12 Merge pull request #1916 from d-Rickyy-b/log-date-timestamp
Log date timestamp
2020-02-05 12:43:26 +01:00
Michael Teeuw
89c9d4dfc4 Merge branch 'develop' into develop 2020-02-05 12:42:43 +01:00
karenorman
5511c15921 Update description in config.js.sample 2020-02-05 10:23:49 +08:00
Rico
e160f9a0f6 docs: add info about changed timestamp in changelog 2020-02-03 21:43:45 +01:00
Rico
65ea341ed0 feat: use date in log timestamp
I find it quite hard to look something up in the logs, when there is no date in the log file. The time itself is not sufficient for debugging, hence I suggest also logging the date.
2020-02-03 21:39:46 +01:00
Michael Teeuw
561827e896 Remove logging. 2020-02-01 19:12:05 +01:00
Michael Teeuw
1315aceb44 Remove duplicate 2.11 entry. 2020-02-01 17:41:49 +01:00
Michael Teeuw
19afd89df5 Fix Typo 2020-02-01 16:48:35 +01:00
Michael Teeuw
cbcc893f64 Restore MM.sh to keep PM2 working. 2020-02-01 15:16:23 +01:00
Michael Teeuw
a41bae3132 Cleanup 2020-02-01 15:05:26 +01:00
Michael Teeuw
8ef8388c32 Set default DISPLAY in package.json. 2020-02-01 15:02:47 +01:00
Michael Teeuw
e2d4a0fde8 Improve Feedback. 2020-02-01 14:52:52 +01:00
Michael Teeuw
65b1d61295 Improve feedback. 2020-02-01 14:43:43 +01:00
Michael Teeuw
1b38e73eb2 Fix install scripts. 2020-02-01 14:41:46 +01:00
Michael Teeuw
e2afee3275 Add feedback. 2020-02-01 14:39:50 +01:00
Michael Teeuw
7f2ecbd04f Cleanup. 2020-02-01 14:32:38 +01:00
Michael Teeuw
21dbaa1a03 Move DISPLAY default to electron script. 2020-02-01 13:59:13 +01:00
Michael Teeuw
09c1ea992c Update start methods. 2020-02-01 13:56:15 +01:00
karenorman
c8c327b6ab Add HTTPS support 2020-02-01 20:46:26 +08:00
Michael Teeuw
3bb801f579 Merge pull request #1914 from kblankenship1989/fix-iso-string
fix: add missing +1 for month
2020-02-01 04:57:12 +01:00
Kurtis Blankenship
ca49d8adb3 fix: correcting syntax 2020-01-31 20:46:43 -06:00
Kurtis Blankenship
88b15797a0 fix: add missing +1 for month 2020-01-31 20:35:46 -06:00
Michael Teeuw
28ebbd229c Merge pull request #1910 from sergge1/develop
added Ukrainian (uk) translation
2020-01-31 19:51:48 +01:00
sergge1
d7f6f46805 2.11.0 - added Ukrainian translation 2020-01-31 11:28:00 +02:00
sergge1
c41d6965ab added Ukrainian translation 2020-01-31 11:18:43 +02:00
sergge1
602119fa41 Ukrainian translation added 2020-01-31 11:17:11 +02:00
Michael Teeuw
4c2a9b47f5 Merge pull request #1906 from mmphego/develop
Grammar fixes on config.js.sample file
2020-01-26 16:46:48 +01:00
Michael Teeuw
5a26fefd6b Merge pull request #1903 from roramirez/not-log-error-vendor-test
Revert error logging introduced in 1e97b5c
2020-01-26 16:46:06 +01:00
Mpho Mphego
85d26f7320 Grammar fixes to config.
This PR does the following:

- [x] Corrects grammar on `config.js.sample`
2020-01-26 14:10:24 +02:00
Michael Teeuw
9487af1852 Merge pull request #1901 from kolbyjack/fix-97e5d92-regression
Fix regression causing 'undefined' to show up when config.hideTemp is…
2020-01-24 17:46:45 +01:00
Jon Kolb
a5b09d7846 Update CHANGELOG.md 2020-01-24 10:51:24 -05:00
Jon Kolb
6ba5056c96 Fix regression causing 'undefined' to show up when config.hideTemp is false 2020-01-24 10:42:45 -05:00
Michael Teeuw
50b4d05ef5 Merge pull request #1899 from MichMich/Skip-weather
Skip weather tests for now
2020-01-23 19:56:23 +01:00
Michael Teeuw
13ebe6d0e1 Check method 2020-01-23 19:52:07 +01:00
Michael Teeuw
95dedf0d80 Skip weather tests for now 2020-01-23 19:38:15 +01:00
Michael Teeuw
89a9368166 Merge pull request #1896 from sejka/patch-1
adds PRECIP polish translation
2020-01-23 19:29:43 +01:00
Michael Teeuw
c10e6159da Merge pull request #1895 from adi-miller/heb
Add Hebrew translation
2020-01-23 19:29:26 +01:00
Michael Teeuw
c30693b8a8 Merge pull request #1894 from roramirez/mode-permission-changelog
Revert permission mode for CHANGELOG
2020-01-23 19:28:59 +01:00
Michael Teeuw
7fc4f61182 Merge pull request #1892 from roramirez/upgrade-electron-6
Upgrade to Electron 6:
2020-01-23 19:28:37 +01:00
Karol Sejka
b44ab88927 adds PRECIP polish translation 2020-01-23 02:24:47 +01:00
adimi
2ca81f965a Add hebrew translation 2020-01-22 22:03:34 +02:00
Michael Teeuw
9f4dc1e382 Merge pull request #1887 from dtreskunov/dtreskunov/sun-and-moon
fix calculation of duration until next sunrise
2020-01-22 15:23:01 +01:00
Michael Teeuw
5ec9704e7f Merge pull request #1893 from roramirez/vendor-fix-test
Fix the vendor_spec test:
2020-01-22 15:22:29 +01:00
Denis Treskunov
7ad0cfd5f6 update CHANGELOG.md 2020-01-21 19:16:42 -08:00
Denis Treskunov
ac8f679dfd Merge remote-tracking branch 'upstream/develop' into dtreskunov/sun-and-moon 2020-01-21 19:13:51 -08:00
Rodrigo Ramírez Norambuena
a7ee2ef3a6 Upgrade to Electron 6:
New version of Electron has enable by default sandbox
http://www.atom.pe/docs/api/sandbox-option/

There was some issues to migrate a new version of Electron for
MagicMirror. Using the new version in Travis CI was failing at this
time. The problem is because the testing runner is a Docker enviroment

The issue experimented is the same topic mentioned here:
 - https://github.com/electron/electron/issues/17972
 - https://github.com/electron-userland/spectron/issues/443

The fix for to all of this is to set the `--no-sandbox` mode in CI
testing https://electronjs.org/docs/all#--no-sandbox

This change use the feature to set and disable Sandbox using
by enviroment variable `ELECTRON_DISABLE_SANDBOX=1`
https://github.com/electron/electron/pull/16576

This change has reference #1800
2020-01-20 22:19:10 +00:00
Rodrigo Ramírez Norambuena
6e7edd9824 Revert error logging introduced in 1e97b5c 2020-01-19 08:50:37 -03:00
Rodrigo Ramírez Norambuena
81b310086f Revert permission mode for CHANGELOG
This change revert change of permission mode for file CHANGELOG.md
introduced in commit a619fc4fef
2020-01-19 04:40:05 -03:00
Rodrigo Ramírez Norambuena
cce57c7229 Fix the vendor_spec test:
This change set after startApplication the configuration to run this
test.

The previous statement when e2e are running using --recursive the
MM_CONFIG_FILE was setting by the test running before this one.
2020-01-19 04:06:21 -03:00
Denis Treskunov
9cffa3dd67 fix calculation of duration until next sunrise 2020-01-18 17:02:40 -08:00
Michael Teeuw
7b3a59455d Merge pull request #1885 from dtreskunov/dtreskunov/sun-and-moon
add sun/moon rise/set times
2020-01-18 21:29:41 +01:00
Michael Teeuw
fefe5659d3 Merge branch 'develop' into dtreskunov/sun-and-moon 2020-01-18 21:20:35 +01:00
Michael Teeuw
db72e22e61 Fuck it. 2020-01-18 21:17:54 +01:00
Michael Teeuw
a85ed709af Remove newlines. 2020-01-18 21:09:18 +01:00
Michael Teeuw
e24d1a1261 Fix newlines? 2020-01-18 21:02:49 +01:00
Michael Teeuw
d6f1bf18de Merge pull request #1884 from kblankenship1989/fix-timeshift-calendar
fix: Issue #1798 - fixing recurrent calendar events crosstime DST
2020-01-18 19:59:24 +01:00
Michael Teeuw
97e5d923fa Merge pull request #1882 from adi-miller/hide_weather
Added the ability to hide the temp label and weather icon in the `cur…
2020-01-18 19:54:30 +01:00
Denis Treskunov
36762a6e46 add duration until next sunset/sunrise 2020-01-18 09:50:43 -08:00
Denis Treskunov
40a9f9dd85 fix stylelint:simple 2020-01-18 08:45:52 -08:00
Denis Treskunov
85a52523cf show sun/moon as bright rather than bold if obj is visible 2020-01-18 08:43:33 -08:00
Kurtis Blankenship
5ed7974099 Merge branch 'fix-timeshift-calendar' of github.com:kblankenship1989/MagicMirror into fix-timeshift-calendar 2020-01-18 06:38:13 -06:00
Kurtis Blankenship
70ca9ce2e0 fix: fixing lint error 2020-01-18 06:38:01 -06:00
kblankenship1989
af9f555e8f fix: fixing copy / paste error on futureLocal 2020-01-18 06:28:21 -06:00
Denis Treskunov
08b9e7b5b5 add sun/moon rise/set times
Icons become bold when the object is above the horizon. Also shows
percent of moon illumination.
2020-01-17 22:28:24 -08:00
Kurtis Blankenship
84f74c53b5 perf: fix wording on changelog 2020-01-17 23:08:34 -06:00
Kurtis Blankenship
762bae907c perf: updating changelog 2020-01-17 23:04:51 -06:00
Kurtis Blankenship
2b738fa14b Merge branch 'develop' of github.com:MichMich/MagicMirror into fix-timeshift-calendar 2020-01-17 22:54:59 -06:00
Kurtis Blankenship
8aa745471b fix: Issue #1798 - fixing recurrent calendar events crosstime DST 2020-01-17 22:53:14 -06:00
Adi Miller
63950f572a Adding trailing enter to avoid build warning. 2020-01-16 16:47:49 +02:00
Adi Miller
81aab7e86f Added the ability to hide the temp label and weather icon in the currentweather module to allow showing only information such as wind and sunset/rise. 2020-01-16 16:26:20 +02:00
Michael Teeuw
1fd5fd4832 Update ISSUE_TEMPLATE.md 2020-01-14 09:20:50 +01:00
Michael Teeuw
ceaf478a84 Merge pull request #1875 from bastilimbach/master
Add different GitHub repos to issue template
2020-01-13 12:29:52 +01:00
Sebastian Limbach
61256f98ca Fix typo 2020-01-13 09:40:38 +01:00
Sebastian Limbach
818ed5d189 Add different GitHub repos
This commit adds the official docker image repo as well as the installation scripts repo to the issue template to avoid the creation of issue which don't belong to the MagicMirror core.
2020-01-12 20:15:04 +01:00
Michael Teeuw
0ca00e5059 Merge pull request #1874 from sdetweil/develop
cleanup installers folder
2020-01-12 17:44:50 +01:00
Sam Detweiler
a2c743167d cleanup installers foldr 2020-01-12 10:19:37 -06:00
Sam Detweiler
786641662c cleanup installers folder 2020-01-12 10:16:59 -06:00
sam detweiler
8380896deb Merge pull request #42 from MichMich/develop
synch with fork source
2020-01-12 10:14:44 -06:00
Michael Teeuw
1152689f34 Remove docs and link to docs.magicmirror.builders. 2020-01-12 13:01:56 +01:00
Michael Teeuw
d2afdc82f1 Merge branch 'master' into develop. 2020-01-10 22:27:44 +01:00
Michael Teeuw
5bf90ae31d Merge pull request #1872 from MichMich/2.10.1-docs
2.10.1 docs
2020-01-10 22:23:18 +01:00
Michael Teeuw
b533e3d3e1 Add install link. 2020-01-10 22:16:19 +01:00
Michael Teeuw
4d9df309c8 Use https. 2020-01-10 22:14:13 +01:00
Michael Teeuw
65126365a6 Add links to documentation site. 2020-01-10 22:11:10 +01:00
Michael Teeuw
0afe403057 Merge pull request #1861 from khassel/develop
fix run-start.sh: if running in docker-container, just start electron…
2020-01-08 16:25:57 +01:00
Michael Teeuw
d500353722 Merge pull request #1871 from shahrukh-alizai/patch-1
Remove the extra two "of" words from Manifesto content.
2020-01-08 16:24:29 +01:00
Shahrukh Khan
eea8b4dfbf Update README.md
Remove extra two "of" words
2020-01-08 18:10:36 +05:00
Karsten Hassel
20a9150ea3 fix run-start.sh: if running in docker-container, just start electron, see #1859 2020-01-03 19:17:50 +01:00
sam detweiler
c51e613568 Merge pull request #34 from MichMich/develop
sync Develop
2020-01-02 09:31:24 -06:00
Michael Teeuw
69a887fb05 Merge pull request #1851 from ZakarFin/fi-translations
Add missing translations for fi
2020-01-02 16:16:00 +01:00
Michael Teeuw
01c1d150c6 Merge branch 'develop' into fi-translations 2020-01-02 16:15:47 +01:00
Michael Teeuw
c51c09348e Merge pull request #1857 from HeikoGr/master
force declaration of public ip adress in config file (ISSUE #1852)
2020-01-02 16:14:14 +01:00
Michael Teeuw
0a4df191a7 Merge branch 'develop' into master 2020-01-02 16:13:30 +01:00
HeikoGr
760995773e Update CHANGELOG.md 2020-01-02 16:04:38 +01:00
HeikoGr
94ff8a9b04 force declaration of public ip adress in config file (ISSUE #1852) 2020-01-02 14:15:24 +00:00
Sami Mäkinen
10d5529f79 Add missing translations for fi 2020-01-02 00:04:59 +02:00
Michael Teeuw
2b511b67c3 Prepare for 2.11.0 2020-01-01 22:21:55 +01:00
Michael Teeuw
b595cdd31e Merge pull request #1850 from MichMich/develop
Version 2.10.0
2020-01-01 22:06:34 +01:00
Michael Teeuw
e64870ca58 Prepare 2.10.0 release. 2020-01-01 21:50:02 +01:00
Michael Teeuw
a40f8d5b3a Merge pull request #1848 from oemel09/fix-calendar-full-multiple-day-events
Display still ongoing multiple day events as happening today
2020-01-01 21:47:54 +01:00
Michael Teeuw
61b8871ead Update package lock. 2020-01-01 21:23:25 +01:00
Michael Teeuw
4b5a3ed44d Downgrade Electron to check Travis. 2020-01-01 21:12:31 +01:00
Michael Teeuw
7d6b7b2691 Reverse tests for debugging. 2020-01-01 21:01:17 +01:00
Michael Teeuw
3dba46b74f Downgrade test utils. 2020-01-01 20:26:16 +01:00
Michael Teeuw
2767e31a28 Downgrade Spectron 2020-01-01 20:18:48 +01:00
Michael Teeuw
40886bcf08 Remove Snyk 2020-01-01 19:48:10 +01:00
Michael Teeuw
04dde74572 Move and alias node_module. 2020-01-01 19:17:23 +01:00
Michael Teeuw
29f3ac065f Re-enable weather tests. 2020-01-01 19:03:32 +01:00
Michael Teeuw
d2b30b4f9c Merge pull request #1849 from roramirez/fix-ci
Fix CI
2020-01-01 18:59:34 +01:00
Rodrigo Ramírez Norambuena
3a42663dea Update changelog for revert commit 2019-12-31 19:40:59 +00:00
Rodrigo Ramírez Norambuena
905d0ca409 Update package-lock* 2019-12-31 19:33:21 +00:00
Rodrigo Ramírez Norambuena
7e2c78666e Revert "stop helper class being erased"
This reverts commit 2fbedca746.
2019-12-31 19:31:13 +00:00
oemel09
6a5f0225fe Display still ongoing multiple day events as happening today 2019-12-31 13:59:58 +01:00
Michael Teeuw
ddb01fca31 Merge pull request #1847 from oemel09/fix-full-day-events
Fixes some events not being recognized as full day events
2019-12-31 13:20:18 +01:00
oemel09
684a3cd49e Fixes some events not being recognized as full day events 2019-12-31 12:37:29 +01:00
Michael Teeuw
ad5e42115b Merge pull request #1846 from oemel09/fix-calendar-debug
Fixes authentication in calendar debug script
2019-12-31 11:31:09 +01:00
oemel09
2d6b8d0c47 Fixes authentication in calendar debug script 2019-12-31 11:27:15 +01:00
Michael Teeuw
61471e5449 Merge pull request #1844 from RGMTAMU/minorREADMEFix
Very minor README spelling error fix
2019-12-30 14:34:15 +01:00
Shiva
b6f7ab7a9c Very minor README spelling error fix 2019-12-29 16:38:47 -06:00
Michael Teeuw
2d061be98e Fix corrupted file. 2019-12-29 15:12:50 +01:00
Michael Teeuw
d6e97b8c76 Cleanup. 2019-12-29 14:52:26 +01:00
Michael Teeuw
9e44660746 Merge pull request #1841 from MichMich/skip-weather-tests
Skip weather tests.
2019-12-29 14:37:31 +01:00
Michael Teeuw
03e6ca58ab Link to issue. 2019-12-29 14:34:07 +01:00
sam detweiler
e884cc1f75 Merge pull request #32 from MichMich/develop
sync Develop
2019-12-29 07:33:57 -06:00
Michael Teeuw
94c63b0554 Skipping weather tests for now. 2019-12-29 14:30:12 +01:00
Michael Teeuw
c7c8c40a70 disable test 2019-12-29 13:56:53 +01:00
Michael Teeuw
91c726c706 Merge branch 'pr/SpencerCornish/1834' into develop 2019-12-29 13:51:18 +01:00
Michael Teeuw
c9805e7ac9 Updated package.lock files. 2019-12-29 13:47:05 +01:00
Michael Teeuw
a4db0e40e3 Merge pull request #1815 from sdetweil/newservermode
fix regression and add support for commented lines in config.js
2019-12-29 00:01:23 +01:00
Michael Teeuw
305b55cb2a Merge pull request #1814 from sdetweil/newscripts
updates for libc6++ on pi 0, node 10
2019-12-29 00:00:03 +01:00
Sam Detweiler
272ca1ac4f synch package-lock.json for testing 2019-12-28 15:46:10 -06:00
Sam Detweiler
bbc6a1b38f synch package-lock for testing 2019-12-28 15:39:57 -06:00
sam detweiler
525c235d3b Merge pull request #31 from MichMich/develop
synch to Develop
2019-12-28 15:01:54 -06:00
Michael Teeuw
0e93713464 Merge pull request #1826 from sdetweil/fixcompliments
Fix compliments to support \n
2019-12-28 22:01:16 +01:00
sam detweiler
8f60e103f9 Merge branch 'develop' into fixcompliments 2019-12-28 14:58:01 -06:00
Michael Teeuw
9cc702241d Merge pull request #1827 from sdetweil/fix_helper
Fix helper being erased accidentally
2019-12-28 21:44:10 +01:00
sam detweiler
0d61c44232 Merge branch 'develop' into newscripts 2019-12-28 14:42:06 -06:00
sam detweiler
9a8faac316 Merge branch 'develop' into fix_helper 2019-12-28 14:36:49 -06:00
Michael Teeuw
05f710cb5c Merge pull request #1838 from tbouron/fix/module-header
Module header updates correctly, if a module need to dynamically show/hide its header based on a condition
2019-12-28 19:41:42 +01:00
Michael Teeuw
c6184769e7 Merge pull request #1836 from akraus53/patch-2
Added a padding between days in dateheader mode
2019-12-28 19:41:15 +01:00
Michael Teeuw
515d1bd920 Merge branch 'develop' into fixcompliments 2019-12-28 19:38:18 +01:00
Michael Teeuw
b19cb17bba Merge branch 'develop' into newservermode 2019-12-28 19:37:41 +01:00
Michael Teeuw
c1e808bce6 Merge pull request #1806 from sdetweil/newElectron
New electron version
2019-12-28 19:35:57 +01:00
Thomas Bouron
d8b7292d4b Fix module header update if using customising from module.getHeaders() 2019-12-26 14:07:13 +00:00
Sam Detweiler
edd5e2f5bc move lxsession screensaver checking to last, some systems still have the folder but don't use it 2019-12-24 06:55:12 -06:00
Alexander Kraus
efc6cb73b2 Added my contribution to the changelog 2019-12-20 15:22:14 +01:00
Alexander Kraus
ecd79dc34b Added a padding between days in dateheader mode 2019-12-20 15:20:12 +01:00
Spencer Cornish
cdfc8b825d Changelog 2019-12-19 21:11:57 -07:00
Spencer Cornish
301344c96d Update unsecure dependencies 2019-12-19 21:02:39 -07:00
sam detweiler
5279995c3b Merge branch 'develop' into newservermode 2019-12-13 08:03:06 -06:00
Sam Detweiler
5176b06b59 add check for root user and abort 2019-12-13 08:01:32 -06:00
Sam Detweiler
ed61ac624d http default if no address is 0.0.0.0, not localhost, hard code localhost as per readme 2019-12-10 12:15:30 -06:00
Sam Detweiler
4da6e3ecee add test for error on 200 rc test path 2019-12-10 11:29:26 -06:00
Sam Detweiler
9e5561936a Merge branch 'newElectron' of https://github.com/sdetweil/MagicMirror into newElectron 2019-12-10 10:54:18 -06:00
Sam Detweiler
843cd0eff6 change spectron version to match doc, update locak file 2019-12-10 10:53:41 -06:00
sam detweiler
6b6ee934a1 Merge branch 'develop' into newElectron 2019-12-10 08:31:50 -06:00
Sam Detweiler
aea57ffaf4 add new run_start.sh script 2019-12-10 08:29:18 -06:00
Sam Detweiler
87b48661fa remove forced npm install 2019-12-09 16:41:56 -06:00
Sam Detweiler
556fa44858 move travis to node 10 , latest npm 2019-12-09 16:26:49 -06:00
Sam Detweiler
1c3e196508 move travis to node 10 and latest npm 2019-12-09 16:24:16 -06:00
Sam Detweiler
9b6812ad0c add package-lock file 2019-12-09 11:15:50 -06:00
Sam Detweiler
b7944c7fa4 add changelog 2019-12-09 10:36:21 -06:00
Sam Detweiler
2fbedca746 stop helper class being erased 2019-12-09 10:33:35 -06:00
Sam Detweiler
340d04a48c add changelog entry 2019-12-09 09:52:15 -06:00
Sam Detweiler
460a383ffc add changelog 2019-12-09 09:46:45 -06:00
Sam Detweiler
52c4e3a256 add changelog update 2019-12-09 09:43:32 -06:00
sam detweiler
4338f11eb1 Merge branch 'develop' into newscripts 2019-12-09 09:40:06 -06:00
Sam Detweiler
42bab052e0 fix comment 2019-12-08 10:07:55 -06:00
Sam Detweiler
0cb377618e add support for sequential compliments usage 2019-12-08 09:28:50 -06:00
Sam Detweiler
5e4d25b957 add support for newline (\n) in compliment text 2019-12-08 08:50:00 -06:00
Sam Detweiler
153d1853fa add apt get upgrade to actually upgrade files, as OS repos are lagging 2019-12-08 08:46:41 -06:00
Sam Detweiler
22a3448461 latest fixes for install and pm2 2019-12-08 08:40:01 -06:00
Sam Detweiler
2cad869680 latest fixes for install and pm2 2019-12-08 08:35:50 -06:00
Your Name
bc912a8ea4 Merge branch 'newscripts' of https://github.com/sdetweil/MagicMirror into newscripts 2019-11-27 08:38:12 -06:00
Your Name
db9176c284 fix pm2 install needing sudo 2019-11-27 08:37:51 -06:00
Sam Detweiler
06308210c0 add support for secured apt-get repositories 2019-11-23 06:57:10 -06:00
Sam Detweiler
63d9904370 regression checking for macOS 2019-11-22 06:30:46 -06:00
Sam Detweiler
caaeff5cb7 add support for commented lines in config.js 2019-11-22 06:22:21 -06:00
Sam Detweiler
d8c93d3455 Merge branch 'newscripts' of https://github.com/sdetweil/MagicMirror into newscripts 2019-11-22 06:18:31 -06:00
Sam Detweiler
cb28e5fddc watch out for commented lines in config 2019-11-22 06:18:04 -06:00
Sam Detweiler
7d7ec1a00b updates for libc6++ on pi 0, node 10 2019-11-21 22:32:48 -06:00
Sam Detweiler
a5bc8dfa3f add package.json to update 2019-11-19 19:50:46 -06:00
sam detweiler
d74f055180 Merge pull request #28 from MichMich/develop
sync changes
2019-11-19 17:15:00 -08:00
Michael Teeuw
73be6c35a6 Merge pull request #1808 from FritzJay/develop
Use config.decimalSymbol when displaying the predicted amount of rain in weatherforecast
2019-11-13 08:01:42 +01:00
Fritz Jay
24f74e1400 Fixed spelling error. 2019-11-12 19:30:42 -08:00
Fritz Jay
8900e069f3 Updated changelog 2019-11-12 19:26:38 -08:00
Fritz Jay
1dfec119bb Fixed bug that was causing predicted amount of rain value to use DOT as a decimal separator regardless of the decimalSymbol config value. 2019-11-12 18:16:55 -08:00
Sam Detweiler
9e23d35f01 update elecgtron version 2019-11-08 13:20:39 -08:00
Sam Detweiler
cd2b240308 upgrade electron 2019-11-08 11:43:17 -08:00
Michael Teeuw
749f366a4a Merge pull request #1796 from sdetweil/fix-untrack
Fix untrack-css on MacOS
2019-10-27 15:27:29 +01:00
Sam Detweiler
420aaa92fa fix for MacOS 2019-10-27 09:14:55 -05:00
Sam Detweiler
985698bbc3 fix for no 'Xorg' process on MacOS 2019-10-27 09:13:44 -05:00
Michael Teeuw
f9c9139f20 Merge pull request #1790 from sdetweil/patch-1
left electron left in dependencies section vs pr 1788
2019-10-25 16:38:35 +02:00
Michael Teeuw
f308e7541f Merge pull request #1791 from sdetweil/newscripts
New scripts cleanuo
2019-10-25 16:09:14 +02:00
Sam Detweiler
cb7ccd7854 update readme and upgrade script to work from website, fix tabs in config sample 2019-10-25 08:46:41 -05:00
Sam Detweiler
a4953028d0 remove electron from dependencies section 2019-10-25 08:13:25 -05:00
sam detweiler
3d6485588d pr merge order left electron in dependencies section 2019-10-25 07:37:21 -05:00
Michael Teeuw
51bb9fede7 Merge pull request #1789 from sdetweil/newscripts
New scripts for install, update and pm2 config
2019-10-25 14:26:13 +02:00
Michael Teeuw
269c429959 Merge branch 'develop' into newscripts 2019-10-25 14:25:57 +02:00
Michael Teeuw
fcdc84a12a Merge pull request #1788 from sdetweil/newservermode
New servermode
2019-10-25 14:24:05 +02:00
Michael Teeuw
ecdd9734eb Merge branch 'develop' into newservermode 2019-10-25 14:23:50 +02:00
Michael Teeuw
84fc2c65af Merge pull request #1784 from MichMich/dependabot/npm_and_yarn/nwmatcher-1.4.4
Bump nwmatcher from 1.4.3 to 1.4.4
2019-10-25 14:21:31 +02:00
Sam Detweiler
c8849a17b6 add detection of xwindows running 2019-10-25 06:22:10 -05:00
Sam Detweiler
d8b49218e9 Merge branch 'newscripts' of https://github.com/sdetweil/MagicMirror into newscripts 2019-10-24 22:14:19 -05:00
Sam Detweiler
e95023e8cc remove forced arch parm for armv6 to armv7, doesn't work 2019-10-24 22:13:46 -05:00
sam detweiler
878710e2cf Add text for new upgrade script 2019-10-24 14:21:38 -05:00
Sam Detweiler
0677d0a810 add changelog info 2019-10-24 09:36:15 -05:00
Sam Detweiler
9c98fea8f4 add new upgrade/pm2 scripts, update installer script 2019-10-24 09:33:34 -05:00
Sam Detweiler
e958f33450 add support for armv6l using serveronlymode, make serveronly config option, electron install optional 2019-10-24 09:20:33 -05:00
sam detweiler
937080b011 Merge pull request #19 from MichMich/master
catch up to 2.9
2019-10-24 07:06:53 -05:00
Michael Teeuw
aee5803dd2 Merge pull request #1773 from qistoph/timestamp_log
Timestamp log
2019-10-23 13:07:06 +02:00
Chris van Marle
f1f394b871 Add merge to package-lock to fix Travis fail 2019-10-23 10:44:30 +00:00
Chris van Marle
81a32b56f0 Fix TravisCI error 2019-10-23 10:16:01 +00:00
Chris van Marle
a6aae70a55 Add UTC timestamp to console log 2019-10-23 10:16:01 +00:00
dependabot[bot]
823eb23773 Bump nwmatcher from 1.4.3 to 1.4.4
Bumps [nwmatcher](https://github.com/dperini/nwmatcher) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/dperini/nwmatcher/releases)
- [Commits](https://github.com/dperini/nwmatcher/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2019-10-22 17:12:07 +00:00
Michael Teeuw
1ff51822df Prepare 2.10.0-develop 2019-10-01 19:47:40 +02:00
Michael Teeuw
500147e130 Merge pull request #1776 from MichMich/develop
v2.9.0
2019-10-01 19:45:34 +02:00
Michael Teeuw
d90de18d99 Prepare 2.9.0 2019-10-01 19:36:51 +02:00
Michael Teeuw
ba4f48662f Merge pull request #1770 from buxxi/develop
Changes to the clock module regarding the notifications sent.
2019-10-01 18:14:41 +02:00
buxxi
d208437c05 Changes to the clock module regarding the notifications sent. Disable sending of CLOCK_SECOND when displaySeconds not set. Avoid drifting by calculating the interval each time and use setTimeout instead of setInterval. Make sure the values sent with CLOCK_SECOND and CLOCK_MINUTE has the correct values instead of starting at 00:00 on startup 2019-09-22 17:33:01 +02:00
Michael Teeuw
01faa2e1d7 Merge pull request #1768 from fewieden/feature/automated-forecast-tests
Automated weather forecast tests
2019-09-13 18:57:26 +02:00
Felix Wiedenbach
c630c387d6 it should render colored rows 2019-09-13 17:06:58 +02:00
Felix Wiedenbach
a774718607 it should render custom table class 2019-09-13 16:21:12 +02:00
Felix Wiedenbach
9430c70d0d it should render fading rows in weather forecast 2019-09-13 15:44:38 +02:00
Felix Wiedenbach
f3e893fddb it should render min and max temperatures 2019-09-13 15:08:44 +02:00
Felix Wiedenbach
11e144ca64 it should render days and icons in weather forecast 2019-09-13 14:58:04 +02:00
Felix Wiedenbach
fbceab707e draft for default weather forecast test cases 2019-09-13 13:54:55 +02:00
Felix Wiedenbach
5b2efc43b9 default weather forecast test config 2019-09-13 13:54:17 +02:00
Felix Wiedenbach
8d85d1aa2d move mocks to separate directory for better overview 2019-09-13 13:53:15 +02:00
Michael Teeuw
b469fc7577 Merge pull request #1755 from buxxi/develop
Fixing weatherforecast module not displaying rain amount if using fal…
2019-09-11 16:51:04 +02:00
Michael Teeuw
9db54831c8 Merge pull request #1766 from fewieden/feature/automated-weather-tests
Automated tests for new weather module
2019-09-11 16:45:28 +02:00
Michael Teeuw
9b88bde09a Merge pull request #1767 from roramirez/prevent-error-404-test-vendor
Prevent error CI build for 404 Test vendors
2019-09-11 16:44:24 +02:00
Felix Wiedenbach
aad03a74c5 fix test path and eslint 2019-09-11 15:58:51 +02:00
fewieden
55eb6e2e5c Add changelog entry 2019-09-11 13:51:19 +02:00
fewieden
ca07355873 adjust tests to new translations 2019-09-11 13:30:54 +02:00
fewieden
11a59e26b2 update package locks 2019-09-11 13:13:08 +02:00
fewieden
ec6d9e3521 Merge branch 'develop' into feature/automated-weather-tests
# Conflicts:
#	modules/default/weather/weather.js
#	package-lock.json
#	package.json
2019-09-11 13:07:31 +02:00
fewieden
230accd31e fix current weather tests 2019-09-11 12:59:55 +02:00
fewieden
a24a4a747e current weather tests 2019-09-11 12:27:06 +02:00
Rodrigo Ramírez Norambuena
1e97b5c27a Prevent error CI build for 404 Test vendors 2019-09-10 18:24:45 -03:00
buxxi
a314ea1aa3 Fixing weatherforecast module not displaying rain amount if using fallback endpoint 2019-08-18 12:44:28 +02:00
Michael Teeuw
a77128d5f7 Merge pull request #1752 from roramirez/mode-en.json-translation
Revert change mode file en.json for translations
2019-08-16 13:18:01 +02:00
Michael Teeuw
1b2673367e Merge pull request #1753 from roramirez/tests-404-vendors
Tests 404 vendors
2019-08-16 13:17:46 +02:00
Rodrigo Ramírez Norambuena
ce10e91a60 Merge remote-tracking branch 'origin/develop' into tests-404-vendors 2019-08-09 01:47:35 -04:00
Rodrigo Ramírez Norambuena
5244b37d2c Revert change mode file en.json for translations
This change it done in commit c80e04fe8d
and this patch revert to old status for this file.
2019-08-09 01:29:01 -04:00
Michael Teeuw
1239c6716b Merge pull request #1749 from putera/develop
Adding a Malay translations
2019-08-06 07:48:03 +02:00
Zulkifli Mohamed
67f6258ab0 Adding a Malay translations 2019-08-06 08:39:57 +08:00
Zulkifli Mohamed
9f63172b43 Adding a Malay translations 2019-08-06 08:36:39 +08:00
Michael Teeuw
bd8bfeb525 Merge pull request #1745 from roramirez/update-year-license
Update year Copyright License
2019-08-03 18:47:28 +02:00
Michael Teeuw
4918c4ef4b Merge pull request #1744 from roramirez/custom-css-step-1
Skip from worktree the css/custom.css:
2019-08-03 18:47:04 +02:00
Michael Teeuw
00d9ea9344 Merge pull request #1743 from roramirez/lint
linter fixes
2019-08-03 18:45:58 +02:00
Michael Teeuw
33537cde76 Merge pull request #1742 from roramirez/es-update
Add PRECIP for the Spanish translation
2019-08-03 18:45:27 +02:00
Michael Teeuw
3d5db5c9ca Merge pull request #1741 from roramirez/remove-comment-bash-lines
installer: Remove comment lines added in PR #1715
2019-08-03 18:44:58 +02:00
Michael Teeuw
fdf339514d Merge pull request #1748 from roramirez/fix-build
Fix Build Failed in Travis CI:
2019-08-03 18:32:01 +02:00
Rodrigo Ramírez Norambuena
937c4e485a Merge remote-tracking branch 'origin/develop' into remove-comment-bash-lines 2019-08-02 00:48:44 -04:00
Rodrigo Ramírez Norambuena
837c060e1f Merge remote-tracking branch 'origin/develop' into custom-css-step-1 2019-08-02 00:47:24 -04:00
Rodrigo Ramírez Norambuena
00bacd7dde Merge remote-tracking branch 'origin/develop' into es-update 2019-08-02 00:46:54 -04:00
Rodrigo Ramírez Norambuena
781031775e Merge remote-tracking branch 'origin/develop' into lint 2019-08-02 00:46:32 -04:00
Rodrigo Ramírez Norambuena
97aee3d375 Merge remote-tracking branch 'origin/develop' into update-year-license 2019-08-02 00:46:06 -04:00
Rodrigo Ramírez Norambuena
34698751f2 Fix Build Failed in Travis CI:
This commit set trusty as image to use and revert this commit changes

Add xvfb as service: 3c31460f2f
Remove failing script: d5cb60b19c
2019-08-02 00:31:43 -04:00
Michael Teeuw
3c31460f2f Add xvfb as service. 2019-07-31 09:53:46 +02:00
Michael Teeuw
d5cb60b19c Remove failing script. 2019-07-31 09:49:22 +02:00
Rodrigo Ramírez Norambuena
3a7cfe3208 Enable Test e2e/vendor_spec.js 2019-07-26 02:21:56 -04:00
Rodrigo Ramírez Norambuena
f079cdad64 Merge remote-tracking branch 'origin/develop' into tests-404-vendors 2019-07-26 02:19:10 -04:00
Rodrigo Ramírez Norambuena
2822303138 Skip from worktree the css/custom.css:
On the next release the css/custom.css will rename to
css/custom.css.sample

This change run git instructions to detach the file from own local
repository. This instructions are called in untrack-css.sh file from
run-start.sh and npm postinstall step

Reference #1540
2019-07-26 02:12:10 -04:00
Rodrigo Ramírez Norambuena
e38de75520 Update year Copyright License 2019-07-26 02:04:38 -04:00
Rodrigo Ramírez Norambuena
2723604d3e installer: Remove comment lines added in PR #1715 2019-07-26 01:25:54 -04:00
Rodrigo Ramírez Norambuena
82ee051c1a linter fixes 2019-07-26 01:25:26 -04:00
Rodrigo Ramírez Norambuena
7bdf49b7e0 Add PRECIP for the Spanish translation 2019-07-26 01:24:59 -04:00
Michael Teeuw
32521aba6b Merge pull request #1724 from vincep5/develop
Fix for weather module not refreshing data after exception
2019-07-11 20:04:30 +02:00
vincep5
819c4cde1c Fix for weather module not refreshing data after exception 2019-07-11 12:49:24 -05:00
Michael Teeuw
776c486b1a Merge pull request #1720 from nischi/master
Fixing send notification in newsfeed module
2019-07-09 10:43:09 +02:00
Michael Teeuw
bcd97120a4 Merge branch 'develop' into master 2019-07-09 10:33:29 +02:00
Thierry Nischelwitzer
312bfb8509 add changes to changelog 2019-07-09 10:24:43 +02:00
Thierry Nischelwitzer
11c9a50931 send NEWS_FEED notification also for the first newsmessage which are shown 2019-07-09 10:20:02 +02:00
Thierry Nischelwitzer
94c0656bcd update to 2.8 2019-07-02 19:38:17 +02:00
Michael Teeuw
13313d0b25 Fix changelog. 2019-07-01 20:27:37 +02:00
Michael Teeuw
3a20db1d76 Merge pull request #1716 from sdetweil/newupdater
fix updatenotification module to not crash
2019-07-01 20:25:59 +02:00
Michael Teeuw
00148b4cc8 Prepare 2.9.0-develop 2019-07-01 20:22:52 +02:00
Michael Teeuw
a31546b1ff Merge pull request #1717 from MichMich/develop
Release 2.8.0
2019-07-01 20:11:40 +02:00
Michael Teeuw
361b62b8e2 Add update info. 2019-07-01 20:05:28 +02:00
sam detweiler
37327b77a7 Merge branch 'develop' into newupdater 2019-07-01 12:56:01 -05:00
Sam Detweiler
7ef8a5bb11 fix conflict with develop branch 2019-07-01 12:45:40 -05:00
Sam Detweiler
11cfb8af32 Merge branch 'newupdater' of https://github.com/sdetweil/MagicMirror into newupdater
pull update
2019-07-01 12:36:52 -05:00
Sam Detweiler
7315f7d283 fix conflict with master repo develop branch 2019-07-01 12:35:47 -05:00
Michael Teeuw
7d58eb718e Prepare release 2.8.0 2019-07-01 19:06:26 +02:00
Michael Teeuw
651be76776 Merge pull request #1715 from sdetweil/newinstaller
update installer to handle non-pi and other issues
2019-07-01 18:36:08 +02:00
sam detweiler
4a5c6f1d39 Update CHANGELOG.md
add info on updatenotification module improvements
2019-06-30 07:18:45 -05:00
sam detweiler
5745d71d6a Update CHANGELOG.md
add info on installer changes
2019-06-30 06:57:41 -05:00
Sam Detweiler
db62b7421a update installer for npm missing, non-PI platforms, mac option on pm2 install 2019-06-29 16:02:44 -05:00
Sam Detweiler
4084c57789 fix updatenotification to not crash 2019-06-29 15:59:03 -05:00
Michael Teeuw
f90bec985a Fix merge issue. 2019-06-27 09:29:01 +02:00
Michael Teeuw
90f911c529 Fix Merge Issue 2019-06-27 09:27:24 +02:00
Michael Teeuw
6c88b106db Merge pull request #1713 from alltopafi/weather-module-location-header
allow location property in config,js to be used as header
2019-06-27 09:24:28 +02:00
Michael Teeuw
cef69d1b97 Merge pull request #1711 from NiekertDev/patch-1
Fix missing '#' (pound) in link
2019-06-27 09:23:10 +02:00
Jesse Alltop
f76a7fb331 allow location property in config,js to be used as header 2019-06-26 19:31:16 -05:00
Niekert
3e7b8b0663 Fix missing '#' (pound) in link 2019-06-24 17:41:51 +02:00
Josef Spitzlberger
a6eb3ad037 added three more class names to 'newsfeed.js'
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
2019-06-21 13:08:36 +02:00
Josef Spitzlberger
9468749384 added three class names
in order to design the news article better with css, three more class-names were introduced: newsfeed-desc, newsfeed-desc, newsfeed-desc
2019-06-21 13:05:40 +02:00
Michael Teeuw
37417fa1bb Merge pull request #1706 from vincep5/develop
Adding sunrise/sunset to weathergov
2019-06-18 14:06:52 +02:00
vincep5
217146351e changelog notes 2019-06-17 10:25:33 -05:00
vincep5
818ec33cef Adding sunrise/sunset to weathergov 2019-06-17 10:20:49 -05:00
Michael Teeuw
cd1671830a Merge pull request #1704 from Hg347/develop
Develop
2019-06-15 13:27:21 +02:00
Christoph Hagedorn
a5fca87dd0 updated info: fixed race condition on module update 2019-06-15 11:49:57 +02:00
Christoph Hagedorn
f06ce55626 Merge remote-tracking branch 'upstream/develop' into develop 2019-06-15 11:33:44 +02:00
Christoph Hagedorn
853085e755 added null check for moduleWrapper
(fixes race condition if element is updated)
2019-06-15 11:32:03 +02:00
Michael Teeuw
2b7accaf68 Merge pull request #1703 from rejas/fix_eslint_errors_automatically
Fix tests
2019-06-14 14:39:12 +02:00
Veeck
5533d93172 Update changelog 2019-06-14 14:06:36 +02:00
Veeck
f0e8c865fe Fix markdown error 2019-06-14 14:03:58 +02:00
Veeck
36400c0a83 Fix some eslint errors from previous merges 2019-06-14 14:03:07 +02:00
Veeck
c5383557b5 Pass fix options to eslint 2019-06-14 14:02:48 +02:00
Michael Teeuw
b645007884 Updated the fetchedLocationName (See PR: #1702) 2019-06-14 13:42:59 +02:00
Michael Teeuw
63ac137206 Merge branch 'mattdb-calendar-rrule' into develop 2019-06-14 13:32:20 +02:00
Michael Teeuw
808cbf8e0b Fix Typecheck. 2019-06-14 13:32:07 +02:00
Michael Teeuw
8ed77ba0c7 Merge 2019-06-14 13:31:59 +02:00
Michael Teeuw
66c74c51e4 Merge branch 'rejas-cleanups' into develop 2019-06-14 13:19:43 +02:00
Michael Teeuw
7a272ef0ab Merge conflict. 2019-06-14 13:19:29 +02:00
Michael Teeuw
60b817ec8e Merge branch 'cybex-dev-develop' into develop 2019-06-14 13:05:36 +02:00
Michael Teeuw
a41ecaf7cc Merge 2019-06-14 13:05:22 +02:00
Matt Bauer
d41afa0e53 Calendar fetch error is still a loading result
Also log error on node side as well.
2019-06-13 15:52:49 -05:00
Matt Bauer
a6284e05e5 Update rrule and request dependencies for calendar’s vendored ical.js
rrule-alt has not been updated in some time, while the main rrule has. ical.js is using updated rrule. Getting rid of rrule-alt would affect some third-party modules, however, so we should keep it around for now at least.
2019-06-13 14:45:32 -05:00
Matt Bauer
e56f61441d Repeating event handling “robustified” 2019-06-13 13:44:54 -05:00
Matt Bauer
7b4b7dffa2 Update calendar’s vendored ical.js 2019-06-13 13:44:54 -05:00
Michael Teeuw
77a214ef9c Merge pull request #1695 from Jason-Cooke/patch-2
docs: fix typo
2019-06-13 20:16:15 +02:00
Michael Teeuw
cf2723aafb Merge pull request #1699 from Hg347/calendar-1696
fixed calendar, issue 1696, ics file start date is not date type
2019-06-13 20:15:53 +02:00
Christoph Hagedorn
499e99cfc5 fixed url 2019-06-13 18:11:41 +02:00
Michael Teeuw
a7b83e9fe3 Merge pull request #1637 from maloakes/master
Add Weather provider UK Met Office
2019-06-13 16:51:09 +02:00
Christoph Hagedorn
964504b9c3 curr.exdates[i] might not be a date, so toISOString() may fail too 2019-06-11 23:24:03 +02:00
Christoph Hagedorn
ec65e66c58 added fixed issue in changelog 2019-06-11 22:43:48 +02:00
Christoph Hagedorn
e694b080be curr.start is not always a date type (depends on ics file). A type check
has been added.
2019-06-09 17:46:48 +02:00
Malcolm Oakes
70894b3938 Corrected merge problem 2019-06-08 15:34:37 +01:00
Malcolm Oakes
fb7115fc13 Merge remote-tracking branch 'upstream/develop' 2019-06-07 16:44:42 +01:00
Malcolm Oakes
a619fc4fef Allow temp and wind units to be specified separately if required. 2019-06-07 15:27:08 +01:00
Jason Cooke
7c6c5fd06f docs: fix typo 2019-06-07 10:34:55 +12:00
Malcolm Oakes
2970568eab Merge branch 'master' of https://github.com/maloakes/MagicMirror
Merge latest from github
2019-06-06 10:59:47 +01:00
rejas
62cb3a610e Actually only test json files in jsonlint, rename stylelintrc for clarity 2019-06-05 20:33:53 +02:00
rejas
f600c163ca Fix intendation 2019-06-05 18:30:04 +02:00
rejas
77cb68e5ac Remove unnecessary entry 2019-06-05 18:29:51 +02:00
rejas
c6314576aa Fix duplicate json entry 2019-06-05 17:04:51 +02:00
rejas
515c183070 Fix a comparison that was an assignement 2019-06-05 17:01:54 +02:00
rejas
63b9c0e6b8 More dependency updates and cleanup of old ones 2019-06-05 16:54:32 +02:00
rejas
84893b1664 Upgrade markdown lint to latest 2019-06-05 10:26:20 +02:00
rejas
835668d96d Add eslint semi rule 2019-06-05 10:23:58 +02:00
rejas
2bce15dc6e Remove multiple-empty-lines 2019-06-05 10:03:28 +02:00
rejas
8f1a212b52 More typo fixes 2019-06-05 09:46:59 +02:00
rejas
5c08bde0fa More == -> === and != -> !== fixes 2019-06-05 09:32:10 +02:00
rejas
98a84c031e Better fix for translator comparison 2019-06-05 08:55:17 +02:00
rejas
ea1715384e Revert "Revert "Fix some == with ===""
This reverts commit d9a4ee4f65.
2019-06-05 08:48:22 +02:00
rejas
d9a4ee4f65 Revert "Fix some == with ==="
This reverts commit 5d39d85215.
2019-06-04 11:04:47 +02:00
rejas
62017c4661 Update changelog 2019-06-04 10:43:16 +02:00
rejas
702b98f510 Cleanup imports 2019-06-04 10:43:06 +02:00
rejas
69aafd7d6a Fix missing ; and == and some missing vars 2019-06-04 10:19:25 +02:00
rejas
c1559dd8c8 More spelling fixes 2019-06-04 10:15:50 +02:00
rejas
4df1895560 Fix badge for travis which moved to .com from .org 2019-06-04 10:14:37 +02:00
rejas
cac92da6e4 Remove unused dependency, move mocha-logger to dev 2019-06-04 10:13:58 +02:00
rejas
5d39d85215 Fix some == with === 2019-06-04 09:51:51 +02:00
rejas
99b4c43fd5 Fix typos and some whitespaces 2019-06-04 09:33:53 +02:00
Charles Dyason
b2f59d6813 Added clock notifications for elapsed time.
Added notifications to default `clock` module to broadcast:
 - `CLOCK_SECOND` for a clock second, and 
 - `CLOCK_MINUTE` for a clock minute having elapsed.

Each notification is broadcasted with the corresponding value i.e. `CLOCK_SECOND` -> `30` and `CLOCK_MINUTE` -> `5` .
2019-06-03 14:01:27 +02:00
Charles Dyason
c7d79bb893 Updated config.js.sample with new configuration entries
Added `broadcastNewsFeeds: true` and `broadcastNewsUpdates: true` to the `config.js.sample` file
2019-05-31 19:45:58 +02:00
Charles Dyason
aa80c468c4 Added broadcasting of news feeds with incremental updates
Added ability to enable broadcasting of news feed items with `NEWS_FEED` notification and broadcasting updated news feed items with `NEWS_FEED_UPDATE` to other modules. This is merged into the default `newsfeed` module.

One can set ability to broadcast the whole news feed or broadcast only updated news feed items.
2019-05-31 16:37:47 +02:00
Charles Dyason
6008cba2db Minor typo corrections 2019-05-31 16:17:09 +02:00
Michael Teeuw
caf56671dc Merge pull request #1682 from kolbyjack/update/optimize-clock-update
Only call updateDom in clock.js when the content has changed
2019-05-19 07:34:05 +02:00
Jon Kolb
44eccf5ee4 Only call updateDom in clock.js when the content has changed 2019-05-18 20:02:22 -04:00
Michael Teeuw
8f96e4847c Merge pull request #1674 from eouia/develop
allow html5 autoplay
2019-05-17 16:29:48 +02:00
Michael Teeuw
ae3e307f33 Merge pull request #1677 from mattdb/develop
Calendar: only slice multi-day events when they actually span midnight
2019-05-17 16:28:30 +02:00
Michael Teeuw
3fe0c758ed Merge pull request #1678 from vincep5/develop
Fix City List
2019-05-17 16:27:18 +02:00
vincep5
7240fb32d2 update city list url 2019-05-14 15:00:30 -05:00
vin p
e23a3461ba Merge pull request #6 from MichMich/develop
Develop
2019-05-14 14:45:48 -05:00
Matt Bauer
727eb0cfd7 Calendar: only slice multi-day events when they actually span midnight 2019-05-14 10:08:53 -05:00
Seongnoh Sean Yi
3796076360 change Squotes to Dquotes 2019-05-13 23:24:59 +02:00
Seongnoh Sean Yi
ef9576f8c4 Fixed:allowance HTML5 autoplay
From commit: 94fc4cb8a2
2019-05-13 21:26:28 +02:00
Seongnoh Sean Yi
94fc4cb8a2 allow html5 autoplay policy
From Chrome 66, autoplay policy is changed. This 1 line can help to play html5 audio and video without user-gesture-allowance in MagicMirror
2019-05-13 21:19:50 +02:00
Michael Teeuw
ccb248db91 Create stale.yml 2019-05-07 21:09:11 +02:00
Michael Teeuw
e7de447725 Merge pull request #1655 from spitzlbergerj/master
default module calendar - added config option nextDaysRelative
2019-05-07 20:49:43 +02:00
Michael Teeuw
7ff5429cb7 Remove newline. 2019-05-07 20:41:02 +02:00
Michael Teeuw
17c581b4aa Update changelog. 2019-05-07 20:35:29 +02:00
Josef Spitzlberger
41e5c2939f added config option nextDaysRelative
added configuration option nextDaysRelative to always display today's and tomorrow's appointments in relative mode, even if timeformat is set to absolute
2019-05-07 20:35:28 +02:00
Josef Spitzlberger
7e2ab51298 added Config Option nextDaysRelative
added configuration option nextDaysRelative to always display today's and tomorrow's appointments in relative mode, even if timeformat is set to absolute
2019-05-07 20:34:35 +02:00
Michael Teeuw
03f917fd9c Update changelog. 2019-05-07 20:31:41 +02:00
Josef Spitzlberger
d24e10a728 added config option nextDaysRelative
added configuration option nextDaysRelative to always display today's and tomorrow's appointments in relative mode, even if timeformat is set to absolute
2019-05-07 20:18:32 +02:00
Josef Spitzlberger
a17ac1c16e added Config Option nextDaysRelative
added configuration option nextDaysRelative to always display today's and tomorrow's appointments in relative mode, even if timeformat is set to absolute
2019-05-07 20:18:08 +02:00
Michael Teeuw
dd6b972be4 Merge pull request #1628 from kolbyjack/feature/calendar-past-events
Add includePastEvents global and calendar-specific settings
2019-05-07 20:12:37 +02:00
Michael Teeuw
7d0c9ba0d9 Merge pull request #1666 from kevbodavidson/patch-1
Update config.js.sample
2019-05-07 20:07:32 +02:00
Michael Teeuw
6fa211634f Merge branch 'develop' into patch-1 2019-05-07 20:07:17 +02:00
Michael Teeuw
1ca24c7f38 Merge branch 'patch-1' of https://github.com/kevbodavidson/magicmirror into pr/kevbodavidson/1666 2019-05-07 20:06:06 +02:00
Michael Teeuw
bcfbccae59 Update changelog. 2019-05-07 20:06:03 +02:00
kevbodavidson
20b75ce6ed Update config.js.sample 2019-05-07 20:04:55 +02:00
Michael Teeuw
2ea15d7bf5 Merge pull request #1660 from magic21nrw/master
Update ical.js #1631
2019-05-07 19:53:04 +02:00
Michael Teeuw
18e14c597f Merge branch 'master' of https://github.com/magic21nrw/magicmirror-1 into pr/magic21nrw/1660 2019-05-07 19:46:26 +02:00
Michael Teeuw
06d75999d7 Update changelog. 2019-05-07 19:46:23 +02:00
magic21nrw
7047a7cae6 Update ical.js
Fixed Bug with more than one calendar.
2019-05-07 19:45:28 +02:00
Michael Teeuw
20d2124867 Merge pull request #1661 from vincep5/develop
Update Feels to Feels like
2019-05-07 19:41:01 +02:00
kevbodavidson
3c7a85361e Update config.js.sample 2019-04-24 17:19:47 -04:00
vincep5
1ffbbdac99 Update English Feels to Feels like 2019-04-17 21:16:36 -05:00
vin p
eeccca8842 Merge pull request #5 from MichMich/develop
Develop
2019-04-17 21:08:04 -05:00
magic21nrw
e2d2dbd2ba Update ical.js
Fixed Bug with more than one calendar.
2019-04-17 20:05:33 +02:00
Jon Kolb
c61f0409fb Rename includePastEvents calendar config option to broadcastPastEvents 2019-04-17 08:16:04 -04:00
Jon Kolb
806be39a6d Add includePastEvents global and calendar-specific settings 2019-04-17 08:13:51 -04:00
Michael Teeuw
6170b0d059 Merge pull request #1653 from darkniki/patch-2
Update CHANGELOG.md
2019-04-17 13:51:49 +02:00
Michael Teeuw
bca838495e Merge pull request #1652 from michaelarnauts/1651-calendar-fix
Fix sliceMultiDayEvents so it respects maximumNumberOfDays
2019-04-17 13:51:07 +02:00
Michael Teeuw
e31a747250 Merge pull request #1636 from darkniki/patch-1
Update ru.json
2019-04-17 13:49:46 +02:00
Michael Teeuw
4cf430e146 Merge pull request #1646 from michaelarnauts/patch-3
sliceMultiDayEvents is false by default
2019-04-17 12:17:44 +02:00
darkniki
ef554cf6ec Update CHANGELOG.md 2019-04-11 14:46:32 +03:00
Thierry Nischelwitzer
fcd91daee6 Merge remote-tracking branch 'upstream/master'
Update MagicMirror
2019-04-10 18:07:55 +02:00
Michaël Arnauts
396c78b46a Changelog 2019-04-10 10:35:11 +02:00
Michaël Arnauts
4677a3fd89 Fix many issues with sliceMultiDayEvents 2019-04-10 10:31:55 +02:00
Michael Teeuw
834ab5c6b9 Merge pull request #1642 from michaelarnauts/patch-2
Handle SIGTERM messages
2019-04-09 09:53:16 +02:00
Michael Teeuw
1599e8f7ff Merge pull request #1647 from retroflex/develop
Added option to show location of calendar events
2019-04-09 09:52:39 +02:00
Michael Teeuw
7430704002 Merge pull request #1635 from ZakarFin/translations
Add translations for FI week/feels
2019-04-09 09:50:31 +02:00
retroflex
4d7b19c8cb Added calendar event location 2019-04-08 21:57:32 +02:00
retroflex
40f535cf3c Added possibility to show event location. 2019-04-08 21:49:19 +02:00
Michaël Arnauts
17425dcaf7 Add CHANGELOG entry. Fix test. 2019-04-07 16:41:05 +02:00
Michaël Arnauts
6b87fc64af sliceMultiDayEvents is false by default 2019-04-07 15:26:25 +02:00
Thierry Nischelwitzer
35174b0348 bugfixing calendar module 2019-04-07 11:15:16 +02:00
Michaël Arnauts
fd53541719 Handle SIGTERM messages 2019-04-06 20:50:54 +02:00
Malcolm Oakes
7c68bff9f5 Update from develop branch 2019-04-03 16:24:42 +01:00
Malcolm Oakes
6c64991951 Update from develop branch 2019-04-03 16:23:55 +01:00
Malcolm Oakes
ca04ff0f37 Update from develop branch 2019-04-03 16:22:26 +01:00
Malcolm Oakes
7742575cab Merge latest from develop branch 2019-04-03 16:16:59 +01:00
Malcolm Oakes
cdcdce702d Changes for UK Met Office weather data provider 2019-04-03 15:46:45 +01:00
Malcolm Oakes
c80e04fe8d Add new weather data provider UK Met Office (Datapoint) 2019-04-03 15:19:32 +01:00
darkniki
c3b3ea107a Update ru.json
Added "FEELS" translation
2019-04-03 08:31:40 +03:00
Sami Mäkinen
1dc530c549 Add translations for FI week/feels 2019-04-02 22:59:34 +03:00
Michael Teeuw
8b0b70e757 Prepare 2.8.0-develop. 2019-04-02 09:55:20 +02:00
Michael Teeuw
b508a629e8 Merge pull request #1632 from MichMich/fix-2.7.1
Fix package.json version number.
2019-04-02 09:50:36 +02:00
Michael Teeuw
abb0dadead Fix package.json version number. 2019-04-02 09:34:42 +02:00
Michael Teeuw
e6fb18df56 Merge pull request #1627 from MichMich/develop
Release 2.7.0
2019-04-01 21:54:05 +02:00
Michael Teeuw
43ba13f3bc Prepare 2.8.0-develop. 2019-04-01 21:26:39 +02:00
Michael Teeuw
ba705f5563 Fix Lint Issue. 2019-04-01 20:55:24 +02:00
Michael Teeuw
34e188ec1f Typo. 2019-04-01 20:48:30 +02:00
Michael Teeuw
b0d97dd170 Prepare for release. 2019-04-01 20:47:07 +02:00
Michael Teeuw
7caeae61f5 Merge pull request #1625 from qistoph/fix_weather_title
Update current weather header only if not undefined
2019-04-01 20:36:37 +02:00
Chris van Marle
416ace4c86 Update current weather header only if not undefined 2019-03-29 13:15:58 +01:00
Chris van Marle
979041ee91 Fix typo in variable name fetchedLocationName 2019-03-29 13:13:56 +01:00
Michael Teeuw
f0939b8af5 Merge pull request #1622 from JasMich/develop
Develop
2019-03-28 19:12:17 +01:00
Jasper Michalke
d7a7002bdd Finally added all required files for Klingon translations 2019-03-28 14:57:45 +01:00
Jasper Michalke
d9601de075 Update translations.js
Added Klingon translations file to translations list
2019-03-28 14:55:01 +01:00
Jasper Michalke
ef570558cf Update CHANGELOG.md 2019-03-28 14:53:28 +01:00
Michael Teeuw
db3e81408f Merge pull request #1618 from dgburr/newsfeed-article-info-request
Add support for the ARTICLE_INFO_REQUEST notification
2019-03-28 12:45:19 +01:00
Michael Teeuw
e8771cdea8 Merge branch 'develop' into newsfeed-article-info-request 2019-03-28 12:11:06 +01:00
Michael Teeuw
057eab2173 Merge pull request #1619 from dgburr/changelog-fix
Fix changelog
2019-03-28 12:09:53 +01:00
Michael Teeuw
e2a7024eeb Merge pull request #1620 from garyray-k/master
Spelling correction in README.md
2019-03-28 12:09:35 +01:00
Michael Teeuw
4650986dfa Merge pull request #1621 from kolbyjack/feature/calendar-name
Add name property to calendars
2019-03-28 12:09:09 +01:00
Jon Kolb
868b5e4617 Add name property to calendars
When consuming CALENDAR_EVENTS broadcasts, it is useful for other
modules to be able to identify which calendar a specific event
came from, for filtering/display purposes.
2019-03-26 19:51:44 -04:00
Gary Krause
f12860c7b1 Spelling correction in README.md
small spelling correction.
2019-03-25 14:07:53 -04:00
Daniel Burr
8f751812a6 The note which I added to the changelog in commit 80eef2ab8c was in the 2.6.0 section instead of 2.7.0 2019-03-25 01:19:00 +01:00
Daniel Burr
07a5092eb3 Add note to changelog 2019-03-25 01:13:02 +01:00
Daniel Burr
29c9c92ba6 Add support for the ARTICLE_INFO_REQUEST notification
Upon reception of an ARTICLE_INFO_REQUEST notification, newsfeed will
respond with the notification ARTICLE_INFO_RESPONSE, containing the
fields 'title', 'source', 'date', 'desc' and 'url'.
2019-03-25 01:08:59 +01:00
Michael Teeuw
edfa327158 Merge pull request #1602 from qistoph/develop
Notifications delay time and background color
2019-03-19 09:36:24 +01:00
Michael Teeuw
869a6e66cc Merge pull request #1611 from ZakarFin/node-upgrade
Node.js upgrade to 10.x (installer)
2019-03-19 09:36:13 +01:00
Sami Mäkinen
36abbfc048 Changelog 2019-03-18 23:12:44 +02:00
Sami Mäkinen
cfc3e6d2f4 Merge branch 'master' into develop 2019-03-18 22:51:23 +02:00
Sami Mäkinen
e38dbee6a6 Node 9 -> 10 (LTS) 2019-03-18 22:23:10 +02:00
Michael Teeuw
68a7c857c0 Merge pull request #1610 from dgburr/documentation-fix
Fix documentation of `useKMPHwind` option in currentweather
2019-03-18 17:09:04 +01:00
Daniel Burr
80eef2ab8c Fix documentation of useKMPHwind option in currentweather 2019-03-18 16:23:03 +01:00
Michael Teeuw
1d652aa746 Merge branch 'develop' into develop 2019-03-18 16:08:13 +01:00
Michael Teeuw
b07c43aa36 Merge pull request #1599 from rejas/use_getHeader
Use getHeader instead of data.header
2019-03-18 16:04:45 +01:00
Chris van Marle
3880c8dc2c Restyle notification colors 2019-03-14 14:11:14 +01:00
Chris van Marle
c0ab2ac297 Support timer in notifications too 2019-03-14 14:11:10 +01:00
Veeck
de684dcb63 Fix typos in jsdoc 2019-03-11 14:03:01 +02:00
Veeck
29ef1db86b Remove whitespace 2019-03-08 11:33:02 +01:00
Veeck
5dfd8a61be Update changelog 2019-03-08 11:29:48 +01:00
Veeck
358e2b3ccf Use getHeader instead of data.header when creating the DOM 2019-03-08 11:25:38 +01:00
Michael Teeuw
4203065a06 Merge pull request #1590 from vincep5/develop
Adding new weather provider for weather.gov
2019-03-07 09:18:40 +01:00
vincep5
bc4e0190a0 readme formatting 2019-03-06 21:33:13 -06:00
Michael Teeuw
dd7004cbc9 Merge pull request #1598 from rejas/more_verbose_error_message
More verbose error message when config.js is broken
2019-03-06 11:48:45 +01:00
Veeck
bdc5c8f620 Fix typos in changelog 2019-03-06 10:02:01 +01:00
Veeck
02d36e22ee Show more verbose error message on console if the config is malformed 2019-03-06 10:01:44 +01:00
Michael Teeuw
331e8c4aa6 Merge pull request #1594 from rejas/patch-1
Updated modernizr code in alert module
2019-03-05 10:26:47 +01:00
Veeck
d622277c11 Updated modernizr code to latest version 2019-03-02 08:40:20 +01:00
Veeck
8f781ea4ab Small typo fix in link 2019-03-02 08:30:08 +01:00
vincep5
ebc1e5bf12 tidy up code for weather 2019-02-27 09:09:37 -06:00
Michael Teeuw
ce9a61622e Merge pull request #1592 from MichMich/revert-1564-develop
Revert "Added autoLocation and autoTimezone option for weather modules and clock respectively."
2019-02-27 13:41:13 +01:00
Michael Teeuw
e4891e699f Revert "Added autoLocation and autoTimezone option for weather modules and clock respectively." 2019-02-27 13:33:14 +01:00
vincep5
d8765578c8 weather.gov N arrow 2019-02-26 14:51:09 -06:00
vincep5
3a034ecec8 Adding new weather provider for weather.gov 2019-02-26 14:06:00 -06:00
vin p
a3dea45089 Merge pull request #4 from MichMich/develop
Develop
2019-02-26 13:59:38 -06:00
Michael Teeuw
de99c8a5e4 Merge pull request #1589 from hudashot/calendar
Regularly trigger ADD_CALENDAR to ensure calendar fetcher is running
2019-02-26 11:17:30 +01:00
hudashot
d3b8dbeea0 Regularly trigger ADD_CALENDAR to ensure calendar fetcher is running 2019-02-26 08:12:02 +00:00
Michael Teeuw
cff2f64155 Merge pull request #1586 from Tom-Hirschberger/feature/alert-fontawesome
Feature/alert fontawesome
2019-02-24 19:58:44 +01:00
Thomas Hirschberger
7b8de35405 Update CHANGELOG.md 2019-02-24 11:55:46 +01:00
Tom Hirschberger
02ae0df2cc add font-awesome.css to styles of alert.js 2019-02-24 11:48:14 +01:00
Michael Teeuw
b386cea69d Merge pull request #1582 from mdobsovic/develop
Slovak translation added
2019-02-23 12:09:48 +01:00
Michal Dobsovic
758ffb75a9 Added sk to translations.js 2019-02-23 10:37:24 +01:00
Michal Dobsovic
78fbc7f392 Modified CHANGELOG.md 2019-02-20 22:15:24 +01:00
Michal Dobsovic
9c58472576 Merge branch 'develop' of https://github.com/mdobsovic/MagicMirror into develop 2019-02-20 22:07:19 +01:00
Michal Dobsovic
f8c4afc228 Slovak translation added 2019-02-20 22:02:42 +01:00
Michael Teeuw
b169d65619 Merge pull request #1577 from sdetweil/develop
fix relative date fulldate events to use start of day to start of day diff… issue 1572
2019-02-19 15:47:57 +01:00
Michael Teeuw
9bf0d4f804 Merge pull request #1580 from lavolp3/lavolp3-patch-1
Changed defaut dateEndFormat
2019-02-19 15:47:41 +01:00
Dirk
4443f57f8a Update CHANGELOG.md 2019-02-19 14:10:17 +01:00
Sam Detweiler
ea5d8590d5 Merge branch 'develop' of https://github.com/sdetweil/MagicMirror into develop 2019-02-19 07:08:46 -06:00
sam detweiler
5d5feb4c71 Merge pull request #1 from MichMich/develop
Develop
2019-02-19 07:08:13 -06:00
Dirk
feb5351ec3 changed default calendarEndDate to "LT"
changed default calendarEndDate to "LT" to show local times for event end times. 
Can still be set to a different value by the user
2019-02-19 14:07:01 +01:00
Sam Detweiler
7630c25ef3 add future date offset correction for emergency date values in absolute mode 2019-02-19 07:06:22 -06:00
Michael Teeuw
24238094e5 Fix url. 2019-02-19 13:43:23 +01:00
Michael Teeuw
7cc9a03db8 Merge pull request #1578 from lavolp3/splitDates
Add "sliceMultiDayEvents" option in calendar module
2019-02-19 09:13:33 +01:00
Dirk
2b2e8508d9 Update calendar.js
Small updates for travis cr check
2019-02-18 22:38:28 +01:00
Dirk
a70716f225 Merge branch 'splitDates' of https://github.com/lavolp3/MagicMirror into splitDates 2019-02-18 21:11:58 +01:00
Dirk
d9fcc46994 included split function to split multiday events 2019-02-18 21:11:24 +01:00
Dirk
2d8acec6f0 Update CHANGELOG.md 2019-02-18 21:04:56 +01:00
Dirk
cd06d8c63a Merge pull request #5 from MichMich/develop
Develop
2019-02-18 21:02:46 +01:00
Sam Detweiler
a06ca55107 fix relative date fulldate events to use start of dat to start of day difference, fix extra space in changelog 2019-02-18 07:30:46 -06:00
Sam Detweiler
9686a9ba77 fix relative date fulldate events to use start of dat to start of day difference 2019-02-18 07:18:07 -06:00
Michael Teeuw
f7f4043ccd Merge pull request #1571 from kolbyjack/develop
Fix null dereference in moduleNeedsUpdate when the module isn't visible
2019-02-15 13:57:24 +01:00
Michael Teeuw
b7b55173a6 Merge pull request #1573 from vincep5/develop
weather module adjustments for rain and snow
2019-02-15 13:56:58 +01:00
Michael Teeuw
954253c7e2 Remove Slack. 2019-02-15 11:15:06 +01:00
vincep5
cbe4d2cd7f weather module adjustments for rain and snow 2019-02-14 13:00:40 -06:00
vin p
40101129b5 Merge pull request #3 from MichMich/develop
Develop
2019-02-14 12:20:52 -06:00
Michael Teeuw
4bb32c6d09 Merge pull request #1514 from fwitte/features/weather_forecast_and_forecast_daily_support
Add forecast and forecast/daily support to new weather module
2019-02-14 17:41:10 +01:00
Michael Teeuw
6e09ceeda6 Merge branch 'develop' into features/weather_forecast_and_forecast_daily_support 2019-02-14 17:34:08 +01:00
fwitte
d6a6a53623 updated weather icon display 2019-02-14 16:48:45 +01:00
Michael Teeuw
4a97052708 Fix linting error. 2019-02-14 13:50:16 +01:00
Jon Kolb
3a4902ad4a Fix null dereference in moduleNeedsUpdate when the module isn't visible 2019-02-14 00:06:45 +00:00
Michael Teeuw
77d14bc218 Add donation link. 2019-02-13 16:12:46 +01:00
Michael Teeuw
1d2a39a855 Merge pull request #1564 from jacob-ebey/develop
Added autoLocation and autoTimezone option for weather modules and clock respectively.
2019-02-13 09:46:25 +01:00
Michael Teeuw
98b53b6b3d Merge branch 'develop' into develop 2019-02-13 09:38:15 +01:00
Michael Teeuw
0148d8beaf Merge pull request #1565 from AnthonyBuisset/fix/calendar
Fix exdate handling when multiple values are specified (comma separated)
2019-02-13 09:37:06 +01:00
Michael Teeuw
5bfd84d3be Merge pull request #1567 from stefsims/patch-2
Added danish translation
2019-02-13 09:36:11 +01:00
Michael Teeuw
351eb95feb Merge pull request #1566 from stefsims/patch-1
Update da.json
2019-02-13 09:35:53 +01:00
stefsims
56788f0933 Update CHANGELOG.md
Added danish translation
2019-02-11 09:02:42 +01:00
stefsims
017a376616 Update da.json
Added FEELS and WEEK
2019-02-11 08:59:16 +01:00
Anthony Buisset
c5888cec66 Fix exdate handling when multiple values are specified (comma separated) 2019-02-10 16:30:12 +01:00
Jacob Ebey
3d5ad29eac - Removed trailing space 2019-02-09 13:51:23 -08:00
Jacob Ebey
c608636b7a - Added autoTimezone property to the clock 2019-02-09 13:41:42 -08:00
Jacob Ebey
1a97107b2d - Converted indentation to tabs. 2019-02-09 12:49:47 -08:00
Jacob Ebey
5ca3fbeaea Added autoLocation option for weather modules. 2019-02-09 12:42:42 -08:00
Michael Teeuw
44896db668 Merge pull request #1554 from roramirez/replace-console-log-none
serveronly: Replace the console.log of none for a \n new line
2019-01-27 11:22:17 +01:00
Rodrigo Ramírez Norambuena
12efb87a23 serveronly: Replace the console.log of none for a \n new line 2019-01-26 14:42:15 -05:00
Michael Teeuw
9181be86ba Merge pull request #1553 from CriticalPoint/patch-1
Updated README
2019-01-25 09:56:25 +01:00
Mike
053b01e036 Updated README
Scanned through it and corrected some spelling mistakes, nothing that affects the core purpose of the document.
2019-01-25 07:50:24 +00:00
Michael Teeuw
86041d0968 Merge pull request #1541 from amcolash/trim_calendar_events
Add in vertical cutting for long calendar event titles
2019-01-23 13:38:19 +01:00
Michael Teeuw
bd87f63e91 Merge pull request #1542 from vincep5/develop
current.njk JS error and Loading string
2019-01-23 13:37:25 +01:00
Dirk
b79b49e8f3 Merge pull request #3 from MichMich/master
updated from master
2019-01-23 10:36:05 +01:00
Andrew McOlash
a0dde39d97 Fix braces for if check 2019-01-21 00:47:53 -08:00
vincep5
2e03868021 current.njk JS error and Loading string 2019-01-17 08:54:16 -06:00
vin p
29384c2ba3 Merge pull request #2 from MichMich/develop
Develop
2019-01-17 08:48:16 -06:00
Andrew McOlash
320743ab8d fix spacing 2019-01-16 22:53:28 -08:00
Andrew McOlash
399e171083 Add in cutting of long vertical titles 2019-01-16 22:51:44 -08:00
Michael Teeuw
184164b677 Merge pull request #1535 from fdahms/develop
forgot one sudo in installation script
2019-01-15 12:48:11 +01:00
fewieden
a8bd196234 current weather tests 2019-01-13 23:59:05 +01:00
fewieden
239d425940 webdriver ajax stub 2019-01-13 23:58:35 +01:00
fewieden
baa3c1461c test setup 2019-01-13 23:57:19 +01:00
fewieden
fa8e398e90 dependencies 2019-01-13 23:50:29 +01:00
fdahms
6d9675a299 forgot one sudo 2019-01-13 20:07:20 +01:00
Michael Teeuw
91e8ce62d4 Merge pull request #1534 from PalatinCoder/patch-1
fix: only show repeating count if the event is actually repeating
2019-01-13 16:36:45 +01:00
Jan Syring-Lingenfelder
06e641015f docs: update changelog 2019-01-13 16:25:57 +01:00
Jan Syring-Lingenfelder
1c83059482 fix: only show repeating count if the event is actually repeating 2019-01-13 16:18:52 +01:00
Michael Teeuw
90b24d824a Merge pull request #1531 from fdahms/develop
Fixing raspbian installation script
2019-01-13 11:58:30 +01:00
Michael Teeuw
62457d0e48 Merge pull request #1532 from oddswop/patch-1
Update README.md - just fixing a typo :)
2019-01-13 11:57:27 +01:00
Yvonne
90c96f7479 Update README.md 2019-01-13 09:26:37 +11:00
fdahms
f87adebe41 Fixing raspbian installer
* fixing issue #1377
* fixing problem with old node installation from fresh raspbian
* add feature for disable screen saver
2019-01-12 18:11:48 +01:00
fdahms
8f24cc8d13 editing CHANGELOG 2019-01-12 18:06:52 +01:00
Michael Teeuw
992802d196 Merge pull request #1525 from ianperrin/develop
Fix conflict between font awesome versions as per #1522
2019-01-10 13:50:14 +01:00
Ian
8546d6730c Update CHANGELOG.md 2019-01-10 12:44:35 +00:00
Ian
0092289105 revert font awesome reference 2019-01-09 21:38:07 +00:00
Ian
7c3923ad00 Use Font Awesome 5 (with backwards compatibility) for all modules 2019-01-09 21:32:43 +00:00
Ian
ef82039401 Allow multiple css to be included for one vendor 2019-01-09 21:29:49 +00:00
Ian
b01b9758e0 remove Font Awesome 4 dependency 2019-01-09 21:24:14 +00:00
vin p
88b00f689b Merge pull request #1 from MichMich/develop
Develop
2019-01-08 20:55:46 -06:00
Michael Teeuw
0a340d5d57 Merge pull request #1512 from fwitte/features/currentweather_weatherforecost_degreesign
still show degree sign if degreeLabel/scale is false
2019-01-08 09:36:26 +01:00
Michael Teeuw
50545a83b8 Merge pull request #1515 from andogit7/andogit7-MM-develop
Andogit7 mm develop
2019-01-08 09:34:50 +01:00
Michael Teeuw
4a57ff40d8 Merge pull request #1518 from fwitte/features/fade_forecast_and_maxnumberdays
Features/fade forecast and maxnumberdays
2019-01-08 09:33:26 +01:00
Michael Teeuw
0238455a5a Merge pull request #1521 from Bardo98/patch-1
Added Italian translation of "FEELS"
2019-01-08 09:10:22 +01:00
Bardo98
a53e963001 Merge pull request #1 from Bardo98/patch-2
Update CHANGELOG.md
2019-01-07 22:19:01 +01:00
Bardo98
984608e23f Added Italian translation of "FEELS" 2019-01-07 22:05:26 +01:00
Bardo98
f680c83d2d Update CHANGELOG.md 2019-01-07 21:55:18 +01:00
fwitte
a79e51c76f updated +CHANGELOG 2019-01-07 08:51:17 +01:00
fwitte
2dfb349609 fixed missing last day display in forecast/hourly 2019-01-07 08:19:50 +01:00
fwitte
766f21b525 adjusted default values 2019-01-06 12:34:44 +01:00
fwitte
733dfa1467 adjusted README 2019-01-06 12:34:27 +01:00
fwitte
63aa840b55 replaced tabs with spaces 2019-01-06 12:30:26 +01:00
fwitte
8b2d544576 added fade and maxnumberofdays options for forecast 2019-01-06 12:24:26 +01:00
fwitte
d6046d2422 simplified fetchForecastHourly function 2019-01-06 10:24:16 +01:00
fwitte
409939360f do not show 0 mm rain value 2019-01-06 10:23:15 +01:00
andogit7
1d21f39fbc Update CHANGELOG.md 2019-01-05 17:09:15 +00:00
andogit7
a477140a4b Update CHANGELOG.md 2019-01-05 17:08:55 +00:00
andogit7
1bbf2d8ce6 Update clock.js 2019-01-05 17:04:33 +00:00
fwitte
40a65eec51 adjusted CHANGELOG 2019-01-05 17:16:50 +01:00
fwitte
8431ebf2e8 adjusted README 2019-01-05 17:16:37 +01:00
fwitte
bdcc0c5373 another typo fix 2019-01-05 17:16:19 +01:00
fwitte
9cbf331533 fixed typo in daily data fetcher 2019-01-05 16:56:47 +01:00
fwitte
77640714cc adjusted openweathermap module to work with /forecast and forecast/daily 2019-01-05 16:54:45 +01:00
fwitte
9457d95c3f Merge remote-tracking branch 'origin' into develop 2019-01-05 15:27:05 +01:00
fwitte
c2ff949f2d adjusted CHANGELOG 2019-01-05 13:14:10 +01:00
fwitte
ba8685a122 readded degreesign 2019-01-05 13:13:53 +01:00
Francesco Witte
55464ed0dd Merge pull request #1 from MichMich/develop
Develop
2019-01-05 12:59:23 +01:00
Michael Teeuw
fdf3691c87 Merge pull request #1510 from fewieden/feature/weather-module-improvements
Fixed issues with the new weather module
2019-01-05 12:29:12 +01:00
fewieden
aa6699cf3e link issues to changelog 2019-01-05 10:33:58 +01:00
fewieden
b79b48baac link issues to changelog 2019-01-05 10:32:09 +01:00
fewieden
5d22dbd99e changelog 2019-01-05 10:26:13 +01:00
Michael Teeuw
4686bb5584 Merge pull request #1509 from shbatm/bug-fix
Fixes Incomplete fix for MichMich/MagicMirror#1507
2019-01-05 07:09:35 +01:00
shbatm
1f62b8f0b6 Update node_helper.js 2019-01-04 18:12:12 -06:00
fewieden
5759ed3728 implemented config option decimal symbol, align indoor elements vertical, add humidity support to nunjuck unit filter, do not display degree symbol for kelvin 2019-01-04 20:14:28 +01:00
fewieden
827fbfb78f dimmed loading indicator for weather forecast 2019-01-04 20:14:28 +01:00
fewieden
dc363de610 fix weather forecast table height 2019-01-04 20:14:28 +01:00
shbatm
b9d6a235e3 Fixes Incomplete fix for MichMich/MagicMirror#1507 2019-01-04 12:37:58 -06:00
Michael Teeuw
ebc57fe494 Merge pull request #1507 from shbatm/bug-fix
Error handling for bad git data in updatenotification
2019-01-04 17:00:27 +01:00
Michael Teeuw
e224ec4ae0 Merge branch 'develop' into bug-fix 2019-01-04 17:00:18 +01:00
Michael Teeuw
a5da347177 Merge pull request #1506 from fwitte/fwitte/weather_forecast_daily_openweather
Fix openweather forecast in new weather module, fetch daily data
2019-01-04 16:59:35 +01:00
shbatm
a257b15f86 Error handling for bad git data in updatenotification
Update CHANGELOG
2019-01-04 09:23:10 -06:00
Michael Teeuw
a70cc53d82 Merge branch 'develop' into fwitte/weather_forecast_daily_openweather 2019-01-04 13:04:02 +01:00
fwitte
1df2de9202 updated README 2019-01-04 12:34:29 +01:00
fwitte
9e394ea349 updated CHANGELOG 2019-01-04 12:34:12 +01:00
fwitte
b55685d610 added comments 2019-01-04 12:13:39 +01:00
fwitte
2156aac046 fixed typos, fetching forecast parameters by day 2019-01-04 12:07:02 +01:00
Michael Teeuw
6914465e3d Remove "Focus" to pass test. 2019-01-03 16:42:31 +01:00
Michael Teeuw
f3847ec6f3 Bump Node version to 8. 2019-01-03 16:35:30 +01:00
Michael Teeuw
e1fe8d1d89 Bump Electron to v3.0.13 - Issue: #1500 2019-01-03 16:04:33 +01:00
Michael Teeuw
675c937a4a Merge pull request #1505 from fwitte/fwitte/change_temperature_unit_display
Remove degree symbol for Kelvin scale
2019-01-03 15:25:24 +01:00
fwitte
c8f53bdf8e updated CHANGELOG.md 2019-01-03 12:35:52 +01:00
fwitte
3541d5adde removed degree symbol display for Kelvin scale, match source code in currentweather and weatherforecast 2019-01-03 12:06:52 +01:00
Michael Teeuw
b52da7c9fc Prepare for 2.7.0 dev branch. 2019-01-01 17:15:37 +01:00
Michael Teeuw
de57daa3cd Merge pull request #1498 from MichMich/develop
Release 2.6.0.
2019-01-01 17:09:33 +01:00
Michael Teeuw
e70e011a9c Add dependency. 2019-01-01 16:57:16 +01:00
Michael Teeuw
99febb99f1 Additional update info. 2019-01-01 16:48:12 +01:00
Michael Teeuw
874d79be36 Upgrade Electron to 2.0.16 2019-01-01 16:33:59 +01:00
Michael Teeuw
b33663c9f8 Prepare for release 2.6.0. 2019-01-01 15:52:29 +01:00
Michael Teeuw
7e69fa39eb Merge pull request #1497 from fewieden/feature/weather-module-improvements
fix rain amount information for different units and providers, docume…
2019-01-01 15:19:27 +01:00
Michael Teeuw
de06490539 Merge pull request #1496 from janfrode/patch-1
Update README.md
2019-01-01 15:18:45 +01:00
fewieden
40a30c24a0 link provider readme in module readme 2018-12-30 20:52:27 +01:00
fewieden
de04c12d3c fix rain amount information for different units and providers, documentation 2018-12-30 20:46:25 +01:00
Jan-Frode Myklebust
38fb53b058 Update README.md
Wrong delimiter used for electronOptions. Use : instead of =.
2018-12-30 20:33:16 +01:00
Michael Teeuw
ed617c5943 Merge pull request #1485 from djgalloway/wip-endtime
Document endTime variables
2018-12-30 15:42:04 +01:00
Michael Teeuw
986337da0c Merge pull request #1495 from fewieden/feature/weather-module-improvements
weather module feels like temperature
2018-12-30 15:40:22 +01:00
fewieden
8dd7621f29 add original feels like temperature and fixed it for imperial units 2018-12-30 14:17:13 +01:00
fewieden
88d862303d fixed beaufortwindspeed for imperial units 2018-12-30 14:14:17 +01:00
fewieden
cc274ffebe fixed darksky metric units 2018-12-30 14:11:16 +01:00
Michael Teeuw
28a108f79b Merge pull request #1491 from devpwnz/patch-1
Update ro.json
2018-12-29 10:51:28 +01:00
Michael Teeuw
b9f75bf7d2 Merge pull request #1489 from fewieden/feature/weather-module-improvements
WIP: weather module improvements
2018-12-29 10:49:18 +01:00
devpwnz
39994d5797 Update CHANGELOG.md 2018-12-29 10:08:57 +02:00
devpwnz
8e28be6558 Update ro.json 2018-12-29 10:00:29 +02:00
fewieden
8a65bef004 add unit and language handling for weather provider darksky 2018-12-28 19:39:00 +01:00
Michael Teeuw
b94dc5044b Merge pull request #1488 from fewieden/weather
Weather refactoring
2018-12-28 08:56:58 +01:00
fewieden
b853c00dd4 Add changelog entry 2018-12-27 23:12:28 +01:00
fewieden
7a0bc81f48 Merge branch 'develop' of https://github.com/MichMich/MagicMirror into weather
# Conflicts:
#	css/main.css
2018-12-27 23:03:41 +01:00
fewieden
10bc326490 cleanup 2018-12-27 19:37:02 +01:00
fewieden
1920f8158e config options and documentation 2018-12-27 18:52:35 +01:00
fewieden
0ed2ba0183 darksky forecast and darksky current weather fixes 2018-12-27 17:56:34 +01:00
fewieden
95adc0aec1 forecast 2018-12-27 17:14:03 +01:00
fewieden
ebee80d10e small improvements 2018-12-27 17:13:49 +01:00
fewieden
63836185d9 weatherprovider 2018-12-27 17:13:06 +01:00
David Galloway
d0195e0509 Document endTime variables
Missed docs in 188aa14d82

Signed-off-by: David Galloway <dgallowa@redhat.com>
2018-12-20 11:40:50 -05:00
Michael Teeuw
5d9bcd9918 Merge pull request #1476 from wast/patch-1
Create hr.json
2018-12-19 16:18:32 +01:00
Michael Teeuw
db04c26d24 Merge pull request #1480 from michael5r/newsfeed-removestarttags-bug
[FIX] Bug in newsfeed module using removeStartTags on a description
2018-12-19 16:17:52 +01:00
Michael Teeuw
56b399655e Merge pull request #1483 from balassy/feature/weatherforecast-degree-labels
Always display the degree symbol in the Weather Forecast module
2018-12-19 16:15:18 +01:00
Michael Teeuw
24e15c0568 Add ajv dependency to fix linting error. 2018-12-19 16:04:52 +01:00
György Balássy
f0c516e82d CHANGED: The Weather Forecast module by default displays the &deg; symbol after every numeric value to be consistent with the Current Weather module. 2018-12-14 11:32:58 +01:00
György Balássy
f38203ef62 Merge pull request #5 from MichMich/develop
Update the develop branch from the original repo
2018-12-14 09:13:37 +01:00
mschmidt
a77c026803 Add issue number to changelog 2018-12-10 14:06:55 -06:00
mschmidt
5b6306671c Initial 2018-12-10 14:02:50 -06:00
Stjepan
25610222bc Update translations.js
Added Croatian.
2018-12-06 11:41:01 +01:00
Stjepan
c17f941fb9 Update CHANGELOG.md
Added Croatian translation to the changelog.
2018-12-06 11:38:34 +01:00
Stjepan
ae6ab1d203 Create hr.json
Croatian translation.
2018-12-06 10:00:34 +01:00
Michael Teeuw
92accf99b4 Merge pull request #1468 from ax42/patch-1
Update README.md
2018-11-29 10:18:39 +01:00
Michael Teeuw
b02702fe80 Merge pull request #1467 from lavolp3/calendar_issues
Fading for dateheaders, fixed bug for fulldayevents
2018-11-29 10:18:09 +01:00
Alexis Iglauer
5c549ec6e5 Update README.md
Typo
2018-11-22 23:28:04 +01:00
Dirk
af459a5a28 formatting corrected
Corrected formatting due to Travis CI errors
2018-11-21 12:10:39 +01:00
Dirk
07770601f6 Update CHANGELOG.md
- Fading for dateheaders timeFormat in Calendar [#1464](https://github.com/MichMich/MagicMirror/issues/1464)
- Bug showing FullDayEvents one day too long in calendar fixe
2018-11-21 10:24:53 +01:00
Dirk
cc96b86b3a Fading for dateheaders
Included fading for dateheaders option
Removed unnecessary switch statement in dateheaders option
2018-11-21 09:32:56 +01:00
Michael Teeuw
1547f4d8b2 Merge pull request #1456 from EdgardosReis/develop
Portuguese translation for "Feels"
2018-11-08 08:57:28 +01:00
Michael Teeuw
75054fcc70 Merge pull request #1458 from tomwardill/ignore-rrule-errors
Ignore RRULE errors for unparseable elements.
2018-11-08 08:56:50 +01:00
Tom Wardill
390b3b173b Update CHANGELOG.md 2018-11-07 18:53:54 +00:00
Tom Wardill
78daa65d28 Ignore rrule errors 2018-11-07 18:53:04 +00:00
EdgardosReis
3bbdd08d24 Portuguese translation for "Feels" 2018-11-07 00:34:02 +00:00
Michael Teeuw
cec1f12918 Merge pull request #1424 from thobach/develop
Allow to parse recurring calendar events where the start date is before 1900
2018-10-30 16:20:33 +01:00
Thomas Bachmann
d923ae2107 Merge branch 'develop' into develop 2018-10-29 20:30:37 +01:00
Thomas Bachmann
85931155e6 Fixed eslint issues
.. as requested in Pull Request #1424
2018-10-29 20:26:54 +01:00
Michael Teeuw
4fd87aca09 Change showEnd default to false. 2018-10-26 15:22:05 +02:00
Michael Teeuw
600e0ec7e3 Merge pull request #1425 from Ybbet/addClassCellCalendar
Add class cell calendar
2018-10-26 15:14:31 +02:00
Michael Teeuw
51fbff1a4a Merge branch 'develop' into addClassCellCalendar 2018-10-26 15:14:17 +02:00
Michael Teeuw
03b1389ee5 Merge pull request #1426 from gberg927/develop
Changed OpenWeatherMap URL in ReadME
2018-10-26 15:12:34 +02:00
Michael Teeuw
8f014e9d82 Merge pull request #1427 from P-Storm/develop
Added Font-awesome 5
2018-10-26 15:11:55 +02:00
Michael Teeuw
cecc6f7561 Merge branch 'develop' into develop 2018-10-26 15:11:46 +02:00
Michael Teeuw
62ba81c6a6 Merge pull request #1430 from shade34321/weather_forecast_screenshot
Added in 5 day forecast screenshot
2018-10-26 14:42:02 +02:00
Michael Teeuw
c5e3422fcd Merge branch 'develop' into weather_forecast_screenshot 2018-10-26 14:40:57 +02:00
Michael Teeuw
bd5a46b4ab Merge pull request #1431 from shade34321/weather_screenshot
Added in screenshot for current weather module.
2018-10-26 14:38:07 +02:00
Michael Teeuw
3a972bbbab Merge pull request #1432 from shade34321/clock_screenshot
Added in screenshot
2018-10-26 14:37:21 +02:00
Michael Teeuw
7768ea28bd Merge pull request #1433 from shade34321/compliments_screenshot
Added in compliments screenshot
2018-10-26 14:36:22 +02:00
Michael Teeuw
75add44e86 Merge pull request #1434 from shade34321/news_feed_screenshot
Added in screenshot for the newfeed module
2018-10-26 14:35:53 +02:00
Michael Teeuw
7d94365cbf Merge pull request #1437 from Duske/patch-1
(doc) showEnd config
2018-10-26 14:34:23 +02:00
Michael Teeuw
2d830fb8e7 Merge pull request #1441 from cphamlet/patch-1
Fix Broken Link
2018-10-26 14:33:36 +02:00
Michael Teeuw
633bf36fe7 Merge pull request #1447 from Santanachia/master
Fix polish translation
2018-10-26 14:31:44 +02:00
Marcin
c0a5e23d95 Merge branch 'develop' into master 2018-10-23 09:00:20 +02:00
Marcin Bielecki
d3798344dd fix polish translation 2018-10-23 08:57:53 +02:00
Teddy
ed37460402 Merge branch 'master' into addClassCellCalendar 2018-10-21 22:38:50 +02:00
cphamlet
9b6ba65cdb Fix Broken Link
http://www.openweathermap.org/help/city_list.txt is a dead link, suggest replacing with https://openweathermap.org/city
2018-10-14 15:08:55 -05:00
Dustin
42a9631926 Merge branch 'develop' into patch-1 2018-10-09 10:51:09 +02:00
Shade Alabsa
676a8a6421 Fixed README formatting errors. 2018-10-08 19:40:54 -04:00
Dustin
cdbf022ce0 Update CHANGELOG.md 2018-10-08 21:19:55 +02:00
Dustin
db79e1271e (doc) showEnd config
Add documentation for showEnd configuration
2018-10-08 21:11:28 +02:00
Shade Alabsa
d2b3efacf9 Added in screenshot for the newfeed module 2018-10-07 15:20:11 -04:00
Shade Alabsa
a2ab94f971 Added in compliments screenshot 2018-10-07 15:16:10 -04:00
Shade Alabsa
a0d92d764b Added in screenshot 2018-10-07 15:12:10 -04:00
Shade Alabsa
649b78e3f2 Added in screenshot for current weather module. 2018-10-07 15:01:51 -04:00
Shade Alabsa
e7df1c3e56 Added in 5 day forecast screenshot 2018-10-07 14:55:07 -04:00
P-Storm
53833ae0c3 Spaces to tab 2018-10-05 01:42:28 +02:00
P-DESK\P-Storm
66b914774a Updated changelog 2018-10-05 01:24:47 +02:00
P-DESK\P-Storm
fc89feec4e * Added font awesome 5, keeping shims in place for the calendar app (https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4)
* Updated example sample config
2018-10-05 01:16:25 +02:00
Dennis Glasberg
d311dbd9d5 Update README.md 2018-10-03 21:28:30 -04:00
Dennis Glasberg
f97aa67100 Merge pull request #2 from gberg927/Weather-Module-Readme-URL
Weather module readme url
2018-10-03 21:23:56 -04:00
Dennis Glasberg
9a8add780c Update README.md 2018-10-03 21:20:38 -04:00
Teddy Payet
3b48f1d042 - Possibility to add classes to the cell of symbol, title and time of the events of calendar. 2018-10-04 02:07:08 +02:00
Teddy Payet
332b54e7a5 Merge branch 'develop' of https://github.com/MichMich/MagicMirror into addClassCellCalendar 2018-10-04 02:02:20 +02:00
Thomas Bachmann
007b2f0c88 Allow to parse recurring calendar events where the start date is before 1900
Some birthday calendar events have a start date before 1900.
2018-10-03 22:43:29 +02:00
Thomas Bachmann
3f083862e7 Allow to parse recurring calendar events where the start date is before 1970
Some birthday calendar events have a start date before 1970.
2018-10-03 22:05:51 +02:00
Thomas Bachmann
39619d5277 Allow to parse recurring calendar events where the start date is before 1970
Some birthday calendar events have a start date before 1970.
2018-10-03 22:03:50 +02:00
Michael Teeuw
d4fe01f9b9 Prepare for 2.6.0-dev. 2018-10-01 08:20:15 +02:00
Michael Teeuw
6db61b4357 Merge pull request #1418 from MichMich/develop
Develop
2018-10-01 08:16:04 +02:00
Michael Teeuw
f245cbf7f2 Merge pull request #1419 from rudibarani/master
Details to install the latest version of Node.js
2018-10-01 08:05:22 +02:00
rudibarani
6f2b04669f Details to install the latest version of Node.js
Added the direct code to always install the latest version of Node.js for the manual installation.
Maybe you could also include this in the automatic setup script, which does not seem to install the latest version of Node.js.
2018-09-30 23:39:22 +02:00
Michael Teeuw
9a46081d0b Prepare for release 2.5.0 2018-09-30 21:36:04 +02:00
Teddy Payet
3c7e507ca1 Merge branch 'develop' of https://github.com/MichMich/MagicMirror into develop 2018-09-26 10:03:26 +02:00
Michael Teeuw
7117725e69 Merge pull request #1405 from ubertao/multi-line-compliments
Multi-line compliments
2018-09-25 11:36:27 +02:00
ubertao
ba428c6cfe Use 'white-space: pre-line' for multi-line compliment. 2018-09-24 23:01:17 +08:00
ubertao
d76c924ad1 Update compliments README.md for multi-line support. 2018-09-20 09:09:06 +08:00
ubertao
cad7debc5b Replace innerHTML() with createElement() and appendChild() for security. 2018-09-20 08:49:17 +08:00
ubertao
40725aa2a2 Update CHANGELOG.md with multi-line compliments support. 2018-09-17 00:54:01 +08:00
ubertao
6034891fed Support multi-line compliments. 2018-09-17 00:51:37 +08:00
Michael Teeuw
9dd9862d33 Merge pull request #1402 from ubertao/pr-zh-cn-2.5.0
Update zh-cn translation for 2.5.0
2018-09-13 08:59:57 +02:00
Michael Teeuw
48c72e319b Merge pull request #1401 from ubertao/pr-calender-gzip
Pr calender gzip
2018-09-13 08:58:13 +02:00
ubertao
4b6208fd9c Update CHANGELOG.md for zh-cn translation updates. 2018-09-12 09:35:58 +08:00
ubertao
168904a159 Update zh-cn translation to 2.5.0 2018-09-12 09:31:46 +08:00
ubertao
28f1498ec3 update CHANGELOG.md adding gzip fix for calendar module 2018-09-12 08:17:10 +08:00
ubertao
d3028e10d3 Merge branch 'develop' of https://github.com/MichMich/MagicMirror into pr-calender-gzip 2018-09-12 08:15:52 +08:00
Teddy Payet
5eb0b77a8a Merge upstream/develop 2018-09-08 23:40:39 +02:00
ubertao
4aace5b95a update changelog with gzip calendar fix 2018-09-08 23:44:12 +08:00
ubertao
044dbd4a65 Add gzip support to calendar fetcher. 2018-09-08 23:05:19 +08:00
Michael Teeuw
5dbae7c9d7 Merge pull request #1383 from balassy/bugfix/updatenotification-localization
Making the word "commit" localizable in the UpdateNotification module message
2018-09-05 09:12:04 +02:00
György Balássy
ec44cb2761 CHANGED: The wording in CHANGELOG is modified to be more descriptive. 2018-09-05 04:41:09 +02:00
György Balássy
b06cf55c0b FIXED: Character encoding issue in pl.json occurred during rebase. 2018-09-05 04:33:42 +02:00
György Balássy
b601f6a138 CHANGED: The UPDATE_INFO key in the localization file is changed to UPDATE_INFO_SINGLE and UPDATE_INFO_MULTIPLE to allow different localization for single and multiple commits. 2018-09-05 04:30:57 +02:00
György Balássy
ddebc63488 ADDED: CHANGELOG entry. 2018-09-05 04:30:23 +02:00
György Balássy
35440822be CHANGED: The COMMIT_COUNT placeholder in the UPDATE_INFO message of the UpdateNotification module does not contain the word "commit" or "commits" any more, so language files can independently localize them. 2018-09-05 04:30:22 +02:00
György Balássy
f4c6bcfb8e Merge pull request #4 from MichMich/develop
Update Develop from the original repo
2018-09-05 04:26:13 +02:00
Michael Teeuw
6365c5c9ef Merge pull request #1396 from matt08/patch-4
Updated Polish translation
2018-09-04 11:42:16 +02:00
matt08
dd0334d30d Update pl.json 2018-08-31 09:24:18 +02:00
matt08
c462a44973 Polish translate for "Feels" 2018-08-31 09:17:04 +02:00
Michael Teeuw
6f88f5db83 Merge pull request #1385 from el97/patch-4
Update sv.json
2018-08-31 09:14:33 +02:00
matt08
93617f62a2 Updating "feels" translation 2018-08-31 09:14:16 +02:00
György Balássy
61d5f39408 Merge pull request #3 from MichMich/develop
Update the develop branch from the original repository
2018-08-30 00:00:56 +02:00
Michael Teeuw
c1fddaa7dd Merge pull request #1392 from vlebourl/develop
support for showing the end time of non full day events and the end date of several day long
2018-08-29 09:12:02 +02:00
vlb
188aa14d82 added support for showing end of events in calendar 2018-08-28 18:11:38 +02:00
Vincent Le Bourlot
5c25dd5b6d Update CHANGELOG.md 2018-08-28 18:00:13 +02:00
vlb
7c579cf7b7 added support for showing end of events through config parameters showEnd and dateEndFormat 2018-08-28 17:35:53 +02:00
vlb
c755c823fa added support for events having a duration instead of an end 2018-08-28 17:29:42 +02:00
Michael Teeuw
116588c237 Merge pull request #1390 from ccrlawrence/patch-1
ClientOnly: Global variable name used in callback function
2018-08-28 15:37:55 +02:00
Michael Teeuw
f02c1e4dc7 Merge branch 'develop' into patch-1 2018-08-28 15:36:58 +02:00
Michael Teeuw
c4e8cc1641 Correct changelog entry. 2018-08-28 15:33:53 +02:00
Michael Teeuw
93e68ad147 Merge branch 'develop' into patch-1 2018-08-28 15:32:47 +02:00
vlb
7ba88a83f0 consider events lasting several full days as full day events 2018-08-28 13:05:06 +02:00
ccrlawrence
c9293327ce Update CHANGELOG.md 2018-08-26 16:01:41 +01:00
ccrlawrence
fa1f35a89e ClientOnly: Global variable name used in callback function.
The global 'config' variable is used in the callback function, changed to local one. Unwanted behaviour when accessing server on docker or if using 0.0.0.0 or blank address in config file as it just passes this to electron to display.
2018-08-26 15:53:01 +01:00
Michael Teeuw
845ce7a711 Merge pull request #1384 from YangVincent/develop
Update OpenWeather city list instructions
2018-08-21 16:31:08 +02:00
el97
2b40007563 Update sv.json
Small changes. Added "FEELS": "Känns som".
2018-08-21 15:29:20 +02:00
Vincent Yang
217034c4a7 Update Changelog for weather city link 2018-08-21 01:06:12 -07:00
Vincent Yang
0b9d4f17ab Fix link for finding cities in OpenWeather 2018-08-21 01:04:58 -07:00
Michael Teeuw
7fb0ec12dd Merge pull request #1381 from Elaniobro/rp-zero-w-es6-fix
RaspBerry Pi Zero W default calendar module fix
2018-08-17 12:18:31 +02:00
György Balássy
3581158a7b Merge pull request #2 from MichMich/develop
Update Develop from original repo
2018-08-17 06:40:54 +02:00
Elan Trybuch
facfa73214 Merge branch 'develop' into rp-zero-w-es6-fix 2018-08-16 12:07:38 -04:00
Elan Trybuch
0ef4a86d42 Add patch note to CHANGELOG.md 2018-08-16 11:51:10 -04:00
Elan Trybuch
d4ec4795c3 Fix ES6 syntax bug on RaspberryPi Zero W
Following this issue https://github.com/MichMich/MagicMirror/issues/694 it seems that the Midori Browser does not recoginize ES6 syntax. Further, the use of 'var' is seen throughout the calendar module excpet on line 439, where the error is reported
2018-08-16 11:45:34 -04:00
Michael Teeuw
b13d0aa283 Merge pull request #1373 from jannekalliola/develop
Calendar: Absolute dates do not show absolute even if getRelative and urgency are set to zero
2018-08-16 12:05:22 +02:00
Michael Teeuw
a6965342e7 Update CHANGELOG.md 2018-08-16 12:00:06 +02:00
Michael Teeuw
752dfa5b7f Merge pull request #1369 from heskja/patch-2
Patch 2
2018-08-16 11:56:03 +02:00
Michael Teeuw
87aa283f22 Merge pull request #1376 from vincep5/develop
weatherforecast rainfall rounding
2018-08-16 11:55:25 +02:00
vincep5
6598ae080f weatherforecast rainfall rounding 2018-08-07 11:48:10 -05:00
Janne Kalliola
7c5e8a66e4 Added also description of the change to changelog 2018-08-05 19:49:26 +03:00
Janne Kalliola
c9577bcdc5 Added an if to use absolute dates with all events 2018-08-05 19:47:27 +03:00
heskja
8254c2e83c Merge pull request #1 from heskja/patch-1
Update nb.json
2018-08-03 20:24:46 +02:00
heskja
20a9ac841d Update nn.json
Added translation for "FEELS"
2018-08-03 20:23:19 +02:00
heskja
ae86b75d89 Update nb.json
Added translation for "FEELS"
2018-08-03 20:22:44 +02:00
György Balássy
93a0afe612 Merge pull request #1 from MichMich/develop
Sync Develop from original repo
2018-08-02 06:26:23 +02:00
Michael Teeuw
439027220b Merge pull request #1366 from Ybbet/alert_css
Alert css #1353
2018-08-01 10:19:52 +02:00
Teddy Payet
4a07272d7a Changelog.md updated 2018-08-01 09:42:23 +02:00
Teddy Payet
81432b54a3 Classes for alert module
Use of classes instead of inline style. With those modifications, it will be easier to personnalize the alert with custom.css
2018-08-01 09:37:27 +02:00
Michael Teeuw
b84a6e0c02 Merge pull request #1358 from jagobagascon/develop
Added missing spanish text
2018-07-15 19:47:04 +02:00
jagoba
37dc5a00e8 Merge branch 'bugfix/spanish-missing-localization' into develop 2018-07-15 19:21:59 +02:00
jagoba
e6edf85fbe Added Spanish translation for "FEELS" 2018-07-15 19:13:04 +02:00
Michael Teeuw
cb533a26f2 Merge pull request #1356 from balassy/bugfix/hungarian-localization
Updating the Hungarian localization
2018-07-13 22:01:56 +02:00
György Balássy
a7278f76a8 UPDATED: The CHANGELOG.md file with description of the changes in the Hungarian localization. 2018-07-13 16:42:47 +02:00
György Balássy
80bd32382f CHANGED: The Hungarian localization of the updatenotification module is changed to be more natural, because the existing messages felt like they were created with machine translation, and they were not only unnatural, but also misleading. 2018-07-13 16:32:32 +02:00
György Balássy
db21ced104 ADDED: Missing Hungarian localization for the "FEELS" resource key. 2018-07-13 16:26:15 +02:00
György Balássy
717c6555cb ADDED: Missing Hungarian localization for the "WEEK" resource key. 2018-07-13 16:23:34 +02:00
Michael Teeuw
a412e4af5c Merge pull request #1354 from Ybbet/develop
Wrong mixup… (cf german and spanish)
2018-07-11 02:21:14 +02:00
Teddy Payet
3350bf1ac6 CHANGELOG 2018-07-11 01:52:29 +02:00
Teddy Payet
4aa3353a1d Wrong mixup… (cf german and spanish)
Thanks fewieden.
2018-07-11 01:45:16 +02:00
Michael Teeuw
ff48a58537 Merge pull request #1352 from Ybbet/develop
Add some translations (mostly french).
2018-07-10 16:15:13 +02:00
Teddy Payet
08fa511d17 Add some translations (mostly french). 2018-07-10 15:03:54 +02:00
Michael Teeuw
c295115ffc Merge pull request #1347 from cederstrom/toggle-news-article-fullscreen
Abillity to toggle news article in fullscreen
2018-07-10 12:41:20 +02:00
Michael Teeuw
5fb14610ec Merge pull request #1348 from cederstrom/swedish-translations
Swedish translations
2018-07-10 12:40:04 +02:00
Andreas Cederström
e87c2350b7 Update CHANGELOG.md 2018-07-07 17:36:51 +02:00
Andreas Cederström
44e691e840 Update CHANGELOG.md 2018-07-07 17:35:04 +02:00
Andreas Cederström
b5a7234cf3 Swedish translation for "FEELS" 2018-07-07 17:26:17 +02:00
Andreas Cederström
d12509957f Abillity to toggle article in fullscreen 2018-07-07 16:50:10 +02:00
Michael Teeuw
f01e7b7e20 Prepare for 2.5.0 2018-07-04 11:32:04 +02:00
Michael Teeuw
6aa156d956 Merge pull request #1343 from MichMich/develop
Release 2.4.1
2018-07-04 11:27:05 +02:00
Michael Teeuw
ef5ea93de1 Prepare for release 2.4.1 2018-07-04 11:20:37 +02:00
Michael Teeuw
b4913f51f2 Merge pull request #1341 from jannekalliola/master
Fixed parsing date
2018-07-03 17:08:07 +02:00
Janne Kalliola
dc3e960e79 Fixed parsing date, as dt_txt is missing from certain weather API results 2018-07-02 23:22:09 +03:00
fewieden
0fe79b5288 indoor data, new filter, small cleanup 2018-07-02 15:43:24 +02:00
Michael Teeuw
1f76bd1942 Setup the next release (2.5.0). 2018-07-01 21:01:41 +02:00
Michael Teeuw
3545f80920 Merge pull request #1338 from MichMich/develop
Release 2.4.0
2018-07-01 20:50:46 +02:00
Michael Teeuw
0b2d1564ef Prepare to release 2.4.0 2018-07-01 20:43:04 +02:00
Michael Teeuw
fdacf824b3 Merge pull request #1337 from ShameerAshraf/develop
Fixed Wind Chill and Heat Index for Kelvin
2018-06-30 21:03:19 +02:00
Shameer Ashraf
5c01a44644 Updated changelog 2018-06-29 13:27:55 -04:00
Shameer Ashraf
4eb49d872b Updated changelog 2018-06-29 13:24:28 -04:00
Shameer Ashraf
34e5f29419 Fixed Wind Chill in Kelvin 2018-06-29 01:00:20 -04:00
Shameer Ashraf
f4910f0a8e Fixed Heat Index for Kelvin 2018-06-29 00:23:04 -04:00
Michael Teeuw
c8c14611dc Merge pull request #1334 from mdrayer/quick-fix-readme-raspberry-pi
Correct the "Raspberry Pi" link in the ToC.
2018-06-27 20:22:30 +02:00
Michael Drayer
491201991e Correct the "Raspberry Pi" link in the ToC. 2018-06-27 14:18:25 -04:00
Michael Teeuw
401f3574fd Update CHANGELOG.md 2018-06-27 10:29:49 +02:00
Michael Teeuw
173a86172c Add update translations. 2018-06-27 10:29:08 +02:00
Michael Teeuw
9ecbff024a Update CHANGELOG.md 2018-06-27 10:26:30 +02:00
Michael Teeuw
1b5be34be4 Merge pull request #1333 from ubertao/fixlocale
Fix locale id zh_cn -> zh-cn, zh_tw -> zh-tw, pt_br -> pt-br
2018-06-27 10:25:34 +02:00
Michael Teeuw
ceb3a997b6 Merge pull request #1330 from pintman/patch-1
minor typo in position fixed.
2018-06-27 10:23:15 +02:00
Ubertao
b1ead7fec8 Fix locale id zh_cn -> zh-cn, zh_tw -> zh-tw, pt_br -> pt-br 2018-06-27 14:09:02 +08:00
Michael Teeuw
d534dbb006 Merge pull request #1331 from flyingchipmunk/dev_newsfeed_logging
Add option to newsfeed for logging errors
2018-06-27 02:39:14 +02:00
Matthew Veno
e56377117b Add option to newsfeed for logging errors
- 'logFeedWarnings' added to newsfeed config, defaulted to false
- Only log parse feed errors when logFeedWarnings is true
- Updated README and CHANGELOG
- Fixes #1329
2018-06-26 20:01:28 -04:00
Marco Bakera
63483dc6c3 minor typo in position fixed. 2018-06-24 14:29:55 +02:00
fewieden
66ceafd010 show indoor data, add loading message 2018-06-16 10:53:17 +02:00
Michael Teeuw
dd793650c3 Merge pull request #1314 from Ybbet/develop
Customize classes for table.
2018-06-12 09:19:16 +02:00
Teddy Payet
afd829307d Tabs and spaces from the original files
With a diff, here the orginal tabulations.
2018-06-11 23:09:00 +02:00
Teddy Payet
09abdc0f12 ESLint format
Resolve format ith eslint
2018-06-11 19:59:21 +02:00
Teddy Payet
ed4d17f578 README updated
Update of README for the new option.
2018-06-11 16:41:08 +02:00
Teddy Payet
aeeeb5a37b Add changelog 2018-06-11 14:04:06 +02:00
Teddy
dcb2e51587 Update .gitignore 2018-06-11 14:00:16 +02:00
Teddy Payet
cbc2eaf908 Customize classes for table
MagicMirror offers helper classes in the main.css. Therefore, we give
the possibility to indicate the class that we want.
2018-06-11 12:54:27 +02:00
Michael Teeuw
8808031e7c Merge pull request #1309 from sdetweil/fix_suspend
invoke callback for suspend notification, even if no dom content
2018-06-08 13:21:40 +02:00
Sam Detweiler
23ac7213d3 remove trailing spaces from reformatted else 2018-06-08 06:11:36 -05:00
Michael Teeuw
add7b44d0b Style change. 2018-06-07 16:31:49 +02:00
Michael Teeuw
1e4b7599a7 Merge branch 'develop' into fix_suspend 2018-06-07 16:29:16 +02:00
Sam Detweiler
54443b038a Revert "fix changelog"
This reverts commit c3f03e3f95.
2018-06-07 08:09:39 -05:00
Sam Detweiler
c3f03e3f95 fix changelog 2018-06-07 08:04:49 -05:00
Sam Detweiler
18135624f6 update changelog 2018-06-07 08:02:16 -05:00
Sam Detweiler
11238d6b71 fix tabs 2018-06-07 07:59:07 -05:00
Sam Detweiler
848f94b1e0 invoke callback for suspend notification, even if no dom content 2018-06-07 07:50:42 -05:00
Michael Teeuw
d47cfe9504 Merge pull request #1304 from kjb085/kb/calendar-regex
Add regex filtering to calendar module
2018-06-05 21:02:56 +02:00
Kenn Breece
70dccff293 Add regex filtering to calendar module 2018-06-03 21:12:31 -04:00
Michael Teeuw
e40873710b Merge pull request #1302 from idoodler/develop
Ability to fetch compliments from a remote server
2018-06-03 19:46:01 +02:00
idoodler
b140ef3b7a Ability to fetch compliments from a remote server 2018-06-03 15:47:56 +02:00
Michael Teeuw
3b7b74aa67 Merge pull request #1297 from OiYouYeahYou/linting-fix
Add and lint clientonly/index.js
2018-05-29 11:56:18 +02:00
Jason
de8e5b2d69 Merge branch 'develop' into linting-fix 2018-05-26 19:44:06 +01:00
Jason
afea33b0e3 Changelog 2018-05-26 19:42:58 +01:00
Jason
b44fbc1e4f add and lint clientonly 2018-05-26 19:36:46 +01:00
Michael Teeuw
c4dee3dd8d Merge pull request #1293 from derRAV3N/patch-1
Add note to README.md
2018-05-22 15:27:03 +02:00
derRAV3N
091e024032 Add note to README.md
Add note to README.md to not add calendars that have entries before 1st January 1970.
2018-05-22 15:14:05 +02:00
Michael Teeuw
0e030f7f48 Add information about the Electron update. 2018-05-21 14:06:50 +02:00
fewieden
3341c9e3bf start with forecast template 2018-05-21 10:57:22 +02:00
fewieden
91ddc00f7e fix moment, add unit filter 2018-05-21 10:56:46 +02:00
Michael Teeuw
3049ba0b24 Merge pull request #1290 from edward-shen/develop
newsfeed now remembers user configuration settings for descriptions after fullscreen view. Fixes #1282.
2018-05-16 07:27:38 +02:00
Edward Shen
55a161fafe Fixes #1282.
Added a runtime var isShowingDescription that gets reset to user config.
this.config.showDescription no longer mutates during runtime.
Changelog has been updated to include this fix.
2018-05-15 20:37:45 -04:00
Michael Teeuw
349af24c81 Merge pull request #1287 from ringzer/patch-1
Update README.md
2018-05-12 12:33:25 +02:00
ringzer
788f1c4b3e Update README.md
Included /home/pi/MagicMirror/ path when copying config.js.sample and running npm run config:check
2018-05-11 16:47:03 +01:00
Michael Teeuw
889af461c6 Upgrade to Electron 2.0.0. 2018-05-11 16:23:43 +02:00
Michael Teeuw
df86e59089 Merge pull request #1284 from jrlambs/develop
New calendar display format
2018-05-11 15:36:36 +02:00
=
c6bf69cce4 fix linting errors. add line to changelog 2018-05-10 19:54:01 -04:00
=
e492012004 fix missing s on timeFormat 2018-05-09 22:36:53 -04:00
=
94c46f9881 New calendar display format with date headers for days and times listed next to events for that date
IE:

Sunday, May 1st
  2:00 pm       Soccer
  4:00 pm       Basketball
2018-05-09 22:32:15 -04:00
Michael Teeuw
1eaa9d32ea Merge pull request #1283 from jannekalliola/develop
Changed weatherforecast to use dt_txt field
2018-05-09 09:35:49 +02:00
Janne Kalliola
0e2e8d2e2a Changed weatherforecast to use dt_txt field 2018-05-08 18:45:38 +03:00
Michael Teeuw
cfb39c6364 Merge pull request #1279 from parnic/develop
Fixed coloredSymbolOnly
2018-05-05 18:38:54 +02:00
Parnic
173499f496 Fixed coloredSymbolOnly 2018-05-05 08:31:58 -05:00
Michael Teeuw
1081049074 Merge pull request #1264 from parnic/develop
Fixed heat index
2018-05-01 09:55:42 +02:00
Michael Teeuw
961dc85514 Merge pull request #1275 from john3300/colored-symbol-only
Added option to calendar module that colors only the symbol
2018-05-01 09:55:13 +02:00
Michael Teeuw
6434acd492 Merge branch 'develop' into colored-symbol-only 2018-05-01 09:55:05 +02:00
Michael Teeuw
ccb27c89d8 Merge pull request #1262 from ndom91/patch-1
Updated newsfeed.js - improved fullscreen iframe
2018-05-01 09:53:56 +02:00
Brian Johnson
8053256203 Added option to calendar module that colors only the symbol instead of the whole line 2018-04-27 11:06:45 -05:00
Parnic
4abd7301fd Updated changelog 2018-04-17 19:45:12 -05:00
Parnic
d6fe5ab417 Fixed heat index
Celsius and Fahrenheit were flipped. The index was computed in Fahrenheit but used as if it were Celsius.
2018-04-17 19:43:09 -05:00
Nico Domino
a739fbdf1d Update CHANGELOG.md 2018-04-17 00:39:05 +02:00
Nico Domino
c90a1ab6dc Updated newsfeed.js - improved fullscreen iframe
Had much better performance using 100vw (viewport width) than 100% (why - idk), but with 100% about 5% of my screen (1080x1920) to the right of the scroll bar was left black/blank, with 100vw I legitimately takes up the whole screen/viewport width. 

With the 10000 height the articles would always load about half way scrolled down. So I reduced the height and style.height to 3000. At my resolution at least, which I assume is fairly common, I had much better results. Unfortunately 3000 also isn't perfect - this still requires some tweaking. The article loads perfectly at the top of the iframe at 2500, but 2500 is much too small for most articles. 3000 seemed a good compromise, I could scroll far enoguh to read most articles on Reuters, and also load far enoguh up to read the beginning of the article.

And finally I added a "scroll back up" button notification. This seems to work flawlessly.
2018-04-17 00:25:58 +02:00
Michael Teeuw
05ef68e079 Merge pull request #1258 from jannekalliola/develop
Support for hiding on-going events
2018-04-08 18:14:39 +02:00
Michael Teeuw
dee4a7f3c7 Merge pull request #1257 from parnic/develop
Fixed to work in Midori browser
2018-04-08 18:11:00 +02:00
Janne Kalliola
75753df0d8 Added description of on-going event hiding changes to the changelog 2018-04-08 15:07:20 +03:00
Janne Kalliola
30c5d78647 Support for hiding on-going events 2018-04-08 14:57:28 +03:00
Chris Pickett
6bb4db3842 Midori 0.4.3 support 2018-04-07 20:01:53 -05:00
Chris Pickett
cc0907fcd7 Updated changelog 2018-04-07 20:00:51 -05:00
Michael Teeuw
20b018bcc7 Merge pull request #1250 from bastilimbach/master
Remove yarn-or-npm as it breaks production builds
2018-04-06 14:40:26 +02:00
Michael Teeuw
aafe2fa8d0 Update CHANGELOG.md 2018-04-06 14:39:41 +02:00
Michael Teeuw
ee7bd73b3f Merge branch 'develop' into master 2018-04-06 14:39:04 +02:00
Michael Teeuw
b67f3bd629 Move change to 2.4.0 changelog. 2018-04-06 14:37:26 +02:00
Michael Teeuw
38b81e79f8 Merge pull request #1255 from wonjerry/develop
Error in default/currentWeather
2018-04-06 14:35:19 +02:00
wonjerry
b73c549131 Error in MagicMirror/modules/default/currentWeather/currentWeather.js line 296, 300
Notice that self.config.animationSpeed can not be found because the notificationReceived function does not have "self" variable.
2018-04-06 21:25:10 +09:00
Michael Teeuw
d21d9f0141 Use Electron 2 Beta. 2018-04-06 13:21:53 +02:00
Michael Teeuw
7bb85032a1 Merge pull request #1252 from BerndKohl/feelslike-localisation
enabling translation for "feelsLike" in current weather
2018-04-06 13:11:51 +02:00
Michael Teeuw
d90446ad28 Update CHANGELOG.md 2018-04-06 13:10:41 +02:00
Michael Teeuw
8b5e2f5528 Add dutch 'Feels' temperature. 2018-04-06 13:04:55 +02:00
Michael Teeuw
1bcc3ab7f1 Add default translation. 2018-04-06 13:04:04 +02:00
Michael Teeuw
3359c3cd45 Update currentweather.js 2018-04-06 13:03:06 +02:00
Michael Teeuw
af812f3c90 Fix translation file. 2018-04-06 13:02:27 +02:00
Michael Teeuw
1e6201093b restore windChillInF variable. 2018-04-06 13:01:23 +02:00
BerndKohl
959ea69427 enabling translation for "feelsLike" in current weather
enabled translation
fixed typos in comments
added German translation
2018-04-06 12:28:47 +02:00
Sebastian Limbach
cea744a914 Remove yarn-or-npm 2018-04-03 19:38:00 +02:00
Michael Teeuw
e8baf48764 Update CHANGELOG.md 2018-04-02 14:18:28 +02:00
Michael Teeuw
41242a2ae1 Merge pull request #1248 from E3V3A/patch-5
null check for notification removal
2018-04-02 14:17:25 +02:00
Michael Teeuw
f1dee488a7 Fix indent. 2018-04-02 14:11:21 +02:00
Michael Teeuw
3b4ff1818e Update CHANGELOG.md 2018-04-02 14:03:16 +02:00
E:V:A
497145b1b5 null check for notification removal
Make sure there is something to remove, before we attempt to remove the notifications. 
- This fixes #1240
2018-04-02 14:07:25 +03:00
Michael Teeuw
10eb41d319 FIx wind chill in Fahrenheit. 2018-04-02 12:58:19 +02:00
Michael Teeuw
4daf2e4a3d Merge pull request #1246 from secuflag/develop
Update italian translation
2018-04-01 19:44:24 +02:00
secuflag
f3266a5111 Update italian translation 2018-04-01 19:38:03 +02:00
Michael Teeuw
27cac4e8b8 Merge v2.3.1 2018-04-01 19:17:08 +02:00
Michael Teeuw
60b9a5b9da Merge pull request #1245 from MichMich/electron-downgrade
v2.3.1
2018-04-01 19:12:25 +02:00
Michael Teeuw
eaaa62a7f3 Downgrade Electron. 2018-04-01 19:05:38 +02:00
Michael Teeuw
6ce732ec3d Preparation for v2.4.0. 2018-04-01 14:23:28 +02:00
Michael Teeuw
fb0cc61e09 Merge pull request #1241 from MichMich/develop
Release 2.3.0
2018-04-01 14:16:36 +02:00
Michael Teeuw
be29b5daf8 Prepare for release 2.3.0 2018-04-01 14:08:38 +02:00
Michael Teeuw
f010adabd0 Merge pull request #1232 from Kiina/develop
Update electron to 1.7.13
2018-03-28 12:27:05 +02:00
Dominic Dey-Marckmann
c93b263b1f Update electron to 1.7.13 2018-03-27 21:09:08 +02:00
Michael Teeuw
15f34d6b54 Update CHANGELOG.md 2018-03-25 14:56:20 +02:00
Michael Teeuw
d0eeb55999 Merge pull request #1186 from BonySimon/patch-1
Fix exception on translation of objects
2018-03-25 14:55:52 +02:00
Michael Teeuw
08c0d39b23 Update translator.js 2018-03-25 14:55:42 +02:00
Michael Teeuw
d0ecde3277 Merge pull request #1176 from relm923/forecast_max_days
Forecast - Max Days
2018-03-25 14:53:30 +02:00
Michael Teeuw
45ec57afd7 Merge branch 'develop' into forecast_max_days 2018-03-25 14:52:42 +02:00
Michael Teeuw
b0cd053083 Merge pull request #1202 from iampranavsethi/currentweather-module-updates
Currentweather module updates
2018-03-25 14:52:05 +02:00
Michael Teeuw
698a11be58 Merge branch 'develop' into currentweather-module-updates 2018-03-25 14:51:47 +02:00
Michael Teeuw
efb08fb1e1 Update CHANGELOG.md 2018-03-25 14:51:18 +02:00
Michael Teeuw
f89bc8422e Merge pull request #1224 from bacongobbler/clearer-install-question
capitalize "y/n" for clearer intent
2018-03-25 14:47:35 +02:00
Michael Teeuw
4bf4889a08 Merge pull request #1225 from moham96/patch-1
use shallow clone
2018-03-25 14:47:09 +02:00
Michael Teeuw
01ab8ba38e Merge pull request #1227 from E3V3A/patch-4
removed known issues as they are closed
2018-03-25 14:46:44 +02:00
E:V:A
ae6d15e812 removed known issues as they are closed 2018-03-25 12:07:29 +03:00
MOHAMMAD RASIM
1abfbe1d34 use shallow clone
not need to download the whole repo history
2018-03-24 16:11:57 +03:00
Matthew Fisher
d3095297c2 capitalize "y/n" for clearer intent
If you press enter, `choice` is an empty string and will default to "no". The convention is to capitalize the default answer so users know what happens when they auto-accept prompts.
2018-03-23 16:29:37 -07:00
Michael Teeuw
79d40d5644 Merge pull request #1199 from ThomasMirlacher/develop
Add dc:date to parsing in newsfeed module, which allows parsing of mo…
2018-03-21 12:17:23 +01:00
Thomas Mirlacher
008e305a84 use doublequotes. 2018-03-21 11:58:09 +01:00
Michael Teeuw
0379611edd Merge pull request #1218 from kjb085/kb/calendar-adv-filter
Add advanced filtering to excludedEvents
2018-03-21 11:34:41 +01:00
Kenn Breece
96d883c1c7 Merge branch 'develop' into kb/calendar-adv-filter 2018-03-20 15:38:16 -04:00
Kenn Breece
be0f262e37 Add advanced filtering to excludedEvents 2018-03-18 23:54:23 -04:00
Michael Teeuw
1676adf071 Merge pull request #1209 from E3V3A/patch-3
update node stable to 9.x
2018-03-14 10:26:25 +01:00
E:V:A
a5d5630067 update node stable to 9.x 2018-03-14 11:24:41 +02:00
Pranav Sethi
275956caba Fixed typos in README.md for currentweather. 2018-03-12 22:22:45 -04:00
Michael Teeuw
bf8ed87fc9 Merge pull request #1197 from ptz0n/patch-1
Update README.md
2018-03-12 18:34:21 +01:00
Michael Teeuw
fb3afac097 Merge pull request #1200 from djgalloway/wip-apt-y
Assume yes when installing deps on Raspberry Pi via apt-get
2018-03-12 18:33:36 +01:00
Michael Teeuw
eda8b037a9 Merge pull request #1205 from Tajnymag/develop
Added yarn support
2018-03-12 18:32:31 +01:00
Marek Lukáš
8ef14f7a54 Added changes from [9974e35] to CHANGELOG 2018-03-12 15:33:30 +01:00
Marek Lukáš
9974e35656 Added yarn support 2018-03-12 15:28:43 +01:00
Pranav Sethi
15bc5431b6 Fixed Trailling Spaces 2018-03-12 05:25:33 -04:00
Pranav Sethi
f767531d89 Fixed Trailling Spaces 2018-03-12 05:25:01 -04:00
Pranav Sethi
7285ada9dd Added feels like and kmph wind for currentweather module 2018-03-12 05:06:16 -04:00
Pranav Sethi
b9b9773df9 Merge branch 'develop' into currentweather-module-updates 2018-03-12 03:56:44 -04:00
David Galloway
c29a83b259 Assume yes when installing deps on Raspberry Pi via apt-get
Signed-off-by: David Galloway <dgallowa@redhat.com>
2018-03-11 13:17:33 -04:00
Thomas Mirlacher
fa45e66da6 Add dc:date to parsing in newsfeed module, which allows parsing of more rss feeds. 2018-03-10 00:30:45 +01:00
Erik Eng
7cbcdddac9 Merge branch 'develop' into patch-1 2018-03-07 09:18:07 +01:00
Erik Eng
a2f17900da Update README.md
Correct manual installation step.
2018-03-07 09:13:33 +01:00
Michael Teeuw
fb7e97b8ad Merge pull request #1190 from E3V3A/patch-1
made the module "this" instances into a table
2018-03-06 09:36:04 +01:00
Michael Teeuw
0c92a8a8e9 Merge pull request #1191 from E3V3A/patch-2
fix md header
2018-03-06 09:35:34 +01:00
Michael Teeuw
dcc59380e5 Merge pull request #1194 from bastilimbach/develop
Remove old docker config and link to docker repository
2018-03-06 09:33:50 +01:00
Sebastian Limbach
f9bf25f96d Add changes 2018-03-04 14:07:44 +01:00
Sebastian Limbach
cbcbea8b08 Remove old docker config 2018-03-04 13:59:45 +01:00
Pranav Sethi
62eb4f20da Fixed Trailling Spaces to Pass checks 2018-03-03 05:08:12 -05:00
Pranav Sethi
43d5311e5e Fixed Trailling Spaces 2018-03-03 05:00:26 -05:00
Pranav Sethi
a6f08a09d5 Added Feels Like and Windspeed in KMPH 2018-03-03 04:52:22 -05:00
Pranav Sethi
d93f5d7785 Added Feels Like and Windspeed in KMPH 2018-03-03 04:21:24 -05:00
E:V:A
c7170e6dc2 fix md header 2018-03-01 11:53:10 +02:00
E:V:A
bcf3ca7339 made the module "this" instances into a table 2018-03-01 09:44:57 +02:00
Steelskin3
0388f5787a Fix exception on translation of objects
Sometimes, the content of translations[module.name][key] is not a string but an entire object. It cause a crash on template.replace(...) of createStringFromTemplate(...). It is currently the case of MMM-Voice-Control and the previous commit have broked this module (10 month ago... I am surprised to be the first founded it)
2018-02-23 11:51:59 +01:00
Michael Teeuw
6514df9d96 Merge pull request #1184 from patoberli/patch-1
Update README.md
2018-02-20 11:29:27 +01:00
Michael Teeuw
8f5b9869dc Merge branch 'develop' into patch-1 2018-02-20 11:28:58 +01:00
patoberli
580c5fe23f Update README.md
Added a hint to use the full and not lite version of Raspbian, as the GUI is missing and thus ndm (electron) can't start after the installation.
2018-02-17 21:54:31 +01:00
Michael Teeuw
b0af5b26ba Merge pull request #1183 from fewieden/feature/translations-update
translations update
2018-02-17 10:30:30 +01:00
Michael Teeuw
9e898932f6 Merge pull request #1182 from fewieden/feature/automated-tests
Automated tests
2018-02-17 10:29:23 +01:00
fewieden
1f873b93f6 changelog, linting 2018-02-17 10:17:59 +01:00
fewieden
f414707f11 update translations for updatenotifications 2018-02-17 10:14:37 +01:00
fewieden
505825056c use translation template for updatenotifications 2018-02-17 10:10:57 +01:00
fewieden
38f7716738 linting 2018-02-17 09:20:34 +01:00
fewieden
a69d08b554 changelog 2018-02-17 09:18:12 +01:00
fewieden
3ccdb64833 deprecated unit tests 2018-02-16 22:09:15 +01:00
fewieden
78d8bff599 clone array, clone nested object, add safe checks for objects (memory address) 2018-02-16 19:58:28 +01:00
fewieden
a756fed70b fixed and reenabled lockstring test 2018-02-16 08:43:27 +01:00
fewieden
3e2a1e3548 linting 2018-02-16 00:08:11 +01:00
fewieden
96b2f2b3a4 clone object unit test 2018-02-16 00:01:02 +01:00
fewieden
d81d7d4f68 compare version unit test 2018-02-15 23:53:57 +01:00
fewieden
20244c4fb5 translations integration test 2018-02-15 23:22:52 +01:00
Michael Teeuw
b50d31ffe2 Merge pull request #1178 from E3V3A/develop
Added ToC
2018-02-13 09:24:36 +01:00
fewieden
d709a44960 strip comments unit test 2018-02-13 07:17:46 +01:00
E:V:A
4e4d07ced6 Added ToC
ToDo: Fix ToC links to headers
2018-02-11 18:24:31 +02:00
fewieden
d775bc9d7e loadCoreTranslationsFallback unit test 2018-02-11 09:08:09 +01:00
fewieden
85528761eb only load core callback if there is one available 2018-02-11 09:07:41 +01:00
fewieden
ad3eac9ddb loadcoretransations unit test 2018-02-11 08:58:02 +01:00
Reagan Elm
613f9fccd2 Update changelog 2018-02-10 20:56:10 -05:00
Reagan Elm
3d1741c904 Respect maxNumberOfDays regardless of endpoint 2018-02-10 20:53:38 -05:00
fewieden
26be14ba67 load unit test 2018-02-10 20:33:22 +01:00
fewieden
daa0755920 add missing parameter in documentation 2018-02-10 12:38:55 +01:00
fewieden
305d60e09b translator unit tests 2018-02-10 12:32:43 +01:00
fewieden
d0029efd02 utils unit tests 2018-02-10 12:30:33 +01:00
fewieden
fb4d42bf5b moved test 2018-02-10 12:28:30 +01:00
Michael Teeuw
20eec53b14 Add Manifesto. 2018-02-07 13:04:10 +01:00
Michael Teeuw
8343db44db Merge pull request #1173 from vvzvlad/vvzvlad_local
add variable morning afternoon times
2018-02-07 12:32:42 +01:00
vvzvlad
649652e373 Merge branch 'develop' into vvzvlad_local 2018-02-07 14:10:43 +03:00
vvzvlad
e37ed7c32d add variable morning afternoon times 2018-02-07 14:06:26 +03:00
vvzvlad
f9a525068b add variable morning afternoon times 2018-02-05 18:15:02 +03:00
Michael Teeuw
aa11e6d62e Merge pull request #1166 from henrysun18/develop
Show remote compliments on boot
2018-02-01 08:20:22 +01:00
henrysun18
6802d152da Show remote compliments at boot instead of after one updateInterval 2018-01-31 23:19:47 -05:00
Michael Teeuw
3b40f393d8 Merge pull request #1163 from pinsdorf/patch-1
corrected link to 3rd party modules wiki page
2018-01-30 13:49:37 +01:00
pinsdorf
020443ae8a corrected link to 3rd party modules wiki page
The link to the 3rd Party Modules still directs to the old wiki page, where use has to follow another link to the right page. Updated the link in README.md to navigate to the right wiki page instantly.
2018-01-30 10:59:18 +01:00
Michael Teeuw
1d0baccffc Merge pull request #1161 from thobach/master
Allow to scroll in full page article view of default newsfeed module
2018-01-30 09:47:33 +01:00
Thomas Bachmann
5426f0f329 Updated documentation for scroll mode in newsfeed module 2018-01-29 21:41:43 +01:00
Thomas Bachmann
790249dd1a Merge branch 'MichMich/develop' 2018-01-29 21:37:25 +01:00
Thomas Bachmann
446a201d25 Allow to scroll articles with gesture events 2018-01-29 21:26:34 +01:00
Thomas Bachmann
b6538d5e18 Merge remote-tracking branch 'MichMich/master' 2018-01-29 18:54:32 +01:00
Michael Teeuw
edd6043059 Fail PRs that are sent to the master branch. 2018-01-26 12:12:44 +01:00
Michael Teeuw
fe4ffeb7f1 Text cleanup. 2018-01-25 20:45:25 +01:00
Michael Teeuw
27b3875bfb Changed missing Changlog text. 2018-01-25 20:38:42 +01:00
Michael Teeuw
e2dbe8a0a2 Minor fixes. 2018-01-25 20:07:51 +01:00
Michael Teeuw
29fc7910b7 Remove Jest. Update dangerfile.js. 2018-01-25 19:51:23 +01:00
Michael Teeuw
22e2fdc707 Jest implementation to get danger.js to work. 2018-01-25 19:43:09 +01:00
Michael Teeuw
584786eb9f Temp disable danger. 2018-01-25 17:00:51 +01:00
Michael Teeuw
d803d9eaf9 Import 'includes' from lodash. 2018-01-25 16:39:49 +01:00
Michael Teeuw
bad6575d83 Add Danger.js 2018-01-25 16:24:05 +01:00
Michael Teeuw
fbcb7ae836 Update README.md 2018-01-23 19:10:37 +01:00
Michael Teeuw
2c1a1b10c8 Merge pull request #1147 from E3V3A/patch-2
Update README.md
2018-01-23 09:51:15 +01:00
E:V:A
155fb16a8a Update README.md
Updated README by reformatting and restructuring.
- Added, Clarified and corrected grammatics and wrong info 
- Moved/Removed some redundant parts
2018-01-23 10:44:55 +02:00
Michael Teeuw
b1ab2ce96a Merge pull request #1146 from cederstrom/put-article-in-front-of-modules
Put article iframe in front of modules
2018-01-21 11:33:22 +01:00
Andreas Cederström
f299ba6218 Put article ifram in front of modules
Before this change the article was brought up in its ifram in fullscreen and you could still see the other modules in front of it
2018-01-20 23:46:58 +01:00
Michael Teeuw
d167ad1923 Merge pull request #1136 from E3V3A/patch-2
Update README
2018-01-19 09:15:54 +01:00
E:V:A
93626e8154 Fixed bullet points markup for lint 2018-01-19 09:13:59 +02:00
Michael Teeuw
d5040c091a Merge pull request #1143 from shbatm/bug-fix
Fix for #1140 - sendNotification module errors after #1116
2018-01-18 13:35:47 +01:00
shbatm
868daef0f0 Fix for #1140 - sendNotification module errors after #1116 2018-01-17 09:49:17 -06:00
Michael Teeuw
dc8e85e7f2 Merge pull request #1139 from amcolash/patch-1
Change English translation to "In 2 days"
2018-01-16 09:20:57 +01:00
Michael Teeuw
22d32d7ca3 Merge pull request #1141 from ConnorChristie/old-dom-event-fix
Fix to emit DOM_OBJECTS_CREATED event after module DOMs have actually loaded
2018-01-16 09:20:39 +01:00
Connor Christie
2d500f8074 Fix to emit DOM_OBJECTS_CREATED event after module DOMs have actually loaded 2018-01-14 22:03:09 -06:00
Andrew McOlash
452cdc17c6 Change English translation to "In 2 days" 2018-01-14 15:52:15 -06:00
E:V:A
bcbfee0321 Update README
Updated README to warn about long installation time as discussed in #1124.
2018-01-12 10:00:35 +02:00
Michael Teeuw
dab2e7ede3 Merge pull request #1127 from roramirez/set-version-test-7-node
Set only 7 version of node to run tests in Travis CI
2018-01-08 11:26:25 +01:00
Michael Teeuw
d91acb8352 Merge pull request #1126 from d-Rickyy-b/patch-1
Fix typo in newsfeed documentation
2018-01-08 11:23:49 +01:00
Rodrigo Ramírez Norambuena
373dd8058e Set only 7 version of node to run tests in Travis CI 2018-01-07 01:03:00 -03:00
Rico
de6310e52a Fix typo
A little typo which lead to poor formatting
2018-01-07 03:30:01 +01:00
Michael Teeuw
8c297a4a4c Merge pull request #1123 from E3V3A/patch-1
Added general advice
2018-01-06 19:49:44 +01:00
E:V:A
4eb5c817bc fixed typos 2018-01-06 20:19:43 +02:00
E:V:A
07e4b26b9e Added general advice 2018-01-06 19:57:46 +02:00
Michael Teeuw
b63aa62985 Merge pull request #1121 from henrikra/master
Add basic typescript types for module
2018-01-06 14:29:52 +01:00
Henrik Raitasola
ca701c0580 Merge branch 'master' of github.com:henrikra/MagicMirror 2018-01-06 15:26:51 +02:00
Henrik Raitasola
e37043a6a8 Solve conflict 2018-01-06 15:26:38 +02:00
Michael Teeuw
7c26975d14 Merge branch 'develop' into master 2018-01-06 14:16:21 +01:00
Henrik Raitasola
47f8a43637 Add changelog 2018-01-06 15:10:10 +02:00
Henrik Raitasola
1238c0cefe Rename file to be more explicit 2018-01-06 15:06:58 +02:00
Henrik Raitasola
4c35fda045 Add most used module properties 2018-01-06 15:04:54 +02:00
Henrik Raitasola
780124c2f5 Add basic types to get started 2018-01-06 14:51:32 +02:00
Michael Teeuw
38e0af41ce Merge pull request #1116 from ConnorChristie/async-dom
DOM creation notifications in cases of async template rendering
2018-01-04 21:51:13 +01:00
Connor Christie
601e99eec0 Merge branch 'develop' into async-dom 2018-01-02 18:10:07 -06:00
Connor Christie
745a2adee7 Merge branch 'develop' into async-dom 2018-01-02 18:08:55 -06:00
Connor Christie
9e83234df1 Update changelog 2018-01-02 18:06:21 -06:00
Connor Christie
e45eeadf7d Merge remote-tracking branch 'origin/master' into async-dom 2018-01-02 18:04:03 -06:00
Michael Teeuw
9a778cea6b Merge v2.2.2 changes. 2018-01-02 18:46:41 +01:00
Michael Teeuw
20823bfc87 Add missing package-lock.json. 2018-01-02 18:41:33 +01:00
Connor Christie
be3d703692 Fix linter errors 2018-01-01 10:55:39 -06:00
Connor Christie
e2df5739f0 Update module docs 2018-01-01 10:40:52 -06:00
Connor Christie
7bb11d6436 Add documentation regarding updates 2018-01-01 10:38:00 -06:00
Connor Christie
80b84212cc Add notification for module dom creation with async support 2018-01-01 10:23:15 -06:00
Connor Christie
4a1bee769b Add true module dom creation events 2018-01-01 09:42:34 -06:00
Michael Teeuw
de99a7aeaf Merge 2.2.1 changes. 2018-01-01 14:23:38 +01:00
Michael Teeuw
538a2acbf5 Fix linting errors. 2018-01-01 13:38:07 +01:00
Michael Teeuw
8d0e453666 Preparation for v2.3.0 release. 2018-01-01 12:59:28 +01:00
Michael Teeuw
07d35a8513 Remove todo item. 2017-10-19 16:52:57 +02:00
Michael Teeuw
16c887814e Show humidity. 2017-10-19 16:51:51 +02:00
Michael Teeuw
22a50b72fd Show unit. 2017-10-19 16:43:12 +02:00
Michael Teeuw
a79e1b6ca1 Rename templates to .njk files to allow syntax highlighting. 2017-10-18 13:52:11 +02:00
Michael Teeuw
995296ef53 Merge branch 'develop' into weather-refactor 2017-10-18 13:49:53 +02:00
Michael Teeuw
ab732b5435 Make all visiable values dynamic. 2017-10-18 13:38:56 +02:00
Michael Teeuw
241ff5cb6e Set temperature rounding. 2017-10-18 12:19:02 +02:00
Michael Teeuw
ec2169e079 Merge branch 'develop' into weather-refactor 2017-10-18 12:01:44 +02:00
Michael Teeuw
d567fd4842 Merge branch 'develop' into weather-refactor 2017-10-18 11:59:29 +02:00
Michael Teeuw
0776dfc80e Minor changes. 2017-10-18 11:58:45 +02:00
Michael Teeuw
681a845ef3 Add Darksky provider. 2017-10-03 14:38:54 +02:00
Michael Teeuw
ad240cf52f Fix lint errors. 2017-10-01 16:19:14 +02:00
Michael Teeuw
99e3a47dde Use templates to render weather. 2017-10-01 13:50:15 +02:00
Michael Teeuw
3fa810b7b8 Merge branch 'develop' into weather-refactor 2017-10-01 13:25:52 +02:00
Nicholas Hubbard
cd129fb055 Revert "Fix Indentation?"
This reverts commit 2bf18d8bda.
2017-09-30 19:44:54 -04:00
Nicholas Hubbard
837e275bfd Update fork 2017-09-29 10:11:46 -04:00
Nicholas Hubbard
7be6031e19 Merge branch 'weather-refactor' of https://github.com/MichMich/MagicMirror into weather-refactor 2017-09-29 10:11:22 -04:00
Michael Teeuw
ff9c6bac0a Add a small forecast example. 2017-09-22 13:26:44 +02:00
Michael Teeuw
713111254b First implementation of the currentWeatherView 2017-09-22 12:26:47 +02:00
Michael Teeuw
5b1462a3e8 Add readme. 2017-09-22 10:37:39 +02:00
Nicholas Hubbard
2bf18d8bda Fix Indentation? 2017-09-21 20:12:25 -04:00
Nicholas Hubbard
7f2e643e62 Add Dark Sky Module 2017-09-21 20:06:42 -04:00
Michael Teeuw
ef172592b8 A first setup of the new Weather Module 2017-09-21 16:38:18 +02:00
Rodrigo Ramírez Norambuena
f34407fc43 Add 404 test HTTP code for vendors 2017-04-18 23:44:50 -03:00
261 changed files with 15349 additions and 14485 deletions

15
.editorconfig Normal file
View 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

View File

@@ -1,6 +1 @@
vendor/*
!/vendor/vendor.js
!/modules/default/**
!/modules/node_helper
!/modules/node_helper/**
!/modules/default/defaultmodules.js
modules/default/calendar/vendor/*

View File

@@ -1,16 +1,30 @@
{
"rules": {
"indent": ["error", "tab"],
"quotes": ["error", "double"],
"max-len": ["error", 250],
"curly": "error",
"camelcase": ["error", {"properties": "never"}],
"no-trailing-spaces": ["error", {"ignoreComments": false }],
"no-irregular-whitespace": ["error"]
},
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
"plugins": ["prettier"],
"env": {
"browser": true,
"node": true,
"es6": true
"es6": true,
"mocha": true,
"node": true
},
"globals": {
"config": true,
"Log": true,
"MM": true,
"Module": true,
"moment": true
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2017,
"ecmaFeatures": {
"globalReturn": true
}
},
"rules": {
"prettier/prettier": "error",
"eqeqeq": "error",
"no-prototype-builtins": "off",
"no-unused-vars": "off"
}
}

View File

@@ -1,25 +1,24 @@
Contribution Policy for MagicMirror²
====================================
# Contribution Policy for MagicMirror²
Thanks for contributing to MagicMirror²!
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
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.
To run ESLint, use `grunt eslint`.
To run ESLint, use `npm run lint:js`.
### 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
@@ -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:
**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.

View File

@@ -1,15 +1,33 @@
Please only submit reproducible issues.
## 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)
## 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)
## 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:
[https://github.com/sdetweil/MagicMirror_scripts](https://github.com/sdetweil/MagicMirror_scripts)
## 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:
[https://github.com/bastilimbach/docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror)
---
## I found a bug in MagicMirror
Please make sure to only submit reproducible issues. You can safely remove everything above the dividing line.
When submitting a new issue, please supply the following information:
**Platform**: Place your platform here... give us your web browser/Electron version *and* your hardware (Raspberry Pi 2/3, Windows, Mac, Linux, System V UNIX).
**Platform**: Place your platform here... give us your web browser/Electron version _and_ your hardware (Raspberry Pi 2/3, 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 8 or later.
**MagicMirror Version**: Now that the versions have split, tell us if you are using the PHP version (v1) or the newer JavaScript version (v2).
**MagicMirror Version**: Please let us now which version of MagicMirror you are running. It can be found in the `package.log` file.
**Description**: Provide a detailed description about the issue and include specific details to help us understand the problem. Adding screenshots will help describing the problem.

View File

@@ -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.
Thanks!
* Does the pull request solve a **related** issue?
* If so, can you reference the issue?
* What does the pull request accomplish? Use a list if needed.
* If it includes major visual changes please add screenshots.
- Does the pull request solve a **related** issue?
- If so, can you reference the issue?
- What does the pull request accomplish? Use a list if needed.
- If it includes major visual changes please add screenshots.

19
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- under investigation
- pr welcome
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

16
.gitignore vendored
View File

@@ -8,10 +8,11 @@ pids
*.seed
lib-cov
coverage
.grunt
.lock-wscript
build/Release
node_modules
/node_modules/**/*
fonts/node_modules/**/*
vendor/node_modules/**/*
jspm_modules
.npm
.node_repl_history
@@ -19,6 +20,9 @@ jspm_modules
# Visual Studio Code ignoramuses.
.vscode/
# IDE Code ignoramuses.
.idea/
# Various Windows ignoramuses.
Thumbs.db
ehthumbs.db
@@ -54,12 +58,6 @@ Temporary Items
.directory
.Trash-*
# Various Magic Mirror ignoramuses and anti-ignoramuses.
# Don't ignore the node_helper core module.
!/modules/node_helper
!/modules/node_helper/**
# Ignore all modules except the default modules.
/modules/**
!/modules/default
@@ -78,3 +76,5 @@ Temporary Items
*.orig
*.rej
*.bak
!/tests/node_modules/**/*

5
.prettierignore Normal file
View File

@@ -0,0 +1,5 @@
package-lock.json
/config/**/*
/modules/default/calendar/vendor/ical.js/**/*
/vendor/**/*
!/vendor/vendor.js

3
.prettierrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"trailingComma": "none"
}

14
.snyk
View File

@@ -1,14 +0,0 @@
version: v1.5.2
ignore: {}
patch:
'npm:minimatch:20160620':
- snyk > recursive-readdir > minimatch:
patched: '2016-07-30T14:02:31.280Z'
'npm:negotiator:20160616':
- socket.io > engine.io > accepts > negotiator:
patched: '2016-07-30T14:02:31.280Z'
'npm:ws:20160624':
- socket.io > engine.io > ws:
patched: '2016-07-30T14:02:31.280Z'
- socket.io > socket.io-client > engine.io-client > ws:
patched: '2016-07-30T14:02:31.280Z'

View File

@@ -1,5 +0,0 @@
{
"extends": "stylelint-config-standard",
"font-family-name-quotes": "double-where-recommended",
"block-no-empty": false
}

7
.stylelintrc.json Normal file
View File

@@ -0,0 +1,7 @@
{
"extends": ["stylelint-prettier/recommended"],
"plugins": ["stylelint-prettier"],
"rules": {
"prettier/prettier": true
}
}

View File

@@ -1,20 +1,25 @@
dist: trusty
language: node_js
node_js:
- "8"
- "7"
- "6"
- "5.1"
- 10
- lts/*
- node
before_install:
- npm i -g npm
before_script:
- npm install grunt-cli -g
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- sleep 5
- yarn danger ci
- "export DISPLAY=:99.0"
- "export ELECTRON_DISABLE_SANDBOX=1"
- "sh -e /etc/init.d/xvfb start"
- sleep 5
script:
- grunt
- npm run test:unit
- npm run test:e2e
- npm run test:prettier
- npm run test:js
- npm run test:css
- npm run test:e2e
- npm run test:unit
after_script:
- npm list
- npm list
cache:
directories:
- node_modules
directories:
- node_modules

View File

@@ -1,7 +1,453 @@
# MagicMirror² Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/).
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror²
## [2.12.0] - 2020-07-01
Special thanks to the following contributors: @AndreKoepke, @andrezibaia, @bryanzzhu, @chamakura, @DarthBrento, @Ekristoffe, @khassel, @Legion2, @ndom91, @radokristof, @rejas, @XBCreepinJesus & @ZoneMR.
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`.
### Added
- Added option to config the level of logging.
- Added prettier for an even cleaner codebase.
- Hide Sunrise/Sunset in Weather module.
- Hide Sunrise/Sunset in Current Weather module.
- Added Met Office DataHub (UK) provider.
### 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.
- Added location title wrapping for calendar module.
- Updated the BG translation.
### 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)
- Support multiple instances of calendar module with different config. [#1109](https://github.com/MichMich/MagicMirror/issues/1109)
- Fix the use of "maxNumberOfDays" in the module "weatherforecast". [#2018](https://github.com/MichMich/MagicMirror/issues/2018)
- Throw error when check_config fails. [#1928](https://github.com/MichMich/MagicMirror/issues/1928)
- Bug fix related to 'maxEntries' not displaying Calendar events. [#2050](https://github.com/MichMich/MagicMirror/issues/2050)
- Updated ical library to latest version. [#1926](https://github.com/MichMich/MagicMirror/issues/1926)
## [2.11.0] - 2020-04-01
🚨 READ THIS BEFORE UPDATING 🚨
In the past years the project has grown a lot. This came with a huge downside: poor maintainability. If I let the project continue the way it was, it would eventually crash and burn. More important: I would completely lose the drive and interest to continue the project. Because of this the decision was made to simplify the core by removing all side features like automatic installers and support for exotic platforms. This release (2.11.0) is the first real release that will reflect (parts) of these changes. As a result of this, some things might break. So before you continue make sure to backup your installation. Your config, your modules or better yet: your full MagicMirror folder. In other words: update at your own risk.
For more information regarding this major change, please check issue [#1860](https://github.com/MichMich/MagicMirror/issues/1860).
### Deleted
- Remove installers.
- Remove externalized scripts.
- Remove jshint dependency, instead eslint checks your config file now
### Added
- Brazilian translation for "FEELS".
- Ukrainian translation.
- Finnish translation for "PRECIP", "UPDATE_INFO_MULTIPLE" and "UPDATE_INFO_SINGLE".
- Added the ability to hide the temp label and weather icon in the `currentweather` module to allow showing only information such as wind and sunset/rise.
- The `clock` module now optionally displays sun and moon data, including rise/set times, remaining daylight, and percent of moon illumination.
- Added Hebrew translation.
- Add HTTPS support and update config.js.sample
- Run tests on long term support and latest stable version of nodejs
- Added the ability to configure a list of modules that shouldn't be update checked.
- Run linters on git commits
- Added date functionality to compliments: display birthday wishes or celebrate an anniversary
- Add HTTPS support for clientonly-mode.
### Fixed
- Force declaration of public ip address in config file (ISSUE #1852)
- Fixes `run-start.sh`: If running in docker-container, don't check the environment, just start electron (ISSUE #1859)
- Fix calendar time offset for recurring events crossing Daylight Savings Time (ISSUE #1798)
- Fix regression in currentweather module causing 'undefined' to show up when config.hideTemp is false
- Fix FEELS translation for Croatian
- Fixed weather tests [#1840](https://github.com/MichMich/MagicMirror/issues/1840)
- Fixed Socket.io can't be used with Reverse Proxy in serveronly mode [#1934](https://github.com/MichMich/MagicMirror/issues/1934)
- Fix update checking skipping 3rd party modules the first time
### Changed
- Remove documentation from core repository and link to new dedicated docs site: [docs.magicmirror.builders](https://docs.magicmirror.builders).
- Updated config.js.sample: Corrected some grammar on `config.js.sample` comment section.
- Removed `run-start.sh` script and update start commands:
- To start using electron, use `npm run start`.
- To start in server only mode, use `npm run server`.
- Remove redundant logging from modules.
- Timestamp in log output now also contains the date
- Turkish translation.
- Option to configure the size of the currentweather module.
## [2.10.1] - 2020-01-10
### Changed
- Updated README.md: Added links to the official documentation website and remove links to broken installer.
## [2.10.0] - 2020-01-01
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`.
### Added
- Timestamps in log output.
- Padding in dateheader mode of the calendar module.
- New upgrade script to help users consume regular updates installers/upgrade-script.sh.
- New script to help setup pm2, without install installers/fixuppm2.sh.
### Updated
- 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 raspberry.sh installer script to handle new platform issues, split node/npm, pm2, and screen saver changes.
- Improve handling for armv6l devices, where electron support has gone away, add optional serveronly config option.
- Improved run-start.sh to handle for serveronly mode, by choice, or when electron not available.
- Only check for xwindows running if not on macOS.
### Fixed
- 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.
- Fix handling of config.js for serverOnly mode commented out.
- Fixed issue in calendar module where the debug script didn't work correctly with authentication.
- Fixed issue that some full day events were not correctly recognized as such.
- Display full day events lasting multiple days as happening today instead of some days ago if they are still ongoing.
## [2.9.0] - 2019-10-01
**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
- Spanish translation for "PRECIP".
- Adding a Malay (Malaysian) translation for MagicMirror².
- Add test check URLs of vendors 200 and 404 HTTP CODE.
- Add tests for new weather module and helper to stub ajax requests.
### Updated
- Updatenotification module: Display update notification for a limited (configurable) time.
- Enabled e2e/vendor_spec.js tests.
- 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.
### Fixed
- Updatenotification module: Properly handle race conditions, prevent crash.
- 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 weatherforecast module not displaying rain amount on fallback endpoint.
- Notifications CLOCK_SECOND & CLOCK_MINUTE being from startup instead of matched against the clock and avoid drifting.
## [2.8.0] - 2019-07-01
**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
- Option to show event location in calendar
- Finnish translation for "Feels" and "Weeks"
- Russian translation for “Feels”
- Calendar module: added `nextDaysRelative` config option
- Add `broadcastPastEvents` config option for calendars to include events from the past `maximumNumberOfDays` in event broadcasts
- Added feature to broadcast news feed items `NEWS_FEED` and updated news items `NEWS_FEED_UPDATED` in default [newsfeed](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/newsfeed) module (when news is updated) with documented default and `config.js` options in [README.md](https://github.com/MichMich/MagicMirror/blob/develop/modules/default/newsfeed/README.md)
- Added notifications to default `clock` module broadcasting `CLOCK_SECOND` and `CLOCK_MINUTE` for the respective time elapsed.
- Added UK Met Office Datapoint feed as a provider in the default weather module.
- Added new provider class
- Added suncalc.js dependency to calculate sun times (not provided in UK Met Office feed)
- Added "tempUnits" and "windUnits" to allow, for example, temp in metric (i.e. celsius) and wind in imperial (i.e. mph). These will override "units" if specified, otherwise the "units" value will be used.
- Use Feels Like temp from feed if present
- Optionally display probability of precipitation (PoP) in current weather (UK Met Office data)
- Automatically try to fix eslint errors by passing `--fix` option to it
- Added sunrise and sunset times to weathergov weather provider [#1705](https://github.com/MichMich/MagicMirror/issues/1705)
- Added "useLocationAsHeader" to display "location" in `config.js` as header when location name is not returned
- 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
- English translation for "Feels" to "Feels like"
- Fixed the example calendar url in `config.js.sample`
- Update `ical.js` to solve various calendar issues.
- Update weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
- Only update clock once per minute when seconds aren't shown
### Fixed
- 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
- Allowance HTML5 autoplay-policy (policy is changed from Chrome 66 updates)
- Handle SIGTERM messages
- Fixes sliceMultiDayEvents so it respects maximumNumberOfDays
- Minor types in default NewsFeed [README.md](https://github.com/MichMich/MagicMirror/blob/develop/modules/default/newsfeed/README.md)
- Fix typos and small syntax errors, cleanup dependencies, remove multiple-empty-lines, add semi-rule
- Fixed issues with calendar not displaying one-time changes to repeating events
- Updated the fetchedLocationName variable in currentweather.js so that city shows up in the header
### Updated installer
- 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
- check for npm installed. node install doesn't do npm anymore
- check for mac as part of PM2 install, add install option string
- update pm2 config with current username instead of hard coded 'pi'
- check for screen saver config, "/etc/xdg/lxsession", bypass if not setup
## [2.7.1] - 2019-04-02
Fixed `package.json` version number.
## [2.7.0] - 2019-04-01
**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
- Italian translation for "Feels"
- Basic Klingon (tlhIngan Hol) translations
- Disabled the screensaver on raspbian with installation script
- Added option to truncate the number of vertical lines a calendar item can span if `wrapEvents` is enabled.
- Danish translation for "Feels" and "Weeks"
- Added option to split multiple day events in calendar to separate numbered events
- Slovakian translation
- Alerts now can contain Font Awesome icons
- Notifications display time can be set in request
- Newsfeed: added support for `ARTICLE_INFO_REQUEST` notification
- Add `name` config option for calendars to be sent along with event broadcasts
### Updated
- 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
- More verbose error message on console if the config is malformed
- Updated installer script to install Node.js version 10.x
### 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 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).
- Fixed analogue clock border display issue where non-black backgrounds used (previous fix for issue 611)
- Fixed compatibility issues caused when modules request different versions of Font Awesome, see issue [#1522](https://github.com/MichMich/MagicMirror/issues/1522). MagicMirror now uses [Font Awesome 5 with v4 shims included for backwards compatibility](https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4#shims).
- 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: 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)
- 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 missing calendar fetchers after server process restarts [#1589](https://github.com/MichMich/MagicMirror/issues/1589)
- Notification: fixed background color (was white text on white background)
- Use getHeader instead of data.header when creating the DOM so overwriting the function also propagates into it
- Fix documentation of `useKMPHwind` option in currentweather
### New weather module
- Fixed weather forecast table display [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
- Dimmed loading indicator for weather forecast.
- Implemented config option `decimalSymbol` [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
- Aligned indoor values in current weather vertical [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
- Added humidity support to nunjuck unit filter.
- Do not display degree symbol for temperature in Kelvin [#1503](https://github.com/MichMich/MagicMirror/issues/1503).
- Weather forecast now works with openweathermap for both, `/forecast` and `/forecast/daily`, in new weather module. If you use the `/forecast`-weatherEndpoint, the hourly data are converted to daily data, see issues [#1504](https://github.com/MichMich/MagicMirror/issues/1504), [#1513](https://github.com/MichMich/MagicMirror/issues/1513).
- Added fade, fadePoint and maxNumberOfDays properties to the forecast mode [#1516](https://github.com/MichMich/MagicMirror/issues/1516)
- Fixed Loading string and decimalSymbol string replace [#1538](https://github.com/MichMich/MagicMirror/issues/1538)
- Show Snow amounts in new weather module [#1545](https://github.com/MichMich/MagicMirror/issues/1545)
- Added weather.gov as a new weather provider for US locations
## [2.6.0] - 2019-01-01
**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 ✨
- 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!
### Added
- 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.
- Missing `showEnd` in calendar documentation
- Screenshot for the new feed module
- Screenshot for the compliments module
- Screenshot for the clock module
- Screenshot for the current weather
- Screenshot for the weather forecast module
- Portuguese translation for "Feels"
- Croatian translation
- Fading for dateheaders timeFormat in Calendar [#1464](https://github.com/MichMich/MagicMirror/issues/1464)
- Documentation for the existing `scale` option in the Weather Forecast module.
### Fixed
- Allow parsing recurring calendar events where the start date is before 1900
- Fixed Polish translation for Single Update Info
- Ignore entries with unparseable details in the calendar module
- 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)
### Updated
- The default calendar setting `showEnd` is changed to `false`.
### Changed
- The Weather Forecast module by default displays the &deg; symbol after every numeric value to be consistent with the Current Weather module.
## [2.5.0] - 2018-10-01
### Added
- Romanian translation for "Feels"
- Support multi-line compliments
- Simplified Chinese translation for "Feels"
- Polish translate for "Feels"
- French translate for "Feels"
- Translations for newsfeed module
- Support for toggling news article in fullscreen
- Hungarian translation for "Feels" and "Week"
- Spanish translation for "Feels"
- Add classes instead of inline style to the message from the module Alert
- Support for events having a duration instead of an end
- Support for showing end of events through config parameters showEnd and dateEndFormat
### Fixed
- Fixed gzip encoded calendar loading issue #1400.
- Mixup between german and spanish translation for newsfeed.
- Fixed close dates to be absolute, if no configured in the config.js - module Calendar
- Fixed the updatenotification module message about new commits in the repository, so they can be correctly localized in singular and plural form.
- Fix for weatherforecast rainfall rounding [#1374](https://github.com/MichMich/MagicMirror/issues/1374)
- Fix calendar parsing issue for Midori on RasperryPi Zero w, related to issue #694.
- Fix weather city ID link in sample config
- Fixed issue with clientonly not updating with IP address and port provided on command line.
### Updated
- Updated Simplified Chinese translation
- Swedish translations
- Hungarian translations for the updatenotification module
- Updated Norsk bokmål translation
- Updated Norsk nynorsk translation
- Consider multi days event as full day events
## [2.4.1] - 2018-07-04
### Fixed
- Fix weather parsing issue #1332.
## [2.4.0] - 2018-07-01
⚠️ **Warning:** This release includes an updated version of Electron. This requires a Raspberry Pi configuration change to allow the best performance and prevent the CPU from overheating. Please read the information on the [MagicMirror Wiki](https://github.com/michmich/magicmirror/wiki/configuring-the-raspberry-pi#enable-the-open-gl-driver-to-decrease-electrons-cpu-usage).
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
### Added
- Enabled translation of feelsLike for module currentweather
- Added support for on-going calendar events
- Added scroll up in fullscreen newsfeed article view
- Changed fullscreen newsfeed width from 100% to 100vw (better results)
- Added option to calendar module that colors only the symbol instead of the whole line
- Added option for new display format in the calendar module with date headers with times/events below.
- Ability to fetch compliments from a remote server
- Add regex filtering to calendar module
- Customize classes for table
- Added option to newsfeed module to only log error parsing a news article if enabled
- Add update translations for Português Brasileiro
### Changed
- Upgrade to Electron 2.0.0.
- Remove yarn-or-npm which breaks production builds.
- Invoke module suspend even if no dom content. [#1308](https://github.com/MichMich/MagicMirror/issues/1308)
### Fixed
- 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)
- 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.
- Fixed browser-side code to work on the Midori browser.
- Fixed issue where heat index was reporting incorrect values in Celsius and Fahrenheit. [#1263](https://github.com/MichMich/MagicMirror/issues/1263)
- Fixed weatherforecast to use dt_txt field instead of dt to handle timezones better
- Newsfeed now remembers to show the description when `"ARTICLE_LESS_DETAILS"` is called if the user wants to always show the description. [#1282](https://github.com/MichMich/MagicMirror/issues/1282)
- `clientonly/*.js` is now linted, and one linting error is fixed
- Fix issue #1196 by changing underscore to hyphen in locale id, in align with momentjs.
- Fixed issue where heat index and wind chill were reporting incorrect values in Kelvin. [#1263](https://github.com/MichMich/MagicMirror/issues/1263)
### Updated
- Updated Italian translation
- Updated German translation
- Updated Dutch translation
## [2.3.1] - 2018-04-01
### Fixed
- 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
### Added
- Add new settings in compliments module: setting time intervals for morning and afternoon
- Add system notification `MODULE_DOM_CREATED` for notifying each module when their Dom has been fully loaded.
- Add types for module.
- Implement Danger.js to notify contributors when CHANGELOG.md is missing in PR.
- 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
- Automated unit tests utils, deprecated, translator, cloneObject(lockstrings)
- Automated integration tests translations
- Add advanced filtering to the excludedEvents configuration of the default calendar module
- New currentweather module config option: `showFeelsLike`: Shows how it actually feels like. (wind chill or heat index)
- New currentweather module config option: `useKMPHwind`: adds an option to see wind speed in Kmph instead of just m/s or Beaufort.
- Add dc:date to parsing in newsfeed module, which allows parsing of more rss feeds.
### Changed
- Add link to GitHub repository which contains the respective Dockerfile.
- Optimized automated unit tests cloneObject, cmpVersions
- Update notifications use now translation templates instead of normal strings.
- Yarn can be used now as an installation tool
- Changed Electron dependency to v1.7.13.
### Fixed
- News article in fullscreen (iframe) is now shown in front of modules.
- Forecast respects maxNumberOfDays regardless of endpoint.
- Fix exception on translation of objects.
## [2.2.2] - 2018-01-02
### Added
- Add missing `package-lock.json`.
### Changed
- Changed Electron dependency to v1.7.10.
## [2.2.1] - 2018-01-01
@@ -14,10 +460,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
### 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.
### Added
- 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 graceful shutdown of modules by calling `stop` function of each `node_helper` on SIGINT before exiting.
@@ -31,6 +479,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Add option for decimal symbols other than the decimal point for temperature values in both default weather modules: WeatherForecast and CurrentWeather.
### Fixed
- Fixed issue with calendar module showing more than `maximumEntries` allows
- WeatherForecast and CurrentWeather are now using HTTPS instead of HTTP
- Correcting translation for Indonesian language
@@ -41,13 +490,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
### Changed
- Remove Roboto fonts files inside `fonts` and these are installed by npm install command.
### Added
- 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 `.vscode/` folder to `.gitignore` to keep custom Visual Studio Code config out of git.
- Add unit test the capitalizeFirstLetter function of newfeed module.
- Add unit test the capitalizeFirstLetter function of newsfeed module.
- Add new unit tests for function `shorten` in calendar module.
- Add new unit tests for function `getLocaleSpecification` in calendar module.
- Add unit test for js/class.js.
@@ -60,6 +511,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Add Slack badge to Readme.
### Updated
- Changed 'default.js' - listen on all attached interfaces by default.
- Add execution of `npm list` after the test are ran in Travis CI.
- Change hooks for the vendors e2e tests.
@@ -68,7 +520,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Set version of the `express-ipfilter` on 0.3.1.
### Fixed
- Fixed issue with incorrect allignment 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 issue with calendar module where 'excludedEvents' count towards 'maximumEntries'.
- Fixed issue with calendar module where global configuration of maximumEntries was not overridden by calendar specific config (see module doc).
@@ -78,11 +531,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [2.1.2] - 2017-07-01
### 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))
- 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.
### Added
- 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 task to check configuration file.
@@ -92,7 +547,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Add unit test calendar_modules function capFirst.
- Add test for check if exists the directories present in defaults modules.
- Add support for showing wind direction as an arrow instead of abbreviation in currentWeather module.
- Add support for writing translation fucntions to support flexible word order
- Add support for writing translation functions to support flexible word order
- Add test for check if exits the directories present in defaults modules.
- Add calendar option to set a separate date format for full day events.
- Add ability for `currentweather` module to display indoor temperature via INDOOR_TEMPERATURE notification
@@ -101,17 +556,19 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added Romanian translation.
### Updated
- Added missing keys to Polish translation.
- Added missing key to German translation.
- Added better translation with flexible word order to Finnish translation.
### Fixed
- 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).
- Fix double message about port when server is starting
- Corrected Swedish translations for TODAY/TOMORROW/DAYAFTERTOMORROW.
- Removed unused import from js/electron.js
- Made calendar.js respect config.timeFormat irrespecive of locale setting.
- Made calendar.js respect config.timeFormat irrespective of locale setting.
- Fixed alignment of analog clock when a large calendar is displayed in the same side bar.
## [2.1.1] - 2017-04-01
@@ -119,6 +576,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
### Changed
- Add `anytime` group for Compliments module.
- Compliments module can use remoteFile without default daytime arrays defined.
- Installer: Use init config.js from config.js.sample.
@@ -129,13 +587,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added `DAYAFTERTOMORROW`, `UPDATE_NOTIFICATION` and `UPDATE_NOTIFICATION_MODULE` to Finnish translations.
- Run `npm test` on Travis automatically.
- Show the splash screen image even when is reboot or halted.
- Added some missing translaton strings in the sv.json file.
- Added some missing translation strings in the sv.json file.
- Run task jsonlint to check translation files.
- Restructured Test Suite.
### Added
- 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.
- 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.
@@ -146,12 +605,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Option to use RegExp in Calendar's titleReplace.
- Hungarian Translation.
- Icelandic Translation.
- Add use a script to prevent when is run by SSH session set DISPLAY enviroment.
- Enable ability to set configuration file by the enviroment variable called MM_CONFIG_FILE.
- Add use a script to prevent when is run by SSH session set DISPLAY environment.
- Enable ability to set configuration file by the environment variable called MM_CONFIG_FILE.
- Option to give each calendar a different color.
- Option for colored min-temp and max-temp.
- Add test e2e helloworld.
- Add test e2e enviroment.
- Add test e2e environment.
- Add `chai-as-promised` npm module to devDependencies.
- Basic set of tests for clock module.
- Run e2e test in Travis.
@@ -169,22 +628,23 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added tests for Translations, dev argument, version, dev console.
- Added test anytime feature compliments module.
- Added test ipwhitelist configuration directive.
- Added test for calendar module: default, basic-auth, backward compability, fail-basic-auth.
- Added test for calendar module: default, basic-auth, backward compatibility, fail-basic-auth.
- Added meta tags to support fullscreen mode on iOS (for server mode)
- Added `ignoreOldItems` and `ignoreOlderThan` options to the News Feed module
- Added test for MM_PORT enviroment variable.
- Added test for MM_PORT environment variable.
- Added a configurable Week section to the clock module.
### Fixed
- Update .gitignore to not ignore default modules folder.
- Remove white flash on boot up.
- Added `update` in Raspberry Pi installation script.
- 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.
- Fix an issue with module hidden status changing to `true` although lock string prevented showing it.
- Fix newsfeed module bug (removeStartTags)
- Fix when is set MM_PORT enviroment variable.
- Fix when is set MM_PORT environment variable.
- Fixed missing animation on `this.show(speed)` when module is alone in a region.
## [2.1.0] - 2016-12-31
@@ -192,6 +652,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
### Added
- Finnish translation.
- Danish translation.
- Turkish translation.
@@ -204,24 +665,25 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- 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.
- 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
- Add module `updatenotification` to get an update whenever a new version is availabe. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information.
- Add the abilty to set timezone on the date display in the Clock 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 the ability to set timezone on the date display in the Clock Module
- Ability to set date format in calendar module
- Possibility to use currentweather for the compliments
- Added option `disabled` for modules.
- 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 `zoom` to scale the whole mirror display with a given factor.
- Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer.
- Added abilty set the classes option to compliments module for style and text size of compliments.
- Added ability set the classes option to compliments module for style and text size of compliments.
- Added ability to configure electronOptions
- Calendar module: option to hide private events
- Add root_path for global vars
### Updated
- Modified translations for Frysk.
- Modified core English translations.
- Updated package.json as a result of Snyk security update.
@@ -232,6 +694,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Modules are now secure, and Helmet is now used to prevent abuse of the Mirror's API.
### Fixed
- 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.
- Global and Module default config values are no longer modified when setting config values.
@@ -242,18 +705,21 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [2.0.5] - 2016-09-20
### Added
- 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 CII Badge (we are compliant with the CII Best Practices)
- Add support for doing http basic auth when loading calendars
- Add the abilty 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
- 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.
- Fix API url for weather API.
### Updated
- Force fullscreen when kioskmode is active.
- Update the .github templates and information with more modern information.
- Update the Gruntfile with a more functional StyleLint implementation.
@@ -261,6 +727,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [2.0.4] - 2016-08-07
### Added
- Brazilian Portuguese Translation.
- Option to enable Kiosk mode.
- Added ability to start the app with Dev Tools.
@@ -268,63 +735,81 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Greek Translation
### Fixed
- Prevent `getModules()` selectors from returning duplicate entries.
- Append endpoints of weather modules with `/` to retreive the correct data. (Issue [#337](https://github.com/MichMich/MagicMirror/issues/337))
- Corrected grammer in `module.js` from 'suspend' to 'suspended'.
- 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'.
- Fixed openweathermap.org URL in config sample.
- Prevent currentweather module from crashing when received data object is incorrect.
- 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 package.json to fix possible vulnerabilities. (Using Snyk)
- Updated weathericons
- Updated default weatherforecast to work with the new icons.
- More detailed error message in case config file couldn't be loaded.
## [2.0.3] - 2016-07-12
### Added
- Add max newsitems parameter to the newsfeed module.
- Translations for Simplified Chinese, Traditional Chinese and Japanese.
- Polish Translation
- Add an analog clock in addition to the digital one.
### Fixed
- 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))
### Changed
- Added default string to calendar titleReplace.
## [2.0.2] - 2016-06-05
### Added
- Norwegian Translations (nb and nn)
- Portuguese Translation
- Swedish Translation
### Fixed
- Added reference to Italian Translation.
- Added the missing NE translation to all languages. [#344](https://github.com/MichMich/MagicMirror/issues/344)
- Added proper User-Agent string to calendar call.
### Changed
- Add option to use locationID in weather modules.
## [2.0.1] - 2016-05-18
### Added
- Changelog
- Italian Translation
### Changed
- Improve the installer by fetching the latest Node.js without any 3rd party interferences.
## [2.0.0] - 2016-05-03
### Initial release of MagicMirror²
It includes (but is not limited to) the following features:
- Modular system allowing 3rd party plugins.
- An Node/Electron based application taking away the need for external servers or browsers.
- A complete development API documentation.
- Small cute fairies that kiss you while you sleep.
## [1.0.0] - 2014-02-16
### 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)

View File

@@ -1,103 +0,0 @@
module.exports = function(grunt) {
require("time-grunt")(grunt);
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
eslint: {
options: {
configFile: ".eslintrc.json"
},
target: [
"js/*.js",
"modules/default/*.js",
"modules/default/*/*.js",
"serveronly/*.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",
"modules/node_modules/node_helper/index.js"
]
},
stylelint: {
simple: {
options: {
configFile: ".stylelintrc"
},
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",
"translations/*.json",
"modules/default/*/translations/*.json",
"installers/pm2_MagicMirror.json",
"vendor/package.js"
],
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
}
},
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"]);
};

View File

@@ -1,7 +1,6 @@
The MIT License (MIT)
=====================
# The MIT License (MIT)
Copyright © 2016-2017 Michael Teeuw
Copyright © 2016-2019 Michael Teeuw
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

181
README.md
View File

@@ -4,181 +4,40 @@
<a href="https://david-dm.org/MichMich/MagicMirror"><img src="https://david-dm.org/MichMich/MagicMirror.svg" alt="Dependency Status"></a>
<a href="https://david-dm.org/MichMich/MagicMirror#info=devDependencies"><img src="https://david-dm.org/MichMich/MagicMirror/dev-status.svg" alt="devDependency Status"></a>
<a href="https://bestpractices.coreinfrastructure.org/projects/347"><img src="https://bestpractices.coreinfrastructure.org/projects/347/badge"></a>
<a href="http://choosealicense.com/licenses/mit"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
<a href="https://travis-ci.org/MichMich/MagicMirror"><img src="https://travis-ci.org/MichMich/MagicMirror.svg" alt="Travis"></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://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="http://slack.magicmirror.builders"><img src="http://slack.magicmirror.builders:3000/badge.svg" alt="Slack Status"></a>
</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!
## Table Of Contents
## Documentation
- [Usage](#usage)
- [Configuration](#configuration)
- [Modules](#modules)
- [Known Issues](#known-issues)
- [Community](#community)
- [Contributing Guidelines](#contributing-guidelines)
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).
## Usage
## Links
### Raspberry Pi Support
Electron, the app wrapper around MagicMirror², only supports the Raspberry Pi 2 & 3. The Raspberry Pi 1 is currently **not** supported. If you want to run this on a Raspberry Pi 1, use the [server only](#server-only) feature and setup a fullscreen browser yourself.
### Automatic Installer (Raspberry Pi Only!)
Execute the following command on your Raspberry Pi to install MagicMirror²:
````
bash -c "$(curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/master/installers/raspberry.sh)"
````
### Manual Installation
1. Download and install the latest Node.js version.
2. Clone the repository and check out the master branch: `git clone https://github.com/MichMich/MagicMirror`
3. Enter the repository: `cd ~/MagicMirror`
4. Install and run the app: `npm install && npm start`
**Important:** `npm start` does **not** work via SSH, use `DISPLAY=:0 nohup npm start &` instead. This starts the mirror on the remote display.
**Note:** if you want to debug on Raspberry Pi you can use `npm start dev` which will start the MagicMirror app with Dev Tools enabled.
### Server Only
In some cases, you want to start the application without an actual app window. In this case, you can start MagicMirror² in server only mode by manually running `node serveronly` or using Docker. This will start the server, after which you can open the application in your browser of choice. Detailed description below.
### Client Only
When you have a server running remotely and want to connect a standalone client to this instance, you can manually run `node clientonly --address 192.168.1.5 --port 8080`. (Specify the ip address and port number of the server)
**Important:** Make sure that you whitelist the interface/ip in the server config where you want the client to connect to, otherwise it will not be allowed to connect to the server
#### Docker
MagicMirror² in server only mode can be deployed using [Docker](https://docker.com). After a successful [Docker installation](https://docs.docker.com/engine/installation/) you just need to execute the following command in the shell:
```bash
docker run -d \
--publish 80:8080 \
--restart always \
--volume ~/magic_mirror/config:/opt/magic_mirror/config \
--volume ~/magic_mirror/modules:/opt/magic_mirror/modules \
--name magic_mirror \
bastilimbach/docker-magicmirror
```
| **Volumes** | **Description** |
| --- | --- |
| `/opt/magic_mirror/config` | Mount this volume to insert your own config into the docker container. |
| `/opt/magic_mirror/modules` | Mount this volume to add your own custom modules into the docker container. |
You may need to add your Docker Host IP to your `ipWhitelist` option. If you have some issues setting up this configuration, check [this forum post](https://forum.magicmirror.builders/topic/1326/ipwhitelist-howto).
```javascript
var config = {
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:172.17.0.1"]
};
```
If you want to run the server on a raspberry pi, use the `raspberry` tag. (bastilimbach/docker-magicmirror:raspberry)
#### Manual
1. Download and install the latest Node.js version.
2. Clone the repository and check out the master branch: `git clone https://github.com/MichMich/MagicMirror`
3. Enter the repository: `cd ~/MagicMirror`
4. Install and run the app: `npm install && node serveronly`
### Raspberry Configuration & Auto Start.
The following wiki links are helpful in the configuration of your MagicMirror² operating system:
- [Configuring the Raspberry Pi](https://github.com/MichMich/MagicMirror/wiki/Configuring-the-Raspberry-Pi)
- [Auto Starting MagicMirror](https://github.com/MichMich/MagicMirror/wiki/Auto-Starting-MagicMirror)
### Updating your MagicMirror²
If you want to update your MagicMirror² to the latest version, use your terminal to go to your Magic Mirror folder and type the following command:
```bash
git pull && npm install
```
If you changed nothing more than the config or the modules, this should work without any problems.
Type `git status` to see your changes, if there are any, you can reset them with `git reset --hard`. After that, git pull should be possible.
## Configuration
1. Duplicate `config/config.js.sample` to `config/config.js`. **Note:** If you used the installer script. This step is already done for you.
2. Modify your required settings.
Note: You'll can check your configuration running the follow command:
```bash
npm run config:check
```
The following properties can be configured:
| **Option** | **Description** |
| --- | --- |
| `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. |
| `address` | The ip address the accept connections. The default open bind `localhost`. Example config: `192.168.10.100`. |
| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1", "::1"]`. It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`). Set `[]` to allow all IP addresses. For more information about how configure this directive see the [follow post ipWhitelist HowTo](https://forum.magicmirror.builders/topic/1326/ipwhitelist-howto) |
| `zoom` | This allows to scale the mirror contents with a given zoom factor. The default value is `1.0`|
| `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. |
| `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. |
| `units` | The units that will be used in the default weather modules. Possible values are `metric` or `imperial`. The default is `metric`. |
| `modules` | An array of active modules. **The array must contain objects. See the next table below for more information.** |
| `electronOptions` | An optional array of Electron (browser) options. This allows configuration of e.g. the browser screen size and position (example: `electronOptions: { fullscreen: false, width: 800, height: 600 }`). Kiosk mode can be enabled by setting `kiosk = true`, `autoHideMenuBar = false` and `fullscreen = false`. More options can be found [here](https://github.com/electron/electron/blob/master/docs/api/browser-window.md). |
| `customCss` | The path of the `custom.css` stylesheet. The default is `css/custom.css`. |
Module configuration:
| **Option** | **Description** |
| --- | --- |
| `module` | The name of the module. This can also contain the subfolder. Valid examples include `clock`, `default/calendar` and `custommodules/mymodule`. |
| `position` | The location of the module in which the module will be loaded. Possible values are `top_ bar`, `top_left`, `top_center`, `top_right`, `upper_third`, `middle_center`, `lower_third`, `bottom_left`, `bottom_center`, `bottom_right`, `bottom_bar`, `fullscreen_above`, and `fullscreen_below`. This field is optional but most modules require this field to set. Check the documentation of the module for more information. Multiple modules with the same position will be ordered based on the order in the configuration file. |
| `classes` | Additional classes which are passed to the module. The field is optional. |
| `header` | To display a header text above the module, add the header property. This field is optional. |
| `disabled` | Set disabled to `true` to skip creating the module. This field is optional. |
| `config` | An object with the module configuration properties. Check the documentation of the module for more information. This field is optional, unless the module requires extra configuration. |
## Modules
The following modules are installed by default.
- [**Clock**](modules/default/clock)
- [**Calendar**](modules/default/calendar)
- [**Current Weather**](modules/default/currentweather)
- [**Weather Forecast**](modules/default/weatherforecast)
- [**News Feed**](modules/default/newsfeed)
- [**Compliments**](modules/default/compliments)
- [**Hello World**](modules/default/helloworld)
- [**Alert**](modules/default/alert)
For more available modules, check out out the wiki page: [MagicMirror² Modules](https://github.com/MichMich/MagicMirror/wiki/MagicMirror²-Modules). If you want to build your own modules, check out the [MagicMirror² Module Development Documentation](modules) and don't forget to add it to the wiki and the [forum](https://forum.magicmirror.builders/category/7/showcase)!
## Known issues
- Electron seems to have some issues on certain Raspberry Pi 2's. See [#145](https://github.com/MichMich/MagicMirror/issues/145).
- MagicMirror² (Electron) sometimes quits without an error after an extended period of use. See [#150](https://github.com/MichMich/MagicMirror/issues/150).
## Community
The community around the MagicMirror² is constantly growing. We even have a [forum](https://forum.magicmirror.builders) now where you can share your ideas, ask questions, help others and get inspired by other builders. We would love to see you there!
- Website: [https://magicmirror.builders](https://magicmirror.builders)
- Documentation: [https://docs.magicmirror.builders](https://docs.magicmirror.builders)
- Forum: [https://forum.magicmirror.builders](https://forum.magicmirror.builders)
- Discord: [https://discord.gg/J5BAtvx](https://discord.gg/J5BAtvx)
- Blog: [https://michaelteeuw.nl/tagged/magicmirror](https://michaelteeuw.nl/tagged/magicmirror)
- Donations: [https://magicmirror.builders/#donate](https://magicmirror.builders/#donate)
## Contributing Guidelines
Contributions of all kinds are welcome, not only in the form of code but also with regards bug reports and documentation.
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)
Please keep the following in mind:
## Enjoying MagicMirror? Consider a donation!
- **Bug Reports**: Make sure you're running the latest version. If the issue(s) still persist: please open a clearly documented issue with a clear title.
- **Minor Bug Fixes**: Please send a pull request with a clear explanation of the issue or a link to the issue it solves.
- **Major Bug Fixes**: please discuss your approach in an GitHub issue before you start to alter a big part of the code.
- **New Features**: please please discuss in a GitHub issue before you start to alter a big part of the code. Without discussion upfront, the pull request will not be accepted / merged.
MagicMirror² is opensource and free. That doesn't mean we don't need any money.
Thanks for your help in making MagicMirror² better!
Please consider a donation to help us cover the ongoing costs like webservers and email services.
If we receive enough donations we might even be able to free up some working hours and spend some extra time improving the MagicMirror² core.
To donate, please follow [this](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G5D8E9MR5DTD2&source=url) link.
<p align="center">
<br>

View File

@@ -1,8 +1,6 @@
/* jshint esversion: 6 */
"use strict";
// Use seperate scope to prevent global scope pollution
// Use separate scope to prevent global scope pollution
(function () {
var config = {};
@@ -19,7 +17,10 @@
// Prefer command line arguments over environment variables
["address", "port"].forEach((key) => {
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) {
@@ -30,27 +31,27 @@
const request = lib.get(url, (response) => {
var configData = "";
// Gather incomming data
response.on("data", function(chunk) {
// Gather incoming data
response.on("data", function (chunk) {
configData += chunk;
});
// Resolve promise at the end of the HTTP/HTTPS stream
response.on("end", function() {
response.on("end", function () {
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}`));
});
})
};
});
}
function fail(message, code = 1) {
if (message !== undefined && typeof message === "string") {
console.log(message);
} 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);
}
@@ -58,17 +59,19 @@
getServerAddress();
(config.address && config.port) || fail();
var prefix = config.tls ? "https://" : "http://";
// 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) {
getServerConfig(`http://${config.address}:${config.port}/config/`)
.then(function (config) {
getServerConfig(`${prefix}${config.address}:${config.port}/config/`)
.then(function (configReturn) {
// Pass along the server config via an environment variable
var env = Object.create(process.env);
var options = { env: env };
config.address = config.address;
config.port = config.port;
env.config = JSON.stringify(config);
configReturn.address = config.address;
configReturn.port = config.port;
configReturn.tls = config.tls;
env.config = JSON.stringify(configReturn);
// Spawn electron application
const electron = require("electron");
@@ -88,12 +91,11 @@
process.stdout.write(`Client: ${err}`);
});
child.on('close', (code) => {
if (code != 0) {
child.on("close", (code) => {
if (code !== 0) {
console.log(`There something wrong. The clientonly is not running code ${code}`);
}
});
})
.catch(function (reason) {
fail(`Unable to connect to server: (${reason})`);
@@ -101,4 +103,4 @@
} else {
fail();
}
}());
})();

View File

@@ -1,29 +1,41 @@
/* Magic Mirror Config Sample
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*
* For more information how you can configurate this file
* For more information on how you can configure this file
* See https://github.com/MichMich/MagicMirror#configuration
*
*/
var config = {
address: "localhost", // Address to listen on, can be:
// - "localhost", "127.0.0.1", "::1" to listen on loopback interface
// - another specific IPv4/6 to listen on a specific interface
// - "", "0.0.0.0", "::" to listen on any interface
// Default, when address config is left out, is "localhost"
address: "localhost", // Address to listen on, can be:
// - "localhost", "127.0.0.1", "::1" to listen on loopback interface
// - another specific IPv4/6 to listen on a specific interface
// - "0.0.0.0", "::" to listen on any interface
// Default, when address config is left out or empty, is "localhost"
port: 8080,
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
// or add a specific IPv4 of 192.168.1.5 :
// ["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"],
basePath: "/", // The URL path where MagicMirror is hosted. If you are using a Reverse proxy
// you must set the sub path here. basePath must end with a /
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
// or add a specific IPv4 of 192.168.1.5 :
// ["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
httpsPrivateKey: "", // HTTPS private key path, only require when useHttps is true
httpsCertificate: "", // HTTPS Certificate path, only require when useHttps is true
language: "en",
logLevel: ["INFO", "LOG", "WARN", "ERROR"],
timeFormat: 24,
units: "metric",
// serverOnly: true/false/"local" ,
// local for armv6l processors, default
// starts serveronly and then starts chrome browser
// false, default for all NON-armv6l devices
// true, force serveronly mode, because you want to.. no UI on this device
modules: [
{
@@ -44,9 +56,8 @@ var config = {
config: {
calendars: [
{
symbol: "calendar-check-o ",
url: "webcal://www.calendarlabs.com/templates/ical/US-Holidays.ics"
}
symbol: "calendar-check",
url: "webcal://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics" }
]
}
},
@@ -59,7 +70,7 @@ var config = {
position: "top_right",
config: {
location: "New York",
locationID: "", //ID from http://www.openweathermap.org/help/city_list.txt
locationID: "", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
appid: "YOUR_OPENWEATHER_API_KEY"
}
},
@@ -69,7 +80,7 @@ var config = {
header: "Weather Forecast",
config: {
location: "New York",
locationID: "5128581", //ID from http://www.openweathermap.org/help/city_list.txt
locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
appid: "YOUR_OPENWEATHER_API_KEY"
}
},
@@ -80,15 +91,16 @@ var config = {
feeds: [
{
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,
showPublishDate: true
showPublishDate: true,
broadcastNewsFeeds: true,
broadcastNewsUpdates: true
}
},
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/

View File

@@ -1,14 +0,0 @@
/*****************************************************
* Magic Mirror *
* Custom CSS *
* *
* By Michael Teeuw http://michaelteeuw.nl *
* MIT Licensed. *
* *
* Add any custom CSS below. *
* Changes to this files will be ignored by GIT. *
*****************************************************/
body {
}

View File

@@ -128,6 +128,10 @@ sup {
text-overflow: ellipsis;
}
.pre-line {
white-space: pre-line;
}
/**
* Region Definitions.
*/
@@ -173,10 +177,6 @@ sup {
.region.top.center,
.region.bottom.center {
left: 50%;
-moz-transform: translateX(-50%);
-o-transform: translateX(-50%);
-webkit-transform: translateX(-50%);
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
@@ -209,10 +209,6 @@ sup {
.region.middle.center {
width: 100%;
text-align: center;
-moz-transform: translateY(-50%);
-o-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}

17
dangerfile.js Normal file
View File

@@ -0,0 +1,17 @@
import { danger, fail, warn } from "danger";
// Check if the CHANGELOG.md file has been edited
// Fail the build and post a comment reminding submitters to do so if it wasn't changed
if (!danger.git.modified_files.includes("CHANGELOG.md")) {
warn("Please include an updated `CHANGELOG.md` file.<br>This way we can keep track of all the contributions.");
}
// Check if the PR request is send to the master branch.
// This should only be done by MichMich.
if (danger.github.pr.base.ref === "master" && danger.github.pr.user.login !== "MichMich") {
// Check if the PR body or title includes the text: #accepted.
// If not, the PR will fail.
if ((danger.github.pr.body + danger.github.pr.title).includes("#accepted")) {
fail("Please send all your pull requests to the `develop` branch.<br>Pull requests on the `master` branch will not be accepted.");
}
}

View File

@@ -4,9 +4,9 @@
"lockfileVersion": 1,
"dependencies": {
"roboto-fontface": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.8.0.tgz",
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz",
"integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g=="
}
}
}

View File

@@ -1,15 +1,15 @@
{
"name": "magicmirror-fonts",
"description": "Package for fonts use by MagicMirror Core.",
"repository": {
"type": "git",
"url": "git+https://github.com/MichMich/MagicMirror.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/MichMich/MagicMirror/issues"
},
"dependencies": {
"roboto-fontface": "^0.8.0"
}
"name": "magicmirror-fonts",
"description": "Package for fonts use by MagicMirror Core.",
"repository": {
"type": "git",
"url": "git+https://github.com/MichMich/MagicMirror.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/MichMich/MagicMirror/issues"
},
"dependencies": {
"roboto-fontface": "^0.10.0"
}
}

View File

@@ -2,94 +2,57 @@
font-family: Roboto;
font-style: normal;
font-weight: 100;
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"),
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.ttf") format("truetype");
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");
}
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-weight: 300;
src:
local("Roboto Condensed Light"),
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");
src: local("Roboto Condensed Light"), 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");
}
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-weight: 400;
src:
local("Roboto Condensed"),
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");
src: local("Roboto Condensed"), 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");
}
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-weight: 700;
src:
local("Roboto Condensed Bold"),
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");
src: local("Roboto Condensed Bold"), 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");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 400;
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"),
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.ttf") format("truetype");
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");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 500;
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"),
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.ttf") format("truetype");
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");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 700;
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"),
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.ttf") format("truetype");
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");
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 300;
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"),
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.ttf") format("truetype");
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");
}

View File

@@ -37,7 +37,7 @@
<div class="region bottom right"><div class="container"></div></div>
</div>
<div class="region fullscreen above"><div class="container"></div></div>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="socket.io/socket.io.js"></script>
<script type="text/javascript" src="vendor/node_modules/nunjucks/browser/nunjucks.min.js"></script>
<script type="text/javascript" src="js/defaults.js"></script>
<script type="text/javascript" src="#CONFIG_FILE#"></script>

View File

@@ -1,2 +1,3 @@
# This file is still here to keep PM2 working on older installations.
cd ~/MagicMirror
DISPLAY=:0 npm start

View File

@@ -1,7 +0,0 @@
{
"apps" : [{
"name" : "MagicMirror",
"script" : "/home/pi/MagicMirror/installers/mm.sh",
"watch" : ["/home/pi/MagicMirror/config/config.js"]
}]
}

View File

@@ -1,2 +0,0 @@
echo "\033[32mMagicMirror installation successful!"
exit 0

View File

@@ -1,163 +0,0 @@
#!/usr/bin/env bash
# This is an installer script for MagicMirror2. It works well enough
# that it can detect if you have Node installed, run a binary script
# and then download and run MagicMirror2.
echo -e "\e[0m"
echo '$$\ $$\ $$\ $$\ $$\ $$\ $$$$$$\'
echo '$$$\ $$$ | \__| $$$\ $$$ |\__| $$ __$$\'
echo '$$$$\ $$$$ | $$$$$$\ $$$$$$\ $$\ $$$$$$$\ $$$$\ $$$$ |$$\ $$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\ \__/ $$ |'
echo '$$\$$\$$ $$ | \____$$\ $$ __$$\ $$ |$$ _____|$$\$$\$$ $$ |$$ |$$ __$$\ $$ __$$\ $$ __$$\ $$ __$$\ $$$$$$ |'
echo '$$ \$$$ $$ | $$$$$$$ |$$ / $$ |$$ |$$ / $$ \$$$ $$ |$$ |$$ | \__|$$ | \__|$$ / $$ |$$ | \__|$$ ____/'
echo '$$ |\$ /$$ |$$ __$$ |$$ | $$ |$$ |$$ | $$ |\$ /$$ |$$ |$$ | $$ | $$ | $$ |$$ | $$ |'
echo '$$ | \_/ $$ |\$$$$$$$ |\$$$$$$$ |$$ |\$$$$$$$\ $$ | \_/ $$ |$$ |$$ | $$ | \$$$$$$ |$$ | $$$$$$$$\'
echo '\__| \__| \_______| \____$$ |\__| \_______|\__| \__|\__|\__| \__| \______/ \__| \________|'
echo ' $$\ $$ |'
echo ' \$$$$$$ |'
echo ' \______/'
echo -e "\e[0m"
# Define the tested version of Node.js.
NODE_TESTED="v5.1.0"
# Determine which Pi is running.
ARM=$(uname -m)
# Check the Raspberry Pi version.
if [ "$ARM" != "armv7l" ]; then
echo -e "\e[91mSorry, your Raspberry Pi is not supported."
echo -e "\e[91mPlease run MagicMirror on a Raspberry Pi 2 or 3."
echo -e "\e[91mIf this is a Pi Zero, you are in the same boat as the original Raspberry Pi. You must run in server only mode."
exit;
fi
# Define helper methods.
function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; }
function command_exists () { type "$1" &> /dev/null ;}
# Update before first apt-get
echo -e "\e[96mUpdating packages ...\e[90m"
sudo apt-get update || echo -e "\e[91mUpdate failed, carrying on installation ...\e[90m"
# Installing helper tools
echo -e "\e[96mInstalling helper tools ...\e[90m"
sudo apt-get install curl wget git build-essential unzip || exit
# Check if we need to install or upgrade Node.js.
echo -e "\e[96mCheck current Node installation ...\e[0m"
NODE_INSTALL=false
if command_exists node; then
echo -e "\e[0mNode currently installed. Checking version number.";
NODE_CURRENT=$(node -v)
echo -e "\e[0mMinimum Node version: \e[1m$NODE_TESTED\e[0m"
echo -e "\e[0mInstalled Node version: \e[1m$NODE_CURRENT\e[0m"
if version_gt $NODE_TESTED $NODE_CURRENT; then
echo -e "\e[96mNode should be upgraded.\e[0m"
NODE_INSTALL=true
# Check if a node process is currenlty running.
# If so abort installation.
if pgrep "node" > /dev/null; then
echo -e "\e[91mA Node process is currently running. Can't upgrade."
echo "Please quit all Node processes and restart the installer."
exit;
fi
else
echo -e "\e[92mNo Node.js upgrade necessary.\e[0m"
fi
else
echo -e "\e[93mNode.js is not installed.\e[0m";
NODE_INSTALL=true
fi
# Install or upgrade node if necessary.
if $NODE_INSTALL; then
echo -e "\e[96mInstalling Node.js ...\e[90m"
# Fetch the latest version of Node.js from the selected branch
# The NODE_STABLE_BRANCH variable will need to be manually adjusted when a new branch is released. (e.g. 7.x)
# Only tested (stable) versions are recommended as newer versions could break MagicMirror.
NODE_STABLE_BRANCH="6.x"
curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash -
sudo apt-get install -y nodejs
echo -e "\e[92mNode.js installation Done!\e[0m"
fi
# Install MagicMirror
cd ~
if [ -d "$HOME/MagicMirror" ] ; then
echo -e "\e[93mIt seems like MagicMirror is already installed."
echo -e "To prevent overwriting, the installer will be aborted."
echo -e "Please rename the \e[1m~/MagicMirror\e[0m\e[93m folder and try again.\e[0m"
echo ""
echo -e "If you want to upgrade your installation run \e[1m\e[97mgit pull\e[0m from the ~/MagicMirror directory."
echo ""
exit;
fi
echo -e "\e[96mCloning MagicMirror ...\e[90m"
if git clone https://github.com/MichMich/MagicMirror.git; then
echo -e "\e[92mCloning MagicMirror Done!\e[0m"
else
echo -e "\e[91mUnable to clone MagicMirror."
exit;
fi
cd ~/MagicMirror || exit
echo -e "\e[96mInstalling dependencies ...\e[90m"
if npm install; then
echo -e "\e[92mDependencies installation Done!\e[0m"
else
echo -e "\e[91mUnable to install dependencies!"
exit;
fi
# Use sample config for start MagicMirror
cp config/config.js.sample config/config.js
# Check if plymouth is installed (default with PIXEL desktop environment), then install custom splashscreen.
echo -e "\e[96mCheck plymouth installation ...\e[0m"
if command_exists plymouth; then
THEME_DIR="/usr/share/plymouth/themes"
echo -e "\e[90mSplashscreen: Checking themes directory.\e[0m"
if [ -d $THEME_DIR ]; then
echo -e "\e[90mSplashscreen: Create theme directory if not exists.\e[0m"
if [ ! -d $THEME_DIR/MagicMirror ]; then
sudo mkdir $THEME_DIR/MagicMirror
fi
if sudo cp ~/MagicMirror/splashscreen/splash.png $THEME_DIR/MagicMirror/splash.png && sudo cp ~/MagicMirror/splashscreen/MagicMirror.plymouth $THEME_DIR/MagicMirror/MagicMirror.plymouth && sudo cp ~/MagicMirror/splashscreen/MagicMirror.script $THEME_DIR/MagicMirror/MagicMirror.script; then
echo -e "\e[90mSplashscreen: Theme copied successfully.\e[0m"
if sudo plymouth-set-default-theme -R MagicMirror; then
echo -e "\e[92mSplashscreen: Changed theme to MagicMirror successfully.\e[0m"
else
echo -e "\e[91mSplashscreen: Couldn't change theme to MagicMirror!\e[0m"
fi
else
echo -e "\e[91mSplashscreen: Copying theme failed!\e[0m"
fi
else
echo -e "\e[91mSplashscreen: Themes folder doesn't exist!\e[0m"
fi
else
echo -e "\e[93mplymouth is not installed.\e[0m";
fi
# Use pm2 control like a service MagicMirror
read -p "Do you want use pm2 for auto starting of your MagicMirror (y/n)?" choice
if [[ $choice =~ ^[Yy]$ ]]; then
sudo npm install -g pm2
sudo su -c "env PATH=$PATH:/usr/bin pm2 startup linux -u pi --hp /home/pi"
pm2 start ~/MagicMirror/installers/pm2_MagicMirror.json
pm2 save
fi
echo " "
echo -e "\e[92mWe're ready! Run \e[1m\e[97mDISPLAY=:0 npm start\e[0m\e[92m from the ~/MagicMirror directory to start your MagicMirror.\e[0m"
echo " "
echo " "

112
js/app.js
View File

@@ -1,19 +1,22 @@
/* Magic Mirror
* The Core App (Server)
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
var fs = require("fs");
var path = require("path");
var Log = require(__dirname + "/logger.js");
var Server = require(__dirname + "/server.js");
var Utils = require(__dirname + "/utils.js");
var defaultModules = require(__dirname + "/../modules/default/defaultmodules.js");
var path = require("path");
// Alias modules mentioned in package.js under _moduleAliases.
require("module-alias/register");
// Get version number.
global.version = JSON.parse(fs.readFileSync("package.json", "utf8")).version;
console.log("Starting MagicMirror: v" + global.version);
Log.log("Starting MagicMirror: v" + global.version);
// global absolute root path
global.root_path = path.resolve(__dirname + "/../");
@@ -31,15 +34,15 @@ if (process.env.MM_PORT) {
// The next part is here to prevent a major exception when there
// is no internet connection. This could probable be solved better.
process.on("uncaughtException", function (err) {
console.log("Whoops! There was an uncaught exception...");
console.error(err);
console.log("MagicMirror will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?");
console.log("If you think this really is an issue, please open an issue on GitHub: https://github.com/MichMich/MagicMirror/issues");
Log.error("Whoops! There was an uncaught exception...");
Log.error(err);
Log.error("MagicMirror will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?");
Log.error("If you think this really is an issue, please open an issue on GitHub: https://github.com/MichMich/MagicMirror/issues");
});
/* App - The core app.
*/
var App = function() {
var App = function () {
var nodeHelpers = [];
/* loadConfig(callback)
@@ -48,16 +51,15 @@ var App = function() {
*
* argument callback function - The callback function.
*/
var loadConfig = function(callback) {
console.log("Loading config ...");
var loadConfig = function (callback) {
Log.log("Loading config ...");
var defaults = require(__dirname + "/defaults.js");
// For this check proposed to TestSuite
// https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8
var configFilename = path.resolve(global.root_path + "/config/config.js");
if (typeof(global.configuration_file) !== "undefined") {
configFilename = path.resolve(global.configuration_file);
if (typeof global.configuration_file !== "undefined") {
configFilename = path.resolve(global.configuration_file);
}
try {
@@ -67,50 +69,45 @@ var App = function() {
var config = Object.assign(defaults, c);
callback(config);
} catch (e) {
if (e.code == "ENOENT") {
console.error(Utils.colors.error("WARNING! Could not find config file. Please create one. Starting with default configuration."));
if (e.code === "ENOENT") {
Log.error(Utils.colors.error("WARNING! Could not find config file. Please create one. Starting with default configuration."));
} else if (e instanceof ReferenceError || e instanceof SyntaxError) {
console.error(Utils.colors.error("WARNING! Could not validate config file. Please correct syntax errors. Starting with default configuration."));
Log.error(Utils.colors.error("WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: " + e.stack));
} else {
console.error(Utils.colors.error("WARNING! Could not load config file. Starting with default configuration. Error found: " + e));
Log.error(Utils.colors.error("WARNING! Could not load config file. Starting with default configuration. Error found: " + e));
}
callback(defaults);
}
};
var checkDeprecatedOptions = function(userConfig) {
var checkDeprecatedOptions = function (userConfig) {
var deprecated = require(global.root_path + "/js/deprecated.js");
var deprecatedOptions = deprecated.configs;
var usedDeprecated = [];
deprecatedOptions.forEach(function(option) {
deprecatedOptions.forEach(function (option) {
if (userConfig.hasOwnProperty(option)) {
usedDeprecated.push(option);
}
});
if (usedDeprecated.length > 0) {
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.")
);
Log.warn(Utils.colors.warn("WARNING! Your config is using deprecated options: " + usedDeprecated.join(", ") + ". Check README and CHANGELOG for more up-to-date ways of getting the same functionality."));
}
}
};
/* loadModule(module)
* Loads a specific module.
*
* 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 moduleName = elements[elements.length - 1];
var moduleFolder = __dirname + "/../modules/" + module;
var moduleFolder = __dirname + "/../modules/" + module;
if (defaultModules.indexOf(moduleName) !== -1) {
moduleFolder = __dirname + "/../modules/default/" + module;
moduleFolder = __dirname + "/../modules/default/" + module;
}
var helperPath = moduleFolder + "/node_helper.js";
@@ -120,7 +117,7 @@ var App = function() {
fs.accessSync(helperPath, fs.R_OK);
} catch (e) {
loadModule = false;
console.log("No helper found for module: " + moduleName + ".");
Log.log("No helper found for module: " + moduleName + ".");
}
if (loadModule) {
@@ -128,11 +125,11 @@ var App = function() {
var m = new Module();
if (m.requiresVersion) {
console.log("Check MagicMirror version for node helper '" + moduleName + "' - Minimum version: " + m.requiresVersion + " - Current version: " + global.version);
Log.log("Check MagicMirror version for node helper '" + moduleName + "' - Minimum version: " + m.requiresVersion + " - Current version: " + global.version);
if (cmpVersions(global.version, m.requiresVersion) >= 0) {
console.log("Version is ok!");
Log.log("Version is ok!");
} else {
console.log("Version is incorrect. Skip module: '" + moduleName + "'");
Log.log("Version is incorrect. Skip module: '" + moduleName + "'");
return;
}
}
@@ -152,19 +149,19 @@ var App = function() {
*
* argument module string - The name of the module (including subpath).
*/
var loadModules = function(modules, callback) {
console.log("Loading module helpers ...");
var loadModules = function (modules, callback) {
Log.log("Loading module helpers ...");
var loadNextModule = function() {
var loadNextModule = function () {
if (modules.length > 0) {
var nextModule = modules[0];
loadModule(nextModule, function() {
loadModule(nextModule, function () {
modules = modules.slice(1);
loadNextModule();
});
} else {
// All modules are loaded
console.log("All module helpers loaded.");
Log.log("All module helpers loaded.");
callback();
}
};
@@ -173,7 +170,7 @@ var App = function() {
};
/* cmpVersions(a,b)
* Compare two symantic 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 b.
@@ -197,13 +194,12 @@ var App = function() {
/* start(callback)
* This methods starts the core app.
* It loads the config, then it loads all modules.
* When it"s done it executs the callback with the config as argument.
* When it's done it executes the callback with the config as argument.
*
* argument callback function - The callback function.
*/
this.start = function(callback) {
loadConfig(function(c) {
this.start = function (callback) {
loadConfig(function (c) {
config = c;
var modules = [];
@@ -215,9 +211,9 @@ var App = function() {
}
}
loadModules(modules, function() {
var server = new Server(config, function(app, io) {
console.log("Server started ...");
loadModules(modules, function () {
var server = new Server(config, function (app, io) {
Log.log("Server started ...");
for (var h in nodeHelpers) {
var nodeHelper = nodeHelpers[h];
@@ -226,12 +222,11 @@ var App = function() {
nodeHelper.start();
}
console.log("Sockets connected & modules started ...");
Log.log("Sockets connected & modules started ...");
if (typeof callback === "function") {
callback(config);
}
});
});
});
@@ -242,7 +237,7 @@ var App = function() {
* This calls each node_helper's STOP() function, if it exists.
* Added to fix #1056
*/
this.stop = function() {
this.stop = function () {
for (var h in nodeHelpers) {
var nodeHelper = nodeHelpers[h];
if (typeof nodeHelper.stop === "function") {
@@ -258,8 +253,21 @@ var App = function() {
* this.stop() is called by app.on("before-quit"... in `electron.js`
*/
process.on("SIGINT", () => {
console.log("[SIGINT] Received. Shutting down server...");
setTimeout(() => { process.exit(0); }, 3000); // Force quit after 3 seconds
Log.log("[SIGINT] Received. Shutting down server...");
setTimeout(() => {
process.exit(0);
}, 3000); // Force quit after 3 seconds
this.stop();
process.exit(0);
});
/* We also need to listen to SIGTERM signals so we stop everything when we are asked to stop by the OS.
*/
process.on("SIGTERM", () => {
Log.log("[SIGTERM] Received. Shutting down server...");
setTimeout(() => {
process.exit(0);
}, 3000); // Force quit after 3 seconds
this.stop();
process.exit(0);
});

71
js/check_config.js Normal file
View File

@@ -0,0 +1,71 @@
/* Magic Mirror
*
* Check the configuration file for errors
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.
*/
const Linter = require("eslint").Linter;
const linter = new Linter();
const path = require("path");
const fs = require("fs");
const rootPath = path.resolve(__dirname + "/../");
const config = require(rootPath + "/.eslintrc.json");
const Log = require(rootPath + "/js/logger.js");
const Utils = require(rootPath + "/js/utils.js");
/* getConfigFile()
* Return string with path of configuration file
* Check if set by environment variable MM_CONFIG_FILE
*/
function getConfigFile() {
// FIXME: This function should be in core. Do you want refactor me ;) ?, be good!
let configFileName = path.resolve(rootPath + "/config/config.js");
if (process.env.MM_CONFIG_FILE) {
configFileName = path.resolve(process.env.MM_CONFIG_FILE);
}
return configFileName;
}
function checkConfigFile() {
const configFileName = getConfigFile();
// Check if file is present
if (fs.existsSync(configFileName) === false) {
Log.error(Utils.colors.error("File not found: "), configFileName);
throw new Error("No config file present!");
}
// check permission
try {
fs.accessSync(configFileName, fs.F_OK);
} catch (e) {
Log.log(Utils.colors.error(e));
throw new Error("No permission to access config file!");
}
// Validate syntax of the configuration file.
Log.info(Utils.colors.info("Checking file... "), configFileName);
// I'm not sure if all ever is utf-8
fs.readFile(configFileName, "utf-8", function (err, data) {
if (err) {
throw err;
}
const messages = linter.verify(data, config);
if (messages.length === 0) {
Log.log("Your configuration file doesn't contain syntax errors :)");
return true;
} else {
// In case the there errors show messages and return
messages.forEach((error) => {
Log.log("Line", error.line, "col", error.column, error.message);
});
throw new Error("Wrong syntax in config file!");
}
});
}
checkConfigFile();

View File

@@ -1,15 +1,22 @@
/* global Class, xyz */
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* By John Resig https://johnresig.com/
*
* Inspired by base2 and Prototype
*
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function () {
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)
this.Class = function () { };
this.Class = function () {};
// Create a new Class that inherits from this class
Class.extend = function (prop) {
@@ -21,32 +28,33 @@
var prototype = new this();
initializing = false;
// Make a copy of all prototype properies, to prevent reference issues.
for (var name in prototype) {
prototype[name] = cloneObject(prototype[name]);
// Make a copy of all prototype properties, to prevent reference issues.
for (var p in prototype) {
prototype[p] = cloneObject(prototype[p]);
}
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function (name, fn) {
return function () {
var tmp = this._super;
prototype[name] =
typeof prop[name] === "function" && typeof _super[name] === "function" && fnTest.test(prop[name])
? (function (name, fn) {
return function () {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) : prop[name];
return ret;
};
})(name, prop[name])
: prop[name];
}
// The dummy class constructor
@@ -92,7 +100,4 @@ function cloneObject(obj) {
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {
module.exports = Class;
module.exports._test = {
cloneObject: cloneObject
}
}

View File

@@ -1,20 +1,20 @@
/* exported defaults */
/* global mmPort */
/* Magic Mirror
* Config Defauls
* Config Defaults
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
var port = 8080;
var address = "localhost";
if (typeof(mmPort) !== "undefined") {
var port = 8080;
if (typeof mmPort !== "undefined") {
port = mmPort;
}
var defaults = {
address: address,
port: port,
basePath: "/",
kioskmode: false,
electronOptions: {},
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
@@ -68,14 +68,16 @@ var defaults = {
config: {
text: "www.michaelteeuw.nl"
}
},
}
],
paths: {
modules: "modules",
vendor: "vendor"
},
}
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = defaults;}
if (typeof module !== "undefined") {
module.exports = defaults;
}

View File

@@ -1,14 +1,16 @@
/* Magic Mirror Deprecated Config Options List
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*
* Olex S. original idea this deprecated option
*/
var deprecated = {
configs: ["kioskmode"],
configs: ["kioskmode"]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = deprecated;}
if (typeof module !== "undefined") {
module.exports = deprecated;
}

View File

@@ -1,9 +1,8 @@
/* jshint esversion: 6 */
"use strict";
const electron = require("electron");
const core = require(__dirname + "/app.js");
const core = require("./app.js");
const Log = require("./logger.js");
// Config
var config = process.env.config ? JSON.parse(process.env.config) : {};
@@ -17,6 +16,7 @@ const BrowserWindow = electron.BrowserWindow;
let mainWindow;
function createWindow() {
app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required");
var electronOptionsDefaults = {
width: 800,
height: 600,
@@ -46,8 +46,16 @@ function createWindow() {
// and load the index.html of the app.
// If config.address is not defined or is an empty string (listening on all interfaces), connect to localhost
var prefix;
if (config["tls"] !== null && config["tls"]) {
prefix = "https://";
} else {
prefix = "http://";
}
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"
if (process.argv.includes("dev")) {
@@ -55,21 +63,21 @@ function createWindow() {
}
// Set responders for window events.
mainWindow.on("closed", function() {
mainWindow.on("closed", function () {
mainWindow = null;
});
if (config.kioskmode) {
mainWindow.on("blur", function() {
mainWindow.on("blur", function () {
mainWindow.focus();
});
mainWindow.on("leave-full-screen", function() {
mainWindow.on("leave-full-screen", function () {
mainWindow.setFullScreen(true);
});
mainWindow.on("resize", function() {
setTimeout(function() {
mainWindow.on("resize", function () {
setTimeout(function () {
mainWindow.reload();
}, 1000);
});
@@ -78,17 +86,17 @@ function createWindow() {
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on("ready", function() {
console.log("Launching application.");
app.on("ready", function () {
Log.log("Launching application.");
createWindow();
});
// Quit when all windows are closed.
app.on("window-all-closed", function() {
app.on("window-all-closed", function () {
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
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
@@ -103,9 +111,11 @@ app.on("activate", function() {
* core.stop() is called by process.on("SIGINT"... in `app.js`
*/
app.on("before-quit", (event) => {
console.log("Shutting down server...");
Log.log("Shutting down server...");
event.preventDefault();
setTimeout(() => { process.exit(0); }, 3000); // Force-quit after 3 seconds.
setTimeout(() => {
process.exit(0);
}, 3000); // Force-quit after 3 seconds.
core.stop();
process.exit(0);
});
@@ -113,7 +123,7 @@ app.on("before-quit", (event) => {
// Start the core application if server is run on localhost
// This starts all node helpers and starts the webserver.
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) > -1) {
core.start(function(c) {
core.start(function (c) {
config = c;
});
}

View File

@@ -1,14 +1,13 @@
/* global config, vendor, MM, Log, Module */
/* global defaultModules, vendor */
/* Magic Mirror
* Module and File loaders.
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
var Loader = (function() {
/* Create helper valiables */
var Loader = (function () {
/* Create helper variables */
var loadedModuleFiles = [];
var loadedFiles = [];
@@ -19,14 +18,13 @@ var Loader = (function() {
/* loadModules()
* Loops thru all modules and requests load for every module.
*/
var loadModules = function() {
var loadModules = function () {
var moduleData = getModuleData();
var loadNextModule = function() {
var loadNextModule = function () {
if (moduleData.length > 0) {
var nextModule = moduleData[0];
loadModule(nextModule, function() {
loadModule(nextModule, function () {
moduleData = moduleData.slice(1);
loadNextModule();
});
@@ -35,11 +33,10 @@ var Loader = (function() {
// This is done after all the modules so we can
// overwrite all the defined styles.
loadFile(config.customCss, function() {
loadFile(config.customCss, function () {
// custom.css loaded. Start all modules.
startModules();
});
}
};
@@ -49,13 +46,13 @@ var Loader = (function() {
/* startModules()
* Loops thru all modules and requests start for every module.
*/
var startModules = function() {
var startModules = function () {
for (var m in moduleObjects) {
var module = moduleObjects[m];
module.start();
}
// Notifiy core of loded modules.
// Notify core of loaded modules.
MM.modulesStarted(moduleObjects);
};
@@ -64,7 +61,7 @@ var Loader = (function() {
*
* return array - module data as configured in config
*/
var getAllModules = function() {
var getAllModules = function () {
return config.modules;
};
@@ -73,7 +70,7 @@ var Loader = (function() {
*
* return array - Module information.
*/
var getModuleData = function() {
var getModuleData = function () {
var modules = getAllModules();
var moduleFiles = [];
@@ -83,10 +80,10 @@ var Loader = (function() {
var elements = module.split("/");
var moduleName = elements[elements.length - 1];
var moduleFolder = config.paths.modules + "/" + module;
var moduleFolder = config.paths.modules + "/" + module;
if (defaultModules.indexOf(moduleName) !== -1) {
moduleFolder = config.paths.modules + "/default/" + module;
moduleFolder = config.paths.modules + "/default/" + module;
}
if (moduleData.disabled === true) {
@@ -97,14 +94,13 @@ var Loader = (function() {
index: m,
identifier: "module_" + m + "_" + module,
name: moduleName,
path: moduleFolder + "/" ,
path: moduleFolder + "/",
file: moduleName + ".js",
position: moduleData.position,
header: moduleData.header,
config: moduleData.config,
classes: (typeof moduleData.classes !== "undefined") ? moduleData.classes + " " + module : module
classes: typeof moduleData.classes !== "undefined" ? moduleData.classes + " " + module : module
});
}
return moduleFiles;
@@ -116,13 +112,13 @@ var Loader = (function() {
* argument callback function - Function called when done.
* 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 afterLoad = function() {
var afterLoad = function () {
var moduleObject = Module.create(module.name);
if (moduleObject) {
bootstrapModule(module, moduleObject, function() {
bootstrapModule(module, moduleObject, function () {
callback();
});
} else {
@@ -133,12 +129,11 @@ var Loader = (function() {
if (loadedModuleFiles.indexOf(url) !== -1) {
afterLoad();
} else {
loadFile(url, function() {
loadFile(url, function () {
loadedModuleFiles.push(url);
afterLoad();
});
}
};
/* bootstrapModule(module, mObj)
@@ -148,23 +143,22 @@ var Loader = (function() {
* argument mObj object - Modules instance.
* 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);
mObj.setData(module);
mObj.loadScripts(function() {
mObj.loadScripts(function () {
Log.log("Scripts loaded for: " + module.name);
mObj.loadStyles(function() {
mObj.loadStyles(function () {
Log.log("Styles loaded for: " + module.name);
mObj.loadTranslations(function() {
mObj.loadTranslations(function () {
Log.log("Translations loaded for: " + module.name);
moduleObjects.push(mObj);
callback();
});
});
});
};
/* loadFile(fileName)
@@ -173,53 +167,58 @@ var Loader = (function() {
* argument fileName string - Path of the file we want to load.
* argument callback function - Function called when done.
*/
var loadFile = function(fileName, callback) {
var extension = fileName.slice((Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1);
var loadFile = function (fileName, callback) {
var extension = fileName.slice((Math.max(0, fileName.lastIndexOf(".")) || Infinity) + 1);
switch (extension.toLowerCase()) {
case "js":
Log.log("Load script: " + fileName);
var script = document.createElement("script");
script.type = "text/javascript";
script.src = fileName;
script.onload = function() {
if (typeof callback === "function") {callback();}
};
script.onerror = function() {
console.error("Error on loading script:", fileName);
if (typeof callback === "function") {callback();}
};
case "js":
Log.log("Load script: " + fileName);
var script = document.createElement("script");
script.type = "text/javascript";
script.src = fileName;
script.onload = function () {
if (typeof callback === "function") {
callback();
}
};
script.onerror = function () {
Log.error("Error on loading script:", fileName);
if (typeof callback === "function") {
callback();
}
};
document.getElementsByTagName("body")[0].appendChild(script);
break;
case "css":
Log.log("Load stylesheet: " + fileName);
var stylesheet = document.createElement("link");
stylesheet.rel = "stylesheet";
stylesheet.type = "text/css";
stylesheet.href = fileName;
stylesheet.onload = function() {
if (typeof callback === "function") {callback();}
};
stylesheet.onerror = function() {
console.error("Error on loading stylesheet:", fileName);
if (typeof callback === "function") {callback();}
};
document.getElementsByTagName("body")[0].appendChild(script);
break;
case "css":
Log.log("Load stylesheet: " + fileName);
var stylesheet = document.createElement("link");
stylesheet.rel = "stylesheet";
stylesheet.type = "text/css";
stylesheet.href = fileName;
stylesheet.onload = function () {
if (typeof callback === "function") {
callback();
}
};
stylesheet.onerror = function () {
Log.error("Error on loading stylesheet:", fileName);
if (typeof callback === "function") {
callback();
}
};
document.getElementsByTagName("head")[0].appendChild(stylesheet);
break;
document.getElementsByTagName("head")[0].appendChild(stylesheet);
break;
}
};
/* Public Methods */
return {
/* loadModules()
* Load all modules as defined in the config.
*/
loadModules: function() {
loadModules: function () {
loadModules();
},
@@ -231,8 +230,7 @@ var Loader = (function() {
* argument module Module Object - the module that calls the loadFile function.
* argument callback function - Function called when done.
*/
loadFile: function(fileName, module, callback) {
loadFile: function (fileName, module, callback) {
if (loadedFiles.indexOf(fileName.toLowerCase()) !== -1) {
Log.log("File already loaded: " + fileName);
callback();
@@ -261,5 +259,4 @@ var Loader = (function() {
loadFile(module.file(fileName), callback);
}
};
})();

View File

@@ -1,20 +1,27 @@
/* global console */
/* exported Log */
/* Magic Mirror
* Logger
* Log
*
* By Michael Teeuw http://michaelteeuw.nl
* 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 https://michaelteeuw.nl
* MIT Licensed.
*/
(function (root, factory) {
if (typeof exports === "object") {
// add timestamps in front of log messages
require("console-stamp")(console, "yyyy-mm-dd HH:MM:ss.l");
// 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 {
// Node, CommonJS-like
module.exports = factory(root.config);
} else {
// Browser globals (root is window)
root.Log = factory(root.config);
}
})(this, function (config) {
let logLevel = {
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),
warn: Function.prototype.bind.call(console.warn, console),
group: Function.prototype.bind.call(console.group, console),
@@ -24,4 +31,14 @@ var Log = (function() {
timeEnd: Function.prototype.bind.call(console.timeEnd, console),
timeStamp: Function.prototype.bind.call(console.timeStamp, console)
};
})();
if (config && config.logLevel) {
Object.keys(logLevel).forEach(function (key, index) {
if (!config.logLevel.includes(key.toLocaleUpperCase())) {
logLevel[key] = function () {};
}
});
}
return logLevel;
});

View File

@@ -1,15 +1,12 @@
/* global Log, Loader, Module, config, defaults */
/* jshint -W020 */
/* global Loader, defaults, Translator */
/* Magic Mirror
* Main System
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
var MM = (function() {
var MM = (function () {
var modules = [];
/* Private Methods */
@@ -18,43 +15,54 @@ var MM = (function() {
* Create dom objects for all modules that
* are configured for a specific position.
*/
var createDomObjects = function() {
for (var m in modules) {
var module = modules[m];
var createDomObjects = function () {
var domCreationPromises = [];
if (typeof module.data.position === "string") {
var wrapper = selectWrapper(module.data.position);
var dom = document.createElement("div");
dom.id = module.identifier;
dom.className = module.name;
if (typeof module.data.classes === "string") {
dom.className = "module " + dom.className + " " + module.data.classes;
}
dom.opacity = 0;
wrapper.appendChild(dom);
if (typeof module.data.header !== "undefined" && module.data.header !== "") {
var moduleHeader = document.createElement("header");
moduleHeader.innerHTML = module.data.header;
moduleHeader.className = "module-header";
dom.appendChild(moduleHeader);
}
var moduleContent = document.createElement("div");
moduleContent.className = "module-content";
dom.appendChild(moduleContent);
updateDom(module, 0);
modules.forEach(function (module) {
if (typeof module.data.position !== "string") {
return;
}
}
var wrapper = selectWrapper(module.data.position);
var dom = document.createElement("div");
dom.id = module.identifier;
dom.className = module.name;
if (typeof module.data.classes === "string") {
dom.className = "module " + dom.className + " " + module.data.classes;
}
dom.opacity = 0;
wrapper.appendChild(dom);
var moduleHeader = document.createElement("header");
moduleHeader.innerHTML = module.getHeader();
moduleHeader.className = "module-header";
dom.appendChild(moduleHeader);
if (typeof module.getHeader() === "undefined" || module.getHeader() !== "") {
moduleHeader.style = "display: none;";
}
var moduleContent = document.createElement("div");
moduleContent.className = "module-content";
dom.appendChild(moduleContent);
var domCreationPromise = updateDom(module, 0);
domCreationPromises.push(domCreationPromise);
domCreationPromise
.then(function () {
sendNotification("MODULE_DOM_CREATED", null, null, module);
})
.catch(Log.error);
});
updateWrapperStates();
sendNotification("DOM_OBJECTS_CREATED");
Promise.all(domCreationPromises).then(function () {
sendNotification("DOM_OBJECTS_CREATED");
});
};
/* selectWrapper(position)
@@ -62,8 +70,8 @@ var MM = (function() {
*
* argument position string - The name of the position.
*/
var selectWrapper = function(position) {
var classes = position.replace("_"," ");
var selectWrapper = function (position) {
var classes = position.replace("_", " ");
var parentWrapper = document.getElementsByClassName(classes);
if (parentWrapper.length > 0) {
var wrapper = parentWrapper[0].getElementsByClassName("container");
@@ -79,11 +87,12 @@ var MM = (function() {
* argument notification string - The identifier of the notification.
* argument payload mixed - The payload of the notification.
* argument sender Module - The module that sent the notification.
* argument sendTo Module - The module to send the notification to. (optional)
*/
var sendNotification = function(notification, payload, sender) {
var sendNotification = function (notification, payload, sender, sendTo) {
for (var m in modules) {
var module = modules[m];
if (module !== sender) {
if (module !== sender && (!sendTo || module === sendTo)) {
module.notificationReceived(notification, payload, sender);
}
}
@@ -94,43 +103,83 @@ var MM = (function() {
*
* argument module Module - The module that needs an update.
* argument speed Number - The number of microseconds for the animation. (optional)
*
* return Promise - Resolved when the dom is fully updated.
*/
var updateDom = function(module, speed) {
var newContent = module.getDom();
var newHeader = module.getHeader();
var updateDom = function (module, speed) {
return new Promise(function (resolve) {
var newContentPromise = module.getDom();
var newHeader = module.getHeader();
if (!module.hidden) {
if (!(newContentPromise instanceof Promise)) {
// convert to a promise if not already one to avoid if/else's everywhere
newContentPromise = Promise.resolve(newContentPromise);
}
newContentPromise
.then(function (newContent) {
var updatePromise = updateDomWithContent(module, speed, newHeader, newContent);
updatePromise.then(resolve).catch(Log.error);
})
.catch(Log.error);
});
};
/* updateDomWithContent(module, speed, newHeader, newContent)
* Update the dom with the specified content
*
* argument module Module - The module that needs an update.
* argument speed Number - The number of microseconds for the animation. (optional)
* argument newHeader String - The new header that is generated.
* argument newContent Domobject - The new content that is generated.
*
* return Promise - Resolved when the module dom has been updated.
*/
var updateDomWithContent = function (module, speed, newHeader, newContent) {
return new Promise(function (resolve) {
if (module.hidden || !speed) {
updateModuleContent(module, newHeader, newContent);
resolve();
return;
}
if (!moduleNeedsUpdate(module, newHeader, newContent)) {
resolve();
return;
}
if (!speed) {
updateModuleContent(module, newHeader, newContent);
resolve();
return;
}
hideModule(module, speed / 2, function() {
hideModule(module, speed / 2, function () {
updateModuleContent(module, newHeader, newContent);
if (!module.hidden) {
showModule(module, speed / 2);
}
resolve();
});
} else {
updateModuleContent(module, newHeader, newContent);
}
});
};
/* moduleNeedsUpdate(module, newContent)
* Check if the content has changed.
*
* argument module Module - The module to check.
* argument newHeader String - The new header that is generated.
* argument newContent Domobject - The new content that is generated.
*
* 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);
if (moduleWrapper === null) {
return false;
}
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
@@ -152,19 +201,22 @@ var MM = (function() {
* Update the content of a module on screen.
*
* argument module Module - The module to check.
* argument newHeader String - The new header 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);
if (moduleWrapper === null) {
return;
}
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");
contentWrapper[0].innerHTML = "";
contentWrapper[0].appendChild(newContent);
if( headerWrapper.length > 0 && newHeader) {
headerWrapper[0].innerHTML = newHeader;
}
headerWrapper[0].innerHTML = newHeader;
headerWrapper[0].style = headerWrapper.length > 0 && newHeader ? undefined : "display: none;";
};
/* hideModule(module, speed, callback)
@@ -174,7 +226,7 @@ var MM = (function() {
* argument speed Number - The speed of the hide animation.
* 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 || {};
// set lockString if set in options.
@@ -191,7 +243,7 @@ var MM = (function() {
moduleWrapper.style.opacity = 0;
clearTimeout(module.showHideTimer);
module.showHideTimer = setTimeout(function() {
module.showHideTimer = setTimeout(function () {
// 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
// below other modules. This works way better than adjusting
@@ -200,8 +252,15 @@ var MM = (function() {
updateWrapperStates();
if (typeof callback === "function") { callback(); }
if (typeof callback === "function") {
callback();
}
}, speed);
} else {
// invoke callback even if no content, issue 1308
if (typeof callback === "function") {
callback();
}
}
};
@@ -212,13 +271,13 @@ var MM = (function() {
* argument speed Number - The speed of the show animation.
* 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 || {};
// remove lockString if set in options.
if (options.lockString) {
var index = module.lockStrings.indexOf(options.lockString);
if ( index !== -1) {
if (index !== -1) {
module.lockStrings.splice(index, 1);
}
}
@@ -241,7 +300,7 @@ var MM = (function() {
var moduleWrapper = document.getElementById(module.identifier);
if (moduleWrapper !== null) {
moduleWrapper.style.transition = "opacity " + speed / 1000 + "s";
// Restore the postition. See hideModule() for more info.
// Restore the position. See hideModule() for more info.
moduleWrapper.style.position = "static";
updateWrapperStates();
@@ -251,17 +310,23 @@ var MM = (function() {
moduleWrapper.style.opacity = 1;
clearTimeout(module.showHideTimer);
module.showHideTimer = setTimeout(function() {
if (typeof callback === "function") { callback(); }
module.showHideTimer = setTimeout(function () {
if (typeof callback === "function") {
callback();
}
}, speed);
} else {
// invoke callback
if (typeof callback === "function") {
callback();
}
}
};
/* updateWrapperStates()
* Checks for all positions if it has visible content.
* If not, if will hide the position to prevent unwanted margins.
* This method schould be called by the show and hide methods.
* This method should be called by the show and hide methods.
*
* Example:
* If the top_bar only contains the update notification. And no update is available,
@@ -269,17 +334,16 @@ var MM = (function() {
* an ugly top margin. By using this function, the top bar will be hidden if the
* 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"];
positions.forEach(function(position) {
positions.forEach(function (position) {
var wrapper = selectWrapper(position);
var moduleWrappers = wrapper.getElementsByClassName("module");
var showWrapper = false;
Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) {
if (moduleWrapper.style.position == "" || moduleWrapper.style.position == "static") {
Array.prototype.forEach.call(moduleWrappers, function (moduleWrapper) {
if (moduleWrapper.style.position === "" || moduleWrapper.style.position === "static") {
showWrapper = true;
}
});
@@ -291,7 +355,9 @@ var MM = (function() {
/* loadConfig()
* 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") {
config = defaults;
Log.error("Config file is missing! Please create a config file.");
@@ -299,6 +365,7 @@ var MM = (function() {
}
config = Object.assign({}, defaults, config);
/* eslint-enable */
};
/* setSelectionMethodsForModules()
@@ -306,8 +373,7 @@ var MM = (function() {
*
* argument modules array - Array of modules.
*/
var setSelectionMethodsForModules = function(modules) {
var setSelectionMethodsForModules = function (modules) {
/* withClass(className)
* calls modulesByClass to filter modules with the specified classes.
*
@@ -315,7 +381,7 @@ var MM = (function() {
*
* return array - Filtered collection of modules.
*/
var withClass = function(className) {
var withClass = function (className) {
return modulesByClass(className, true);
};
@@ -326,7 +392,7 @@ var MM = (function() {
*
* return array - Filtered collection of modules.
*/
var exceptWithClass = function(className) {
var exceptWithClass = function (className) {
return modulesByClass(className, false);
};
@@ -338,13 +404,13 @@ var MM = (function() {
*
* return array - Filtered collection of modules.
*/
var modulesByClass = function(className, include) {
var modulesByClass = function (className, include) {
var searchClasses = className;
if (typeof className === "string") {
searchClasses = className.split(" ");
}
var newModules = modules.filter(function(module) {
var newModules = modules.filter(function (module) {
var classes = module.data.classes.toLowerCase().split(" ");
for (var c in searchClasses) {
@@ -368,8 +434,8 @@ var MM = (function() {
*
* return array - Filtered collection of modules.
*/
var exceptModule = function(module) {
var newModules = modules.filter(function(mod) {
var exceptModule = function (module) {
var newModules = modules.filter(function (mod) {
return mod.identifier !== module.identifier;
});
@@ -382,16 +448,24 @@ var MM = (function() {
*
* argument callback function - The function to execute with the module as an argument.
*/
var enumerate = function(callback) {
modules.map(function(module) {
var enumerate = function (callback) {
modules.map(function (module) {
callback(module);
});
};
if (typeof modules.withClass === "undefined") { Object.defineProperty(modules, "withClass", {value: withClass, 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}); }
if (typeof modules.withClass === "undefined") {
Object.defineProperty(modules, "withClass", { value: withClass, 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 {
@@ -400,7 +474,7 @@ var MM = (function() {
/* init()
* Main init method.
*/
init: function() {
init: function () {
Log.info("Initializing MagicMirror.");
loadConfig();
Translator.loadCoreTranslations(config.language);
@@ -412,7 +486,7 @@ var MM = (function() {
*
* argument moduleObjects array<Module> - All module instances.
*/
modulesStarted: function(moduleObjects) {
modulesStarted: function (moduleObjects) {
modules = [];
for (var m in moduleObjects) {
var module = moduleObjects[m];
@@ -428,11 +502,11 @@ var MM = (function() {
/* sendNotification(notification, payload, sender)
* Send a notification to all modules.
*
* argument notification string - The identifier of the noitication.
* argument notification string - The identifier of the notification.
* argument payload mixed - The payload of 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) {
Log.error("sendNotification: Missing arguments.");
return;
@@ -458,7 +532,7 @@ var MM = (function() {
* argument module Module - The module that needs an update.
* argument speed Number - The number of microseconds for the animation. (optional)
*/
updateDom: function(module, speed) {
updateDom: function (module, speed) {
if (!(module instanceof Module)) {
Log.error("updateDom: Sender should be a module.");
return;
@@ -473,7 +547,7 @@ var MM = (function() {
*
* return array - A collection of all modules currently active.
*/
getModules: function() {
getModules: function () {
setSelectionMethodsForModules(modules);
return modules;
},
@@ -486,7 +560,7 @@ var MM = (function() {
* argument callback function - Called when the animation is done.
* argument options object - Optional settings for the hide method.
*/
hideModule: function(module, speed, callback, options) {
hideModule: function (module, speed, callback, options) {
module.hidden = true;
hideModule(module, speed, callback, options);
},
@@ -499,18 +573,17 @@ var MM = (function() {
* argument callback function - Called when the animation is done.
* 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
showModule(module, speed, callback, options);
}
};
})();
// Add polyfill for Object.assign.
if (typeof Object.assign != "function") {
(function() {
Object.assign = function(target) {
if (typeof Object.assign !== "function") {
(function () {
Object.assign = function (target) {
"use strict";
if (target === undefined || target === null) {
throw new TypeError("Cannot convert undefined or null to object");

View File

@@ -1,15 +1,12 @@
/* global Log, Class, Loader, Class , MM */
/* exported Module */
/* global Class, cloneObject, Loader, MMSocket, nunjucks, Translator */
/* Magic Mirror
* Module Blueprint.
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
var Module = Class.extend({
/*********************************************************
* All methods (and properties) below can be subclassed. *
*********************************************************/
@@ -76,36 +73,36 @@ var Module = Class.extend({
/* getDom()
* This method generates the dom which needs to be displayed. This method is called by the Magic Mirror core.
* This method can to be subclassed if the module wants to display info on the mirror.
* Alternatively, the getTemplete method could be subclassed.
* Alternatively, the getTemplate method could be subclassed.
*
* return domobject - The dom to display.
* return DomObject | Promise - The dom or a promise with the dom to display.
*/
getDom: function () {
var div = document.createElement("div");
var template = this.getTemplate();
var templateData = this.getTemplateData();
var self = this;
return new Promise(function (resolve) {
var div = document.createElement("div");
var template = self.getTemplate();
var templateData = self.getTemplateData();
// Check to see if we need to render a template string or a file.
if (/^.*((\.html)|(\.njk))$/.test(template)) {
// the template is a filename
this.nunjucksEnvironment().render(template, templateData, function (err, res) {
if (err) {
Log.error(err)
}
// Check to see if we need to render a template string or a file.
if (/^.*((\.html)|(\.njk))$/.test(template)) {
// the template is a filename
self.nunjucksEnvironment().render(template, templateData, function (err, res) {
if (err) {
Log.error(err);
}
// The inner content of the div will be set after the template is received.
// This isn't the most optimal way, but since it's near instant
// it probably won't be an issue.
// If it gives problems, we can always add a way to pre fetch the templates.
// Let's not over optimise this ... KISS! :)
div.innerHTML = res;
});
} else {
// the template is a template string.
div.innerHTML = this.nunjucksEnvironment().renderString(template, templateData);
}
div.innerHTML = res;
return div;
resolve(div);
});
} else {
// the template is a template string.
div.innerHTML = self.nunjucksEnvironment().renderString(template, templateData);
resolve(div);
}
});
},
/* getHeader()
@@ -121,14 +118,14 @@ var Module = Class.extend({
/* getTemplate()
* This method returns the template for the module which is used by the default getDom implementation.
* This method needs to be subclassed if the module wants to use a tempate.
* This method needs to be subclassed if the module wants to use a template.
* It can either return a template sting, or a template filename.
* If the string ends with '.html' it's considered a file from within the module's folder.
*
* return string - The template string of filename.
*/
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()
@@ -138,7 +135,7 @@ var Module = Class.extend({
* return Object
*/
getTemplateData: function () {
return {}
return {};
},
/* notificationReceived(notification, payload, sender)
@@ -151,9 +148,9 @@ var Module = Class.extend({
*/
notificationReceived: function (notification, payload, sender) {
if (sender) {
Log.log(this.name + " received a module notification: " + notification + " from sender: " + sender.name);
// Log.log(this.name + " received a module notification: " + notification + " from sender: " + sender.name);
} else {
Log.log(this.name + " received a system notification: " + notification);
// Log.log(this.name + " received a system notification: " + notification);
}
},
@@ -163,19 +160,19 @@ var Module = Class.extend({
* @returns Nunjucks Environment
*/
nunjucksEnvironment: function() {
if (this._nunjucksEnvironment != null) {
nunjucksEnvironment: function () {
if (this._nunjucksEnvironment !== null) {
return this._nunjucksEnvironment;
}
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,
lstripBlocks: true
});
this._nunjucksEnvironment.addFilter("translate", function(str) {
return self.translate(str)
this._nunjucksEnvironment.addFilter("translate", function (str) {
return self.translate(str);
});
return this._nunjucksEnvironment;
@@ -212,7 +209,7 @@ var Module = Class.extend({
/* setData(data)
* Set the module data.
*
* argument data obejct - Module data.
* argument data object - Module data.
*/
setData: function (data) {
this.data = data;
@@ -226,19 +223,19 @@ var Module = Class.extend({
/* setConfig(config)
* Set the module config and combine it with the module defaults.
*
* argument config obejct - Module config.
* argument config object - Module config.
*/
setConfig: function (config) {
this.config = Object.assign({}, this.defaults, config);
},
/* socket()
* Returns a socket object. If it doesn"t exist, it"s created.
* Returns a socket object. If it doesn't exist, it"s created.
* It also registers the notification callback.
*/
socket: function () {
if (typeof this._socket === "undefined") {
this._socket = this._socket = new MMSocket(this.name);
this._socket = new MMSocket(this.name);
}
var self = this;
@@ -315,7 +312,9 @@ var Module = Class.extend({
// The variable `first` will contain the first
// defined translation after the following line.
for (var first in translations) { break; }
for (var first in translations) {
break;
}
if (translations) {
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.
*
* argument key string - The key of the string to translate
* argument defaultValueOrVariables string/object - The default value or variables for translating. (Optional)
* argument defaultValue string - The default value with variables. (Optional)
* argument defaultValueOrVariables string/object - The default value or variables for translating. (Optional)
* argument defaultValue string - The default value with variables. (Optional)
*/
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 || "";
@@ -388,17 +387,22 @@ var Module = Class.extend({
hide: function (speed, callback, options) {
if (typeof callback === "object") {
options = callback;
callback = function () { };
callback = function () {};
}
callback = callback || function () { };
callback = callback || function () {};
options = options || {};
var self = this;
MM.hideModule(self, speed, function () {
self.suspend();
callback();
}, options);
MM.hideModule(
self,
speed,
function () {
self.suspend();
callback();
},
options
);
},
/* showModule(module, speed, callback)
@@ -411,21 +415,28 @@ var Module = Class.extend({
show: function (speed, callback, options) {
if (typeof callback === "object") {
options = callback;
callback = function () { };
callback = function () {};
}
callback = callback || function () { };
callback = callback || function () {};
options = options || {};
this.resume();
MM.showModule(this, speed, callback, options);
var self = this;
MM.showModule(
this,
speed,
function () {
self.resume();
callback;
},
options
);
}
});
Module.definitions = {};
Module.create = function (name) {
// Make sure module definition is available.
if (!Module.definitions[name]) {
return;
@@ -438,15 +449,14 @@ Module.create = function (name) {
var ModuleClass = Module.extend(clonedDefinition);
return new ModuleClass();
};
/* cmpVersions(a,b)
* Compare two symantic version numbers and return the difference.
*
* argument a string - Version number a.
* argument a string - Version number b.
*/
* Compare two semantic version numbers and return the difference.
*
* argument a string - Version number a.
* argument a string - Version number b.
*/
function cmpVersions(a, b) {
var i, diff;
var regExStrip0 = /(\.0+)+$/;
@@ -464,10 +474,9 @@ function cmpVersions(a, b) {
}
Module.register = function (name, moduleDefinition) {
if (moduleDefinition.requiresVersion) {
Log.log("Check MagicMirror version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + version);
if (cmpVersions(version, moduleDefinition.requiresVersion) >= 0) {
Log.log("Check MagicMirror version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + window.version);
if (cmpVersions(window.version, moduleDefinition.requiresVersion) >= 0) {
Log.log("Version is ok!");
} else {
Log.log("Version is incorrect. Skip module: '" + name + "'");
@@ -477,11 +486,3 @@ Module.register = function (name, moduleDefinition) {
Log.log("Module registered: " + name);
Module.definitions[name] = moduleDefinition;
};
if (typeof exports != "undefined") { // For testing purpose only
// A good a idea move the function cmpversions a helper file.
// It's used into other side.
exports._test = {
cmpVersions: cmpVersions
}
}

View File

@@ -1,26 +1,25 @@
/* Magic Mirror
* Node Helper Superclass
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const Class = require("./class.js");
const Log = require("./logger.js");
const express = require("express");
var Class = require("../../../js/class.js");
var express = require("express");
var path = require("path");
NodeHelper = Class.extend({
init: function() {
console.log("Initializing new module helper ...");
var NodeHelper = Class.extend({
init: function () {
Log.log("Initializing new module helper ...");
},
loaded: function(callback) {
console.log("Module helper loaded: " + this.name);
loaded: function (callback) {
Log.log("Module helper loaded: " + this.name);
callback();
},
start: function() {
console.log("Starting module helper: " + this.name);
start: function () {
Log.log("Starting module helper: " + this.name);
},
/* stop()
@@ -29,8 +28,8 @@ NodeHelper = Class.extend({
* gracefully exit the module.
*
*/
stop: function() {
console.log("Stopping module helper: " + this.name);
stop: function () {
Log.log("Stopping module helper: " + this.name);
},
/* socketNotificationReceived(notification, payload)
@@ -39,8 +38,8 @@ NodeHelper = Class.extend({
* argument notification string - The identifier of the notification.
* argument payload mixed - The payload of the notification.
*/
socketNotificationReceived: function(notification, payload) {
console.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
socketNotificationReceived: function (notification, payload) {
Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
},
/* setName(name)
@@ -48,7 +47,7 @@ NodeHelper = Class.extend({
*
* argument name string - Module name.
*/
setName: function(name) {
setName: function (name) {
this.name = name;
},
@@ -57,7 +56,7 @@ NodeHelper = Class.extend({
*
* argument path string - Module path.
*/
setPath: function(path) {
setPath: function (path) {
this.path = path;
},
@@ -67,7 +66,7 @@ NodeHelper = Class.extend({
* argument notification string - The identifier 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);
},
@@ -77,7 +76,7 @@ NodeHelper = Class.extend({
*
* argument app Express app - The Express app object.
*/
setExpressApp: function(app) {
setExpressApp: function (app) {
this.expressApp = app;
var publicPath = this.path + "/public";
@@ -90,36 +89,38 @@ NodeHelper = Class.extend({
*
* argument io Socket.io - The Socket io object.
*/
setSocketIO: function(io) {
setSocketIO: function (io) {
var self = this;
self.io = io;
console.log("Connecting socket for: " + this.name);
Log.log("Connecting socket for: " + 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.
var onevent = socket.onevent;
socket.onevent = function(packet) {
socket.onevent = function (packet) {
var args = packet.data || [];
onevent.call(this, packet); // original call
onevent.call(this, packet); // original call
packet.data = ["*"].concat(args);
onevent.call(this, packet); // additional call to catch-all
onevent.call(this, packet); // additional call to catch-all
};
// register catch all.
socket.on("*", function(notification, payload) {
socket.on("*", function (notification, payload) {
if (notification !== "*") {
//console.log('received message in namespace: ' + namespace);
//Log.log('received message in namespace: ' + namespace);
self.socketNotificationReceived(notification, payload);
}
});
});
}
});
NodeHelper.create = function(moduleDefinition) {
NodeHelper.create = function (moduleDefinition) {
return NodeHelper.extend(moduleDefinition);
};
module.exports = NodeHelper;
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {
module.exports = NodeHelper;
}

View File

@@ -1,41 +1,51 @@
/* Magic Mirror
* Server
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
var express = require("express");
var app = require("express")();
var server = require("http").Server(app);
var io = require("socket.io")(server);
var path = require("path");
var ipfilter = require("express-ipfilter").IpFilter;
var fs = require("fs");
var helmet = require("helmet");
var Utils = require(__dirname + "/utils.js");
var Server = function(config, callback) {
var Log = require("./logger.js");
var Utils = require("./utils.js");
var Server = function (config, callback) {
var port = config.port;
if (process.env.MM_PORT) {
port = process.env.MM_PORT;
}
console.log("Starting server on port " + port + " ... ");
var server = null;
if (config.useHttps) {
var options = {
key: fs.readFileSync(config.httpsPrivateKey),
cert: fs.readFileSync(config.httpsCertificate)
};
server = require("https").Server(options, app);
} else {
server = require("http").Server(app);
}
var io = require("socket.io")(server);
server.listen(port, config.address ? config.address : null);
Log.log("Starting server on port " + port + " ... ");
if (config.ipWhitelist instanceof Array && config.ipWhitelist.length == 0) {
console.info(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs"))
server.listen(port, config.address ? config.address : "localhost");
if (config.ipWhitelist instanceof Array && config.ipWhitelist.length === 0) {
Log.info(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs"));
}
app.use(function(req, res, next) {
var result = ipfilter(config.ipWhitelist, {mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false})(req, res, function(err) {
app.use(function (req, res, next) {
var result = ipfilter(config.ipWhitelist, { mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false })(req, res, function (err) {
if (err === undefined) {
return next();
}
console.log(err.message);
Log.log(err.message);
res.status(403).send("This device is not allowed to access your mirror. <br> Please check your config.js or config.js.sample to change this.");
});
});
@@ -49,21 +59,21 @@ var Server = function(config, callback) {
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);
});
app.get("/config", function(req,res) {
app.get("/config", function (req, res) {
res.send(config);
});
app.get("/", function(req, res) {
var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), {encoding: "utf8"});
app.get("/", function (req, res) {
var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), { encoding: "utf8" });
html = html.replace("#VERSION#", global.version);
configFile = "config/config.js";
if (typeof(global.configuration_file) !== "undefined") {
configFile = global.configuration_file;
var configFile = "config/config.js";
if (typeof global.configuration_file !== "undefined") {
configFile = global.configuration_file;
}
html = html.replace("#CONFIG_FILE#", configFile);

View File

@@ -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
});
}
};
};

View File

@@ -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;
if (typeof moduleName !== "string") {
@@ -8,30 +16,36 @@ var MMSocket = function(moduleName) {
self.moduleName = moduleName;
// Private Methods
self.socket = io("/" + self.moduleName);
var notificationCallback = function() {};
var base = "/";
if (typeof config !== "undefined" && typeof config.basePath !== "undefined") {
base = config.basePath;
}
self.socket = io("/" + self.moduleName, {
path: base + "socket.io"
});
var notificationCallback = function () {};
var onevent = self.socket.onevent;
self.socket.onevent = function(packet) {
self.socket.onevent = function (packet) {
var args = packet.data || [];
onevent.call(this, packet); // original call
onevent.call(this, packet); // original call
packet.data = ["*"].concat(args);
onevent.call(this, packet); // additional call to catch-all
onevent.call(this, packet); // additional call to catch-all
};
// register catch all.
self.socket.on("*", function(notification, payload) {
self.socket.on("*", function (notification, payload) {
if (notification !== "*") {
notificationCallback(notification, payload);
}
});
// Public Methods
this.setNotificationCallback = function(callback) {
this.setNotificationCallback = function (callback) {
notificationCallback = callback;
};
this.sendNotification = function(notification, payload) {
this.sendNotification = function (notification, payload) {
if (typeof payload === "undefined") {
payload = {};
}

View File

@@ -1,12 +1,12 @@
/* exported Translator */
/* global translations */
/* Magic Mirror
* Translator (l10n)
*
* By Christopher Fenner http://github.com/CFenner
* By Christopher Fenner https://github.com/CFenner
* MIT Licensed.
*/
var Translator = (function() {
var Translator = (function () {
/* loadJSON(file, callback)
* Load a JSON file via XHR.
*
@@ -18,7 +18,7 @@ var Translator = (function() {
xhr.overrideMimeType("application/json");
xhr.open("GET", file, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == "200") {
if (xhr.readyState === 4 && xhr.status === 200) {
callback(JSON.parse(stripComments(xhr.responseText)));
}
};
@@ -61,7 +61,7 @@ var Translator = (function() {
currentChar = str[i];
nextChar = str[i + 1];
if (!insideComment && currentChar === "\"") {
if (!insideComment && currentChar === '"') {
var escaped = str[i - 1] === "\\" && str[i - 2] !== "\\";
if (!escaped) {
insideString = !insideString;
@@ -118,7 +118,7 @@ var Translator = (function() {
* argument key string - The key of the text to translate.
* 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
// Combines template and variables like:
@@ -126,15 +126,18 @@ var Translator = (function() {
// variables: {timeToWait: "2 hours", work: "painting"}
// to: "Please wait for 2 hours before continuing with painting."
function createStringFromTemplate(template, variables) {
if(variables.fallback && !template.match(new RegExp("\{.+\}"))) {
if (Object.prototype.toString.call(template) !== "[object String]") {
return template;
}
if (variables.fallback && !template.match(new RegExp("{.+}"))) {
template = variables.fallback;
}
return template.replace(new RegExp("\{([^\}]+)\}", "g"), function(_unused, varName){
return variables[varName] || "{"+varName+"}";
return template.replace(new RegExp("{([^}]+)}", "g"), function (_unused, 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: ");
return createStringFromTemplate(this.translations[module.name][key], variables);
}
@@ -156,14 +159,16 @@ var Translator = (function() {
return key;
},
/* load(module, file, callback)
/* load(module, file, isFallback, callback)
* Load a translation file (json) and remember the data.
*
* argument module Module - The module to load the translation file for.
* argument file string - Path of the file we want to load.
* argument isFallback boolean - Flag to indicate fallback translations.
* argument callback function - Function called when done.
*/
load: function(module, file, isFallback, callback) {
load: function (module, file, isFallback, callback) {
if (!isFallback) {
Log.log(module.name + " - Load translation: " + file);
} else {
@@ -171,8 +176,8 @@ var Translator = (function() {
}
var self = this;
if(!this.translationsFallback[module.name]) {
loadJSON(module.file(file), function(json) {
if (!this.translationsFallback[module.name]) {
loadJSON(module.file(file), function (json) {
if (!isFallback) {
self.translations[module.name] = json;
} else {
@@ -190,12 +195,12 @@ var Translator = (function() {
*
* argument lang String - The language identifier of the core language.
*/
loadCoreTranslations: function(lang) {
loadCoreTranslations: function (lang) {
var self = this;
if (lang in translations) {
Log.log("Loading core translation file: " + translations[lang]);
loadJSON(translations[lang], function(translations) {
loadJSON(translations[lang], function (translations) {
self.coreTranslations = translations;
});
} else {
@@ -209,17 +214,21 @@ var Translator = (function() {
* Load the core translations fallback.
* The first language defined in translations.js will be used.
*/
loadCoreTranslationsFallback: function() {
loadCoreTranslationsFallback: function () {
var self = this;
// The variable `first` will contain the first
// defined translation after the following line.
for (var first in translations) {break;}
for (var first in translations) {
break;
}
Log.log("Loading core translation fallback file: " + translations[first]);
loadJSON(translations[first], function(translations) {
self.coreTranslationsFallback = translations;
});
},
if (first) {
Log.log("Loading core translation fallback file: " + translations[first]);
loadJSON(translations[first], function (translations) {
self.coreTranslationsFallback = translations;
});
}
}
};
})();

View File

@@ -1,11 +1,9 @@
/* exported Utils */
/* Magic Mirror
* Utils
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.
*/
var colors = require("colors/safe");
var Utils = {
@@ -16,4 +14,6 @@ var Utils = {
}
};
if (typeof module !== "undefined") {module.exports = Utils;}
if (typeof module !== "undefined") {
module.exports = Utils;
}

View File

@@ -6,8 +6,5 @@
"module": "commonjs",
"allowSyntheticDefaultImports": true
},
"exclude": [
"modules",
"node_modules"
]
"exclude": ["modules", "node_modules"]
}

31
module-types.ts Normal file
View File

@@ -0,0 +1,31 @@
type ModuleProperties = {
defaults?: object,
start?(): void,
getHeader?(): string,
getTemplate?(): string,
getTemplateData?(): object,
notificationReceived?(notification: string, payload: any, sender: object): void,
socketNotificationReceived?(notification: string, payload: any): void,
suspend?(): void,
resume?(): void,
getDom?(): HTMLElement,
getStyles?(): string[],
[key: string]: any,
};
export declare const Module: {
register(moduleName: string, moduleProperties: ModuleProperties): void;
};
export declare const Log: {
info(message?: any, ...optionalParams: any[]): void,
log(message?: any, ...optionalParams: any[]): void,
error(message?: any, ...optionalParams: any[]): void,
warn(message?: any, ...optionalParams: any[]): void,
group(groupTitle?: string, ...optionalParams: any[]): void,
groupCollapsed(groupTitle?: string, ...optionalParams: any[]): void,
groupEnd(): void,
time(timerName?: string): void,
timeEnd(timerName?: string): void,
timeStamp(timerName?: string): void,
};

View File

@@ -1,698 +0,0 @@
# MagicMirror² Module Development Documentation
This document describes the way to develop your own MagicMirror² modules.
## Module structure
All modules are loaded in the `modules` folder. The default modules are grouped together in the `modules/default` folder. Your module should be placed in a subfolder of `modules`. Note that any file or folder your create in the `modules` folder will be ignored by git, allowing you to upgrade the MagicMirror² without the loss of your files.
A module can be placed in one single folder. Or multiple modules can be grouped in a subfolder. Note that name of the module must be unique. Even when a module with a similar name is placed in a different folder, they can't be loaded at the same time.
### Files
- **modulename/modulename.js** - This is your core module script.
- **modulename/node_helper.js** - This is an optional helper that will be loaded by the node script. The node helper and module script can communicate with each other using an intergrated socket system.
- **modulename/public** - Any files in this folder can be accesed via the browser on `/modulename/filename.ext`.
- **modulename/anyfileorfolder** Any other file or folder in the module folder can be used by the core module script. For example: *modulename/css/modulename.css* would be a good path for your additional module styles.
## Core module file: modulename.js
This is the script in which the module will be defined. This script is required in order for the module to be used. In it's most simple form, the core module file must contain:
````javascript
Module.register("modulename",{});
````
Of course, the above module would not do anything fancy, so it's good to look at one of the simplest modules: **helloworld**:
````javascript
//helloworld.js:
Module.register("helloworld",{
// Default module config.
defaults: {
text: "Hello World!"
},
// Override dom generator.
getDom: function() {
var wrapper = document.createElement("div");
wrapper.innerHTML = this.config.text;
return wrapper;
}
});
````
As you can see, the `Module.register()` method takes two arguments: the name of the module and an object with the module properties.
### Available module instance properties
After the module is initialized, the module instance has a few available module properties:
#### `this.name`
**String**
The name of the module.
#### `this.identifier`
**String**
This is a unique identifier for the module instance.
#### `this.hidden`
**Boolean**
This represents if the module is currently hidden (faded away).
#### `this.config`
**Boolean**
The configuration of the module instance as set in the user's config.js file. This config will also contain the module's defaults if these properties are not over written by the user config.
#### `this.data`
**Object**
The data object contains additional metadata about the module instance:
- `data.classes` - The classes which are added to the module dom wrapper.
- `data.file` - The filename of the core module file.
- `data.path` - The path of the module folder.
- `data.header` - The header added to the module.
- `data.position` - The position in which the instance will be shown.
#### `defaults: {}`
Any properties defined in the defaults object, will be merged with the module config as defined in the user's config.js file. This is the best place to set your modules's configuration defaults. Any of the module configuration properties can be accessed using `this.config.propertyName`, but more about that later.
#### `requiresVersion:`
*Introduced in version: 2.1.0.*
A string that defines the minimum version of the MagicMirror framework. If it is set, the system compares the required version with the users version. If the version of the user is out of date, it won't run the module. Make sure to also set this value in the Node helper.
**Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module.
Example:
````javascript
requiresVersion: "2.1.0",
````
### Subclassable module methods
#### `init()`
This method is called when a module gets instantiated. In most cases you do not need to subclass this method.
#### `loaded(callback)`
*Introduced in version: 2.1.1.*
This method is called when a module is loaded. Subsequent modules in the config are not yet loaded. The `callback` function MUST be called when the module is done loading. In most cases you do not need to subclass this method.
**Example:**
````javascript
loaded: function(callback) {
this.finishLoading();
Log.log(this.name + ' is loaded!');
callback();
}
````
#### `start()`
This method is called when all modules are loaded an the system is ready to boot up. Keep in mind that the dom object for the module is not yet created. The start method is a perfect place to define any additional module properties:
**Example:**
````javascript
start: function() {
this.mySpecialProperty = "So much wow!";
Log.log(this.name + ' is started!');
}
````
#### `getScripts()`
**Should return: Array**
The getScripts method is called to request any additional scripts that need to be loaded. This method should therefore return an array with strings. If you want to return a full path to a file in the module folder, use the `this.file('filename.js')` method. In all cases the loader will only load a file once. It even checks if the file is available in the default vendor folder.
**Example:**
````javascript
getScripts: function() {
return [
'script.js', // will try to load it from the vendor folder, otherwise it will load is from the module folder.
'moment.js', // this file is available in the vendor folder, so it doesn't need to be available in the module folder.
this.file('anotherfile.js'), // this file will be loaded straight from the module folder.
'https://code.jquery.com/jquery-2.2.3.min.js', // this file will be loaded from the jquery servers.
]
}
````
**Note:** If a file can not be loaded, the boot up of the mirror will stall. Therefore it's advised not to use any external urls.
#### `getStyles()`
**Should return: Array**
The getStyles method is called to request any additional stylesheets that need to be loaded. This method should therefore return an array with strings. If you want to return a full path to a file in the module folder, use the `this.file('filename.css')` method. In all cases the loader will only load a file once. It even checks if the file is available in the default vendor folder.
**Example:**
````javascript
getStyles: function() {
return [
'script.css', // will try to load it from the vendor folder, otherwise it will load is from the module folder.
'font-awesome.css', // this file is available in the vendor folder, so it doesn't need to be avialable in the module folder.
this.file('anotherfile.css'), // this file will be loaded straight from the module folder.
'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css', // this file will be loaded from the bootstrapcdn servers.
]
}
````
**Note:** If a file can not be loaded, the boot up of the mirror will stall. Therefore it's advised not to use any external urls.
#### `getTranslations()`
**Should return: Dictionary**
The getTranslations method is called to request translation files that need to be loaded. This method should therefore return a dictionary with the files to load, identified by the country's short name.
If the module does not have any module specific translations, the function can just be omitted or return `false`.
**Example:**
````javascript
getTranslations: function() {
return {
en: "translations/en.json",
de: "translations/de.json"
}
}
````
#### `getDom()`
**Should return:** Dom Object
Whenever the MagicMirror needs to update the information on screen (because it starts, or because your module asked a refresh using `this.updateDom()`), the system calls the getDom method. This method should therefore return a dom object.
**Example:**
````javascript
getDom: function() {
var wrapper = document.createElement("div");
wrapper.innerHTML = 'Hello world!';
return wrapper;
}
````
#### `getHeader()`
**Should return:** String
Whenever the MagicMirror needs to update the information on screen (because it starts, or because your module asked a refresh using `this.updateDom()`), the system calls the getHeader method to retrieve the module's header. This method should therefor return a string. If this method is not subclassed, this function will return the user's configured header.
If you want to use the original user's configured header, reference `this.data.header`.
**NOTE:** If the user did not configure a default header, no header will be displayed and thus this method will not be called.
**Example:**
````javascript
getHeader: function() {
return this.data.header + ' Foo Bar';
}
````
#### `notificationReceived(notification, payload, sender)`
That MagicMirror core has the ability to send notifications to modules. Or even better: the modules have the possibility to send notifications to other modules. When this module is called, it has 3 arguments:
- `notification` - String - The notification identifier.
- `payload` - AnyType - The payload of a notification.
- `sender` - Module - The sender of the notification. If this argument is `undefined`, the sender of the notififiction is the core system.
**Example:**
````javascript
notificationReceived: function(notification, payload, sender) {
if (sender) {
Log.log(this.name + " received a module notification: " + notification + " from sender: " + sender.name);
} else {
Log.log(this.name + " received a system notification: " + notification);
}
}
````
**Note:** the system sends two notifications when starting up. These notifications could come in handy!
- `ALL_MODULES_STARTED` - All modules are started. You can now send notifications to other modules.
- `DOM_OBJECTS_CREATED` - All dom objects are created. The system is now ready to perform visual changes.
#### `socketNotificationReceived: function(notification, payload)`
When using a node_helper, the node helper can send your module notifications. When this module is called, it has 2 arguments:
- `notification` - String - The notification identifier.
- `payload` - AnyType - The payload of a notification.
**Note 1:** When a node helper sends a notification, all modules of that module type receive the same notifications. <br>
**Note 2:** The socket connection is established as soon as the module sends its first message using [sendSocketNotification](thissendsocketnotificationnotification-payload).
**Example:**
````javascript
socketNotificationReceived: function(notification, payload) {
Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
},
````
#### `suspend()`
When a module is hidden (using the `module.hide()` method), the `suspend()` method will be called. By subclassing this method you can perform tasks like halting the update timers.
#### `resume()`
When a module is requested to be shown (using the `module.show()` method), the `resume()` method will be called. By subclassing this method you can perform tasks restarting the update timers.
### Module instance methods
Each module instance has some handy methods which can be helpful building your module.
#### `this.file(filename)`
***filename* String** - The name of the file you want to create the path for.<br>
**Returns String**
If you want to create a path to a file in your module folder, use the `file()` method. It returns the path to the filename given as the attribute. Is method comes in handy when configuring the [getScripts](#getscripts) and [getStyles](#getstyles) methods.
#### `this.updateDom(speed)`
***speed* Number** - Optional. Animation speed in milliseconds.<br>
Whenever your module need to be updated, call the `updateDom(speed)` method. It requests the MagicMirror core to update its dom object. If you define the speed, the content update will be animated, but only if the content will really change.
As an example: the clock modules calls this method every second:
````javascript
...
start: function() {
var self = this;
setInterval(function() {
self.updateDom(); // no speed defined, so it updates instantly.
}, 1000); //perform every 1000 milliseconds.
},
...
````
#### `this.sendNotification(notification, payload)`
***notification* String** - The notification identifier.<br>
***payload* AnyType** - Optional. A notification payload.<br>
If you want to send a notification to all other modules, use the `sendNotification(notification, payload)`. All other modules will receive the message via the [notificationReceived](#notificationreceivednotification-payload-sender) method. In that case, the sender is automatically set to the instance calling the sendNotification method.
**Example:**
````javascript
this.sendNotification('MYMODULE_READY_FOR_ACTION', {foo:bar});
````
#### `this.sendSocketNotification(notification, payload)`
***notification* String** - The notification identifier.<br>
***payload* AnyType** - Optional. A notification payload.<br>
If you want to send a notification to the node_helper, use the `sendSocketNotification(notification, payload)`. Only the node_helper of this module will receive the socket notification.
**Example:**
````javascript
this.sendSocketNotification('SET_CONFIG', this.config);
````
#### `this.hide(speed, callback, options)`
***speed* Number** - Optional (Required when setting callback or options), The speed of the hide animation in milliseconds.
***callback* Function** - Optional, The callback after the hide animation is finished.
***options* Function** - Optional, Object with additional options for the hide action (see below). (*Introduced in version: 2.1.0.*)
To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itself using `this.hide()`, but of course you can also hide another module using `anOtherModule.hide()`.
Possible configurable options:
- `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. It's considered best practice to use your modules identifier as the locksString: `this.identifier`. See *visibility locking* below.
**Note 1:** If the hide animation is canceled, for instance because the show method is called before the hide animation was finished, the callback will not be called.<br>
**Note 2:** If the hide animation is hijacked (an other method calls hide on the same module), the callback will not be called.<br>
**Note 3:** If the dom is not yet created, the hide method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender).
#### `this.show(speed, callback, options)`
***speed* Number** - Optional (Required when setting callback or options), The speed of the show animation in milliseconds.
***callback* Function** - Optional, The callback after the show animation is finished.
***options* Function** - Optional, Object with additional options for the show action (see below). (*Introduced in version: 2.1.0.*)
To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itself using `this.show()`, but of course you can also show another module using `anOtherModule.show()`.
Possible configurable options:
- `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. See *visibility locking* below.
- `force` - Boolean - When setting the force tag to `true`, the locking mechanism will be overwritten. Use this option with caution. It's considered best practice to let the usage of the force option be use- configurable. See *visibility locking* below.
**Note 1:** If the show animation is canceled, for instance because the hide method is called before the show animation was finished, the callback will not be called.<br>
**Note 2:** If the show animation is hijacked (an other method calls show on the same module), the callback will not be called.<br>
**Note 3:** If the dom is not yet created, the show method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender).
#### Visibility locking
(*Introduced in version: 2.1.0.*)
Visiblity locking helps the module system to prevent unwanted hide/show actions. The following scenario explains the concept:
**Module B asks module A to hide:**
````javascript
moduleA.hide(0, {lockString: "module_b_identifier"});
````
Module A is now hidden, and has an lock array with the following strings:
````javascript
moduleA.lockStrings == ["module_b_identifier"]
moduleA.hidden == true
````
**Module C asks module A to hide:**
````javascript
moduleA.hide(0, {lockString: "module_c_identifier"});
````
Module A is now hidden, and has an lock array with the following strings:
````javascript
moduleA.lockStrings == ["module_b_identifier", "module_c_identifier"]
moduleA.hidden == true
````
**Module B asks module A to show:**
````javascript
moduleA.show(0, {lockString: "module_b_identifier"});
````
The lockString will be removed from moduleAs locks array, but since there still is an other lock string available, the module remains hidden:
````javascript
moduleA.lockStrings == ["module_c_identifier"]
moduleA.hidden == true
````
**Module C asks module A to show:**
````javascript
moduleA.show(0, {lockString: "module_c_identifier"});
````
The lockString will be removed from moduleAs locks array, and since this will result in an empty lock array, the module will be visible:
````javascript
moduleA.lockStrings == []
moduleA.hidden == false
````
**Note:** The locking mechanism can be overwritten by using the force tag:
````javascript
moduleA.show(0, {force: true});
````
This will reset the lockstring array, and will show the module.
````javascript
moduleA.lockStrings == []
moduleA.hidden == false
````
Use this `force` method with caution. See `show()` method for more information.
#### `this.translate(identifier)`
***identifier* String** - Identifier of the string that should be translated.
The Magic Mirror contains a convenience wrapper for `l18n`. You can use this to automatically serve different translations for your modules based on the user's `language` configuration.
If no translation is found, a fallback will be used. The fallback sequence is as follows:
- 1. Translation as defined in module translation file of the user's preferred language.
- 2. Translation as defined in core translation file of the user's preferred language.
- 3. Translation as defined in module translation file of the fallback language (the first defined module translation file).
- 4. Translation as defined in core translation file of the fallback language (the first defined core translation file).
- 5. The key (identifier) of the translation.
When adding translations to your module, it's a good idea to see if an apropriate translation is already available in the [core translation files](https://github.com/MichMich/MagicMirror/tree/master/translations). This way, your module can benefit from the existing translations.
**Example:**
````javascript
this.translate("INFO") //Will return a translated string for the identifier INFO
````
**Example json file:**
````javascript
{
"INFO": "Really important information!"
}
````
**Note:** although comments are officially not supported in JSON files, MagicMirror allows it by stripping the comments before parsing the JSON file. Comments in translation files could help other translators.
##### `this.translate(identifier, variables)`
***identifier* String** - Identifier of the string that should be translated.
***variables* Object** - Object of variables to be used in translation.
This improved and backwards compatible way to handle translations behaves like the normal translation function and follows the rules described above. It's recommended to use this new format for translating everywhere. It allows translator to change the word order in the sentence to be translated.
**Example:**
````javascript
var timeUntilEnd = moment(event.endDate, "x").fromNow(true);
this.translate("RUNNING", { "timeUntilEnd": timeUntilEnd) }); // Will return a translated string for the identifier RUNNING, replacing `{timeUntilEnd}` with the contents of the variable `timeUntilEnd` in the order that translator intended.
````
**Example English .json file:**
````javascript
{
"RUNNING": "Ends in {timeUntilEnd}",
}
````
**Example Finnish .json file:**
````javascript
{
"RUNNING": "Päättyy {timeUntilEnd} päästä",
}
````
**Note:** The *variables* Object has an special case called `fallback`. It's used to support old translations in translation files that do not have the variables in them. If you are upgrading an old module that had translations that did not support the word order, it is recommended to have the fallback layout.
**Example:**
````javascript
var timeUntilEnd = moment(event.endDate, "x").fromNow(true);
this.translate("RUNNING", {
"fallback": this.translate("RUNNING") + " {timeUntilEnd}"
"timeUntilEnd": timeUntilEnd
)}); // Will return a translated string for the identifier RUNNING, replacing `{timeUntilEnd}` with the contents of the variable `timeUntilEnd` in the order that translator intended. (has a fallback)
````
**Example swedish .json file that does not have the variable in it:**
````javascript
{
"RUNNING": "Slutar",
}
````
In this case the `translate`-function will not find any variables in the translation, will look for `fallback` variable and use that if possible to create the translation.
## The Node Helper: node_helper.js
The node helper is a Node.js script that is able to do some backend task to support your module. For every module type, only one node helper instance will be created. For example: if your MagicMirror uses two calendar modules, there will be only one calendar node helper instantiated.
**Note:** Because there is only one node helper per module type, there is no default config available within your module. It's your task to send the desired config from your module to your node helper.
In it's most simple form, the node_helper.js file must contain:
````javascript
var NodeHelper = require("node_helper");
module.exports = NodeHelper.create({});
````
Of course, the above helper would not do anything useful. So with the information above, you should be able to make it a bit more sophisticated.
### Available module instance properties
#### `this.name`
**String**
The name of the module
#### `this.path`
**String**
The path of the module
#### `this.expressApp`
**Express App Instance**
This is a link to the express instance. It will allow you to define extra routes.
**Example:**
````javascript
start: function() {
this.expressApp.get('/foobar', function (req, res) {
res.send('GET request to /foobar');
});
}
````
**Note:** By default, a public path to your module's public folder will be created:
````javascript
this.expressApp.use("/" + this.name, express.static(this.path + "/public"));
````
#### `this.io`
**Socket IO Instance**
This is a link to the IO instance. It will allow you to do some Socket.IO magic. In most cases you won't need this, since the Node Helper has a few convenience methods to make this simple.
#### `requiresVersion:`
*Introduced in version: 2.1.0.*
A string that defines the minimum version of the MagicMirror framework. If it is set, the system compares the required version with the users version. If the version of the user is out of date, it won't run the module.
**Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module.
Example:
````javascript
requiresVersion: "2.1.0",
````
### Subclassable module methods
#### `init()`
This method is called when a node helper gets instantiated. In most cases you do not need to subclass this method.
#### `start()`
This method is called when all node helpers are loaded and the system is ready to boot up. The start method is a perfect place to define any additional module properties:
**Example:**
````javascript
start: function() {
this.mySpecialProperty = "So much wow!";
Log.log(this.name + ' is started!');
}
````
#### `stop()`
This method is called when the MagicMirror server receives a `SIGINT` command and is shutting down. This method should include any commands needed to close any open connections, stop any sub-processes and gracefully exit the module.
**Example:**
````javascript
stop: function() {
console.log("Shutting down MyModule");
this.connection.close();
}
````
#### `socketNotificationReceived: function(notification, payload)`
With this method, your node helper can receive notifications from your modules. When this method is called, it has 2 arguments:
- `notification` - String - The notification identifier.
- `payload` - AnyType - The payload of a notification.
**Note:** The socket connection is established as soon as the module sends its first message using [sendSocketNotification](thissendsocketnotificationnotification-payload).
**Example:**
````javascript
socketNotificationReceived: function(notification, payload) {
Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
},
````
### Module instance methods
Each node helper has some handy methods which can be helpful building your module.
#### `this.sendSocketNotification(notification, payload)`
***notification* String** - The notification identifier.<br>
***payload* AnyType** - Optional. A notification payload.<br>
If you want to send a notification to all your modules, use the `sendSocketNotification(notification, payload)`. Only the module of your module type will receive the socket notification.
**Note:** Since all instances of your module will receive the notifications, it's your task to make sure the right module responds to your messages.
**Example:**
````javascript
this.sendSocketNotification('SET_CONFIG', this.config);
````
## MagicMirror Helper Methods
The core Magic Mirror object: `MM` has some handy method that will help you in controlling your and other modules. Most of the `MM` methods are available via convenience methods on the Module instance.
### Module selection
The only additional method available for your module, is the feature to retrieve references to other modules. This can be used to hide and show other modules.
#### `MM.getModules()`
**Returns Array** - An array with module instances.<br>
To make a selection of all currently loaded module instances, run the `MM.getModules()` method. It will return an array with all currently loaded module instances. The returned array has a lot of filtering methods. See below for more info.
**Note:** This method returns an empty array if not all modules are started yet. Wait for the `ALL_MODULES_STARTED` [notification](#notificationreceivednotification-payload-sender).
##### `.withClass(classnames)`
***classnames* String or Array** - The class names on which you want to filter.
**Returns Array** - An array with module instances.<br>
If you want to make a selection based on one or more class names, use the withClass method on a result of the `MM.getModules()` method. The argument of the `withClass(classname)` method can be an array, or space separated string.
**Examples:**
````javascript
var modules = MM.getModules().withClass('classname');
var modules = MM.getModules().withClass('classname1 classname2');
var modules = MM.getModules().withClass(['classname1','classname2']);
````
##### `.exceptWithClass(classnames)`
***classnames* String or Array** - The class names of the modules you want to remove from the results.
**Returns Array** - An array with module instances.<br>
If you to remove some modules from a selection based on a classname, use the exceptWithClass method on a result of the `MM.getModules()` method. The argument of the `exceptWithClass(classname)` method can be an array, or space separated string.
**Examples:**
````javascript
var modules = MM.getModules().exceptWithClass('classname');
var modules = MM.getModules().exceptWithClass('classname1 classname2');
var modules = MM.getModules().exceptWithClass(['classname1','classname2']);
````
##### `.exceptModule(module)`
***module* Module Object** - The reference to a module you want to remove from the results.
**Returns Array** - An array with module instances.<br>
If you to remove a specific module instance from a selection based on a classname, use the exceptWithClass method on a result of the `MM.getModules()` method. This can be helpful if you want to select all module instances except the instance of your module.
**Examples:**
````javascript
var modules = MM.getModules().exceptModule(this);
````
Of course, you can combine all of the above filters:
**Example:**
````javascript
var modules = MM.getModules().withClass('classname1').exceptwithClass('classname2').exceptModule(aModule);
````
##### `.enumerate(callback)`
***callback* Function(module)** - The callback run on every instance.
If you want to perform an action on all selected modules, you can use the `enumerate` function:
````javascript
MM.getModules().enumerate(function(module) {
Log.log(module.name);
});
````
**Example:**
To hide all modules except the your module instance, you could write something like:
````javascript
Module.register("modulename",{
//...
notificationReceived: function(notification, payload, sender) {
if (notification === 'DOM_OBJECTS_CREATED') {
MM.getModules().exceptModule(this).enumerate(function(module) {
module.hide(1000, function() {
//Module hidden.
});
});
}
},
//...
});
````
## MagicMirror Logger
The Magic Mirror contains a convenience wrapper for logging. Currently, this logger is a simple proxy to the original `console.log` methods. But it might get additional features in the future. The Loggers is currently only available in the core module file (not in the node_helper).
**Examples:**
````javascript
Log.info('error');
Log.log('log');
Log.error('info');
````

View File

@@ -1,64 +1,5 @@
# Module: Alert
The alert module is one of the default modules of the MagicMirror. This module displays notifications from other modules.
## Usage
To use this module, add it to the modules array in the config/config.js file:
```
modules: [
{
module: "alert",
config: {
// The config property is optional.
// See 'Configuration options' for more information.
}
}
]
```
## Configuration options
The following properties can be configured:
| Option | Description
| ----------------- | -----------
| `effect` | The animation effect to use for notifications. <br><br> **Possible values:** `scale` `slide` `genie` `jelly` `flip` `exploader` `bouncyflip` <br> **Default value:** `slide`
| `alert_effect` | The animation effect to use for alerts. <br><br> **Possible values:** `scale` `slide` `genie` `jelly` `flip` `exploader` `bouncyflip` <br> **Default value:** `jelly`
| `display_time` | Time a notification is displayed in milliseconds. <br><br> **Possible values:** `int` <br> **Default value:** `3500`
| `position` | Position where the notifications should be displayed. <br><br> **Possible values:** `left` `center` `right` <br> **Default value:** `center`
| `welcome_message` | Message shown at startup. <br><br> **Possible values:** `string` `false` <br> **Default value:** `false` (no message at startup)
## Developer notes
For notifications use:
```
self.sendNotification("SHOW_ALERT", {type: "notification"});
```
For alerts use:
```
self.sendNotification("SHOW_ALERT", {});
```
### Notification params
| Option | Description
| --------- | -----------
| `title` | The title of the notification. <br><br> **Possible values:** `text` or `html`
| `message` | The message of the notification. <br><br> **Possible values:** `text` or `html`
### Alert params
| Option | Description
| ----------------------------------------------- | -----------
| `title` | The title of the alert. <br><br> **Possible values:** `text` or `html`
| `message` | The message of the alert. <br><br> **Possible values:** `text` or `html`
| `imageUrl` (optional) | Image to show in the alert <br><br> **Possible values:** `url` `path` <br> **Default value:** `none`
| `imageFA` (optional) | Font Awesome icon to show in the alert <br><br> **Possible values:** See [Font Awsome](http://fontawesome.io/icons/) website. <br> **Default value:** `none`
| `imageHeight` (optional even with imageUrl set) | Height of the image <br><br> **Possible values:** `intpx` <br> **Default value:** `80px`
| `timer` (optional) | How long the alert should stay visible in ms. <br> **Important:** If you do not use the `timer`, it is your duty to hide the alert by using `self.sendNotification("HIDE_ALERT");`! <br><br>**Possible values:** `int` `float` <br> **Default value:** `none`
## Open Source Licenses
###[NotificationStyles](https://github.com/codrops/NotificationStyles)
See [ympanus.net](http://tympanus.net/codrops/licensing/) for license.
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/alert.html).

View File

@@ -1,13 +1,12 @@
/* global Module */
/* global NotificationFx */
/* Magic Mirror
* Module: alert
*
* By Paul-Vincent Roll http://paulvincentroll.com
* By Paul-Vincent Roll https://paulvincentroll.com/
* MIT Licensed.
*/
Module.register("alert",{
Module.register("alert", {
defaults: {
// scale|slide|genie|jelly|flip|bouncyflip|exploader
effect: "slide",
@@ -18,59 +17,64 @@ Module.register("alert",{
//Position
position: "center",
//shown at startup
welcome_message: false,
welcome_message: false
},
getScripts: function() {
return ["classie.js", "modernizr.custom.js", "notificationFx.js"];
getScripts: function () {
return ["notificationFx.js"];
},
getStyles: function() {
return ["ns-default.css"];
getStyles: function () {
return ["notificationFx.css", "font-awesome.css"];
},
// Define required translations.
getTranslations: function() {
getTranslations: function () {
return {
en: "translations/en.json",
de: "translations/de.json",
nl: "translations/nl.json",
nl: "translations/nl.json"
};
},
show_notification: function(message) {
if (this.config.effect == "slide") {this.config.effect = this.config.effect + "-" + this.config.position;}
msg = "";
if (message.title) {
msg += "<span class='thin' style='line-height: 35px; font-size:24px' color='#4A4A4A'>" + message.title + "</span>";
show_notification: function (message) {
if (this.config.effect === "slide") {
this.config.effect = this.config.effect + "-" + this.config.position;
}
if (message.message){
if (msg != ""){
msg+= "<br />";
let msg = "";
if (message.title) {
msg += "<span class='thin dimmed medium'>" + message.title + "</span>";
}
if (message.message) {
if (msg !== "") {
msg += "<br />";
}
msg += "<span class='light' style='font-size:28px;line-height: 30px;'>" + message.message + "</span>";
msg += "<span class='light bright small'>" + message.message + "</span>";
}
new NotificationFx({
message: msg,
layout: "growl",
effect: this.config.effect,
ttl: this.config.display_time
ttl: message.timer !== undefined ? message.timer : this.config.display_time
}).show();
},
show_alert: function(params, sender) {
var self = this;
show_alert: function (params, sender) {
let image = "";
//Set standard params if not provided by module
if (typeof params.timer === "undefined") { params.timer = null; }
if (typeof params.imageHeight === "undefined") { params.imageHeight = "80px"; }
if (typeof params.timer === "undefined") {
params.timer = null;
}
if (typeof params.imageHeight === "undefined") {
params.imageHeight = "80px";
}
if (typeof params.imageUrl === "undefined" && typeof params.imageFA === "undefined") {
params.imageUrl = null;
image = "";
} else if (typeof params.imageFA === "undefined"){
image = "<img src='" + (params.imageUrl).toString() + "' height=" + (params.imageHeight).toString() + " style='margin-bottom: 10px;'/><br />";
} else if (typeof params.imageUrl === "undefined"){
image = "<span class='" + "fa fa-" + params.imageFA + "' style='margin-bottom: 10px;color: #fff;font-size:" + (params.imageHeight).toString() + ";'/></span><br />";
} else if (typeof params.imageFA === "undefined") {
image = "<img src='" + params.imageUrl.toString() + "' height='" + params.imageHeight.toString() + "' style='margin-bottom: 10px;'/><br />";
} 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 />";
}
//Create overlay
var overlay = document.createElement("div");
const overlay = document.createElement("div");
overlay.id = "overlay";
overlay.innerHTML += "<div class=\"black_overlay\"></div>";
overlay.innerHTML += '<div class="black_overlay"></div>';
document.body.insertBefore(overlay, document.body.firstChild);
//If module already has an open alert close it
@@ -79,16 +83,16 @@ Module.register("alert",{
}
//Display title and message only if they are provided in notification parameters
message ="";
let message = "";
if (params.title) {
message += "<span class='light' style='line-height: 35px; font-size:30px' color='#4A4A4A'>" + params.title + "</span>"
message += "<span class='light dimmed medium'>" + params.title + "</span>";
}
if (params.message) {
if (message != ""){
if (message !== "") {
message += "<br />";
}
message += "<span class='thin' style='font-size:22px;line-height: 30px;'>" + params.message + "</span>";
message += "<span class='thin bright small'>" + params.message + "</span>";
}
//Store alert in this.alerts
@@ -102,53 +106,59 @@ Module.register("alert",{
this.alerts[sender.name].show();
//Add timer to dismiss alert and overlay
if (params.timer) {
setTimeout(function() {
self.hide_alert(sender);
setTimeout(() => {
this.hide_alert(sender);
}, params.timer);
}
},
hide_alert: function(sender) {
hide_alert: function (sender) {
//Dismiss alert and remove from this.alerts
this.alerts[sender.name].dismiss();
this.alerts[sender.name] = null;
//Remove overlay
var overlay = document.getElementById("overlay");
overlay.parentNode.removeChild(overlay);
if (this.alerts[sender.name]) {
this.alerts[sender.name].dismiss();
this.alerts[sender.name] = null;
//Remove overlay
const overlay = document.getElementById("overlay");
overlay.parentNode.removeChild(overlay);
}
},
setPosition: function(pos) {
setPosition: function (pos) {
//Add css to body depending on the set position for notifications
var sheet = document.createElement("style");
if (pos == "center") {sheet.innerHTML = ".ns-box {margin-left: auto; margin-right: auto;text-align: center;}";}
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;}";}
const sheet = document.createElement("style");
if (pos === "center") {
sheet.innerHTML = ".ns-box {margin-left: auto; margin-right: auto;text-align: center;}";
}
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);
},
notificationReceived: function(notification, payload, sender) {
notificationReceived: function (notification, payload, sender) {
if (notification === "SHOW_ALERT") {
if (typeof payload.type === "undefined") { payload.type = "alert"; }
if (payload.type == "alert") {
if (typeof payload.type === "undefined") {
payload.type = "alert";
}
if (payload.type === "alert") {
this.show_alert(payload, sender);
} else if (payload.type = "notification") {
} else if (payload.type === "notification") {
this.show_notification(payload);
}
} else if (notification === "HIDE_ALERT") {
this.hide_alert(sender);
}
},
start: function() {
start: function () {
this.alerts = {};
this.setPosition(this.config.position);
if (this.config.welcome_message) {
if (this.config.welcome_message == true){
this.show_notification({title: this.translate("sysTitle"), message: this.translate("welcome")});
}
else{
this.show_notification({title: this.translate("sysTitle"), message: this.config.welcome_message});
if (this.config.welcome_message === true) {
this.show_notification({ title: this.translate("sysTitle"), message: this.translate("welcome") });
} else {
this.show_notification({ title: this.translate("sysTitle"), message: this.config.welcome_message });
}
}
Log.info("Starting module: " + this.name);
}
});

View File

@@ -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);

File diff suppressed because one or more lines are too long

View 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);
}
}

View File

@@ -1,34 +1,21 @@
/**
* Based on work by
*
* notificationFx.js v1.0.0
* http://www.codrops.com
* https://tympanus.net/codrops/
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* https://opensource.org/licenses/mit-license.php
*
* Copyright 2014, Codrops
* http://www.codrops.com
* https://tympanus.net/codrops/
*/
// jscs:disable
;(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") ];
(function (window) {
/**
* extend obj function
*/
function extend(a, b) {
for (var key in b) {
for (let key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
@@ -70,19 +57,23 @@
ttl: 6000,
al_no: "ns-box",
// callbacks
onClose: function() { return false; },
onOpen: function() { return false; }
onClose: function () {
return false;
},
onOpen: function () {
return false;
}
};
/**
* init function
* initialize and cache some vars
*/
NotificationFx.prototype._init = function() {
NotificationFx.prototype._init = function () {
// create HTML structure
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;
var strinner = "<div class=\"ns-box-inner\">";
this.ntf.className = this.options.al_no + " ns-" + this.options.layout + " ns-effect-" + this.options.effect + " ns-type-" + this.options.type;
let strinner = '<div class="ns-box-inner">';
strinner += this.options.message;
strinner += "</div>";
this.ntf.innerHTML = strinner;
@@ -91,13 +82,12 @@
this.options.wrapper.insertBefore(this.ntf, this.options.wrapper.nextSibling);
// dismiss after [options.ttl]ms
var self = this;
if (this.options.ttl) {
this.dismissttl = setTimeout(function() {
if (self.active) {
self.dismiss();
}
}, this.options.ttl);
this.dismissttl = setTimeout(() => {
if (this.active) {
this.dismiss();
}
}, this.options.ttl);
}
// init events
@@ -107,59 +97,54 @@
/**
* init events
*/
NotificationFx.prototype._initEvents = function() {
var self = this;
NotificationFx.prototype._initEvents = function () {
// 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
*/
NotificationFx.prototype.show = function() {
NotificationFx.prototype.show = function () {
this.active = true;
classie.remove(this.ntf, "ns-hide");
classie.add(this.ntf, "ns-show");
this.ntf.classList.remove("ns-hide");
this.ntf.classList.add("ns-show");
this.options.onOpen();
};
/**
* dismiss the notification
*/
NotificationFx.prototype.dismiss = function() {
var self = this;
NotificationFx.prototype.dismiss = function () {
this.active = false;
clearTimeout(this.dismissttl);
classie.remove(this.ntf, "ns-show");
setTimeout(function() {
classie.add(self.ntf, "ns-hide");
this.ntf.classList.remove("ns-show");
setTimeout(() => {
this.ntf.classList.add("ns-hide");
// callback
self.options.onClose();
this.options.onClose();
}, 25);
// after animation ends remove ntf from the DOM
var onEndAnimationFn = function(ev) {
if (support.animations) {
if (ev.target !== self.ntf) return false;
this.removeEventListener(animEndEventName, onEndAnimationFn);
const onEndAnimationFn = (ev) => {
if (ev.target !== this.ntf) {
return false;
}
this.ntf.removeEventListener("animationend", onEndAnimationFn);
if (this.parentNode === self.options.wrapper) {
self.options.wrapper.removeChild(this);
if (ev.target.parentNode === this.options.wrapper) {
this.options.wrapper.removeChild(this.ntf);
}
};
if (support.animations) {
this.ntf.addEventListener(animEndEventName, onEndAnimationFn);
} else {
onEndAnimationFn();
}
this.ntf.addEventListener("animationend", onEndAnimationFn);
};
/**
* add to global namespace
*/
window.NotificationFx = NotificationFx;
})(window);

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror нотификация",
"welcome": "Добре дошли, стартирането беше успешно"
"sysTitle": "MagicMirror нотификация",
"welcome": "Добре дошли, стартирането беше успешно"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notifikation",
"welcome": "Velkommen, modulet er succesfuldt startet!"
"sysTitle": "MagicMirror Notifikation",
"welcome": "Velkommen, modulet er succesfuldt startet!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Benachrichtigung",
"welcome": "Willkommen, Start war erfolgreich!"
"sysTitle": "MagicMirror Benachrichtigung",
"welcome": "Willkommen, Start war erfolgreich!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notification",
"welcome": "Welcome, start was successful!"
"sysTitle": "MagicMirror Notification",
"welcome": "Welcome, start was successful!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notificaciones",
"welcome": "Bienvenido, ¡se iniciado correctamente!"
"sysTitle": "MagicMirror Notificaciones",
"welcome": "Bienvenido, ¡se iniciado correctamente!"
}

View File

@@ -0,0 +1,4 @@
{
"sysTitle": "MagicMirror Notification",
"welcome": "Bienvenue, le démarrage a été un succès!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror értesítés",
"welcome": "Üdvözöljük, indulás sikeres!"
"sysTitle": "MagicMirror értesítés",
"welcome": "Üdvözöljük, indulás sikeres!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Notificatie",
"welcome": "Welkom, Succesvol gestart!"
"sysTitle": "MagicMirror Notificatie",
"welcome": "Welkom, Succesvol gestart!"
}

View File

@@ -1,4 +1,4 @@
{
"sysTitle": "MagicMirror Уведомление",
"welcome": "Добро пожаловать, старт был успешным!"
"sysTitle": "MagicMirror Уведомление",
"welcome": "Добро пожаловать, старт был успешным!"
}

89
modules/default/calendar/README.md Normal file → Executable file
View File

@@ -1,91 +1,6 @@
# Module: Calendar
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.
## Using the module
To use this module, add it to the modules array in the `config/config.js` file:
````javascript
modules: [
{
module: "calendar",
position: "top_left", // This can be any of the regions. Best results in left or right regions.
config: {
// The config property is optional.
// If no config is set, an example calendar is shown.
// See 'Configuration options' for more information.
}
}
]
````
## Configuration options
The following properties can be configured:
| Option | Description
| ---------------------------- | -----------
| `maximumEntries` | The maximum number of events shown. / **Possible values:** `0` - `100` <br> **Default value:** `10`
| `maximumNumberOfDays` | The maximum number of days in the future. <br><br> **Default value:** `365`
| `displaySymbol` | Display a symbol in front of an entry. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
| `defaultSymbol` | The default symbol. <br><br> **Possible values:** See [Font Awsome](http://fontawesome.io/icons/) website. <br> **Default value:** `calendar`
| `maxTitleLength` | The maximum title length. <br><br> **Possible values:** `10` - `50` <br> **Default value:** `25`
| `wrapEvents` | Wrap event titles to multiple lines. Breaks lines at the length defined by `maxTitleLength`. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
| `fetchInterval` | How often does the content needs to be fetched? (Milliseconds) <br><br> **Possible values:** `1000` - `86400000` <br> **Default value:** `300000` (5 minutes)
| `animationSpeed` | Speed of the update animation. (Milliseconds) <br><br> **Possible values:**`0` - `5000` <br> **Default value:** `2000` (2 seconds)
| `fade` | Fade the future events to black. (Gradient) <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
| `fadePoint` | Where to start fade? <br><br> **Possible values:** `0` (top of the list) - `1` (bottom of list) <br> **Default value:** `0.25`
| `calendars` | The list of calendars. <br><br> **Possible values:** An array, see _calendar configuration_ below. <br> **Default value:** _An example calendar._
| `titleReplace` | An object of textual replacements applied to the tile of the event. This allow to remove or replace certains words in the title. <br><br> **Example:** `{'Birthday of ' : '', 'foo':'bar'}` <br> **Default value:** `{ "De verjaardag van ": "", "'s birthday": "" }`
| `displayRepeatingCountTitle` | Show count title for yearly repeating events (e.g. "X. Birthday", "X. Anniversary") <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
| `dateFormat` | Format to use for the date of events (when using absolute dates) <br><br> **Possible values:** See [Moment.js formats](http://momentjs.com/docs/#/parsing/string-format/) <br> **Default value:** `MMM Do` (e.g. Jan 18th)
| `fullDayEventDateFormat` | Format to use for the date of full day events (when using absolute dates) <br><br> **Possible values:** See [Moment.js formats](http://momentjs.com/docs/#/parsing/string-format/) <br> **Default value:** `MMM Do` (e.g. Jan 18th)
| `timeFormat` | Display event times as absolute dates, or relative time <br><br> **Possible values:** `absolute` or `relative` <br> **Default value:** `relative`
| `getRelative` | How much time (in hours) should be left until calendar events start getting relative? <br><br> **Possible values:** `0` (events stay absolute) - `48` (48 hours before the event starts) <br> **Default value:** `6`
| `urgency` | When using a timeFormat of `absolute`, the `urgency` setting allows you to display events within a specific time frame as `relative`. This allows events within a certain time frame to be displayed as relative (in xx days) while others are displayed as absolute dates <br><br> **Possible values:** a positive integer representing the number of days for which you want a relative date, for example `7` (for 7 days) <br><br> **Default value:** `7`
| `broadcastEvents` | If this property is set to true, the calendar will broadcast all the events to all other modules with the notification message: `CALENDAR_EVENTS`. The event objects are stored in an array and contain the following fields: `title`, `startDate`, `endDate`, `fullDayEvent`, `location` and `geo`. <br><br> **Possible values:** `true`, `false` <br><br> **Default value:** `true`
| `hidePrivate` | Hides private calendar events. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
| `excludedEvents` | An array of words / phrases from event titles that will be excluded from being shown. <br><br> **Example:** `['Birthday', 'Hide This Event']` <br> **Default value:** `[]`
### Calendar configuration
The `calendars` property contains an array of the configured calendars.
The `colored` property gives the option for an individual color for each calendar.
#### Default value:
````javascript
config: {
colored: false,
calendars: [
{
url: 'http://www.calendarlabs.com/templates/ical/US-Holidays.ics',
symbol: 'calendar',
auth: {
user: 'username',
pass: 'superstrongpassword',
method: 'basic'
}
},
],
}
````
#### Calendar configuration options:
| Option | Description
| --------------------- | -----------
| `url` | The url of the calendar .ical. This property is required. <br><br> **Possible values:** Any public accessble .ical calendar.
| `symbol` | The symbol to show in front of an event. This property is optional. <br><br> **Possible values:** See [Font Awesome](http://fontawesome.io/icons/) website. To have multiple symbols you can define them in an array e.g. `["calendar", "plane"]`
| `color` | The font color of an event from this calendar. This property should be set if the config is set to colored: true. <br><br> **Possible values:** HEX, RGB or RGBA values (#efefef, rgb(242,242,242), rgba(242,242,242,0.5)).
| `repeatingCountTitle` | The count title for yearly repating events in this calendar. <br><br> **Example:** `'Birthday'`
| `maximumEntries` | The maximum number of events shown. Overrides global setting. **Possible values:** `0` - `100`
| `maximumNumberOfDays` | The maximum number of days in the future. Overrides global setting
| `auth` | The object containing options for authentication against the calendar.
#### Calendar authentication options:
| Option | Description
| --------------------- | -----------
| `user` | The username for HTTP authentication.
| `pass` | The password for HTTP authentication. (If you use Bearer authentication, this should be your BearerToken.)
| `method` | Which authentication method should be used. HTTP Basic, Digest and Bearer authentication methods are supported. Basic authentication is used by default if this option is omitted. **Possible values:** `digest`, `basic`, `bearer` **Default value:** `basic`
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/calendar.html).

View File

@@ -7,8 +7,6 @@
.calendar .symbol span {
display: inline-block;
-ms-transform: translate(0, 2px); /* IE 9 */
-webkit-transform: translate(0, 2px); /* Safari */
transform: translate(0, 2px);
}

504
modules/default/calendar/calendar.js Normal file → Executable file
View File

@@ -1,47 +1,61 @@
/* global Module */
/* global cloneObject */
/* Magic Mirror
* Module: Calendar
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("calendar", {
// Define module defaults
defaults: {
maximumEntries: 10, // Total Maximum Entries
maximumNumberOfDays: 365,
displaySymbol: true,
defaultSymbol: "calendar", // Fontawesome Symbol see http://fontawesome.io/cheatsheet/
defaultSymbol: "calendar", // Fontawesome Symbol see https://fontawesome.com/cheatsheet?from=io
showLocation: false,
displayRepeatingCountTitle: false,
defaultRepeatingCountTitle: "",
maxTitleLength: 25,
maxLocationTitleLength: 25,
wrapEvents: false, // wrap events to multiple lines breaking at maxTitleLength
wrapLocationEvents: false,
maxTitleLines: 3,
maxEventTitleLines: 3,
fetchInterval: 5 * 60 * 1000, // Update every 5 minutes.
animationSpeed: 2000,
fade: true,
urgency: 7,
timeFormat: "relative",
dateFormat: "MMM Do",
dateEndFormat: "LT",
fullDayEventDateFormat: "MMM Do",
showEnd: false,
getRelative: 6,
fadePoint: 0.25, // Start on 1/4th of the list.
hidePrivate: false,
hideOngoing: false,
colored: false,
coloredSymbolOnly: false,
tableClass: "small",
calendars: [
{
symbol: "calendar",
url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics",
},
url: "https://www.calendarlabs.com/templates/ical/US-Holidays.ics"
}
],
titleReplace: {
"De verjaardag van ": "",
"'s birthday": ""
},
locationTitleReplace: {
"street ": ""
},
broadcastEvents: true,
excludedEvents: []
excludedEvents: [],
sliceMultiDayEvents: false,
broadcastPastEvents: false,
nextDaysRelative: false
},
// Define required scripts.
@@ -75,20 +89,37 @@ Module.register("calendar", {
var calendarConfig = {
maximumEntries: calendar.maximumEntries,
maximumNumberOfDays: calendar.maximumNumberOfDays
maximumNumberOfDays: calendar.maximumNumberOfDays,
broadcastPastEvents: calendar.broadcastPastEvents
};
if (calendar.symbolClass === "undefined" || calendar.symbolClass === null) {
calendarConfig.symbolClass = "";
}
if (calendar.titleClass === "undefined" || calendar.titleClass === null) {
calendarConfig.titleClass = "";
}
if (calendar.timeClass === "undefined" || calendar.timeClass === null) {
calendarConfig.timeClass = "";
}
// 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("https://github.com/MichMich/MagicMirror/tree/v2.1.2/modules/default/calendar#calendar-authentication-options");
calendar.auth = {
user: calendar.user,
pass: calendar.pass
}
};
}
this.addCalendar(calendar.url, calendar.auth, calendarConfig);
// Trigger ADD_CALENDAR every fetchInterval to make sure there is always a calendar
// fetcher running on the server side.
var self = this;
setInterval(function () {
self.addCalendar(calendar.url, calendar.auth, calendarConfig);
}, self.config.fetchInterval);
}
this.calendarData = {};
@@ -97,6 +128,10 @@ Module.register("calendar", {
// Override socket notification handler.
socketNotificationReceived: function (notification, payload) {
if (this.identifier !== payload.id) {
return;
}
if (notification === "CALENDAR_EVENTS") {
if (this.hasCalendarURL(payload.url)) {
this.calendarData[payload.url] = payload.events;
@@ -108,10 +143,9 @@ Module.register("calendar", {
}
} else if (notification === "FETCH_ERROR") {
Log.error("Calendar Error. Could not fetch calendar: " + payload.url);
this.loaded = true;
} else if (notification === "INCORRECT_URL") {
Log.error("Calendar Error. Incorrect url: " + payload.url);
} else {
Log.log("Calendar received an unknown socket notification: " + notification);
}
this.updateDom(this.config.animationSpeed);
@@ -119,22 +153,55 @@ Module.register("calendar", {
// Override dom generator.
getDom: function () {
var events = this.createEventList();
var wrapper = document.createElement("table");
wrapper.className = "small";
wrapper.className = this.config.tableClass;
if (events.length === 0) {
wrapper.innerHTML = (this.loaded) ? this.translate("EMPTY") : this.translate("LOADING");
wrapper.className = "small dimmed";
wrapper.innerHTML = this.loaded ? this.translate("EMPTY") : this.translate("LOADING");
wrapper.className = this.config.tableClass + " dimmed";
return wrapper;
}
if (this.config.fade && this.config.fadePoint < 1) {
if (this.config.fadePoint < 0) {
this.config.fadePoint = 0;
}
var startFade = events.length * this.config.fadePoint;
var fadeSteps = events.length - startFade;
}
var currentFadeStep = 0;
var lastSeenDate = "";
for (var e in events) {
var event = events[e];
var dateAsString = moment(event.startDate, "x").format(this.config.dateFormat);
if (this.config.timeFormat === "dateheaders") {
if (lastSeenDate !== dateAsString) {
var dateRow = document.createElement("tr");
dateRow.className = "normal";
var dateCell = document.createElement("td");
dateCell.colSpan = "3";
dateCell.innerHTML = dateAsString;
dateCell.style.paddingTop = "10px";
dateRow.appendChild(dateCell);
wrapper.appendChild(dateRow);
if (e >= startFade) {
//fading
currentFadeStep = e - startFade;
dateRow.style.opacity = 1 - (1 / fadeSteps) * currentFadeStep;
}
lastSeenDate = dateAsString;
}
}
var eventWrapper = document.createElement("tr");
if (this.config.colored) {
if (this.config.colored && !this.config.coloredSymbolOnly) {
eventWrapper.style.cssText = "color:" + this.colorForUrl(event.url);
}
@@ -142,28 +209,38 @@ Module.register("calendar", {
if (this.config.displaySymbol) {
var symbolWrapper = document.createElement("td");
symbolWrapper.className = "symbol align-right";
if (this.config.colored && this.config.coloredSymbolOnly) {
symbolWrapper.style.cssText = "color:" + this.colorForUrl(event.url);
}
var symbolClass = this.symbolClassForUrl(event.url);
symbolWrapper.className = "symbol align-right " + symbolClass;
var symbols = this.symbolsForUrl(event.url);
if(typeof symbols === "string") {
if (typeof symbols === "string") {
symbols = [symbols];
}
for(var i = 0; i < symbols.length; i++) {
for (var i = 0; i < symbols.length; i++) {
var symbol = document.createElement("span");
symbol.className = "fa fa-fw fa-" + symbols[i];
if(i > 0){
if (i > 0) {
symbol.style.paddingLeft = "5px";
}
symbolWrapper.appendChild(symbol);
}
eventWrapper.appendChild(symbolWrapper);
} else if (this.config.timeFormat === "dateheaders") {
var blankCell = document.createElement("td");
blankCell.innerHTML = "&nbsp;&nbsp;&nbsp;";
eventWrapper.appendChild(blankCell);
}
var titleWrapper = document.createElement("td"),
repeatingCountTitle = "";
if (this.config.displayRepeatingCountTitle) {
if (this.config.displayRepeatingCountTitle && event.firstYear !== undefined) {
repeatingCountTitle = this.countTitleForUrl(event.url);
if (repeatingCountTitle !== "") {
@@ -174,64 +251,55 @@ Module.register("calendar", {
}
}
titleWrapper.innerHTML = this.titleTransform(event.title) + repeatingCountTitle;
titleWrapper.innerHTML = this.titleTransform(event.title, this.config.titleReplace, this.config.wrapEvents, this.config.maxTitleLength, this.config.maxTitleLines) + repeatingCountTitle;
var titleClass = this.titleClassForUrl(event.url);
if (!this.config.colored) {
titleWrapper.className = "title bright";
titleWrapper.className = "title bright " + titleClass;
} else {
titleWrapper.className = "title";
titleWrapper.className = "title " + titleClass;
}
eventWrapper.appendChild(titleWrapper);
var timeWrapper;
var timeWrapper = document.createElement("td");
//console.log(event.today);
var now = new Date();
// Define second, minute, hour, and day variables
var oneSecond = 1000; // 1,000 milliseconds
var oneMinute = oneSecond * 60;
var oneHour = oneMinute * 60;
var oneDay = oneHour * 24;
if (event.fullDayEvent) {
if (event.today) {
timeWrapper.innerHTML = this.capFirst(this.translate("TODAY"));
} else if (event.startDate - now < oneDay && event.startDate - now > 0) {
timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW"));
} else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) {
if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") {
timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW"));
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
if (this.config.timeFormat === "dateheaders") {
if (event.fullDayEvent) {
titleWrapper.colSpan = "2";
titleWrapper.align = "left";
} else {
/* 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
* 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()
*
* 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.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) {
// This event falls within the config.urgency period that the user has set
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat));
}
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
timeWrapper = document.createElement("td");
timeWrapper.className = "time light " + this.timeClassForUrl(event.url);
timeWrapper.align = "left";
timeWrapper.style.paddingLeft = "2px";
timeWrapper.innerHTML = moment(event.startDate, "x").format("LT");
eventWrapper.appendChild(timeWrapper);
titleWrapper.align = "right";
}
eventWrapper.appendChild(titleWrapper);
} else {
if (event.startDate >= new Date()) {
if (event.startDate - now < 2 * oneDay) {
// This event is within the next 48 hours (2 days)
if (event.startDate - now < this.config.getRelative * oneHour) {
// If event is within 6 hour, display 'in xxx' time format or moment.fromNow()
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
timeWrapper = document.createElement("td");
eventWrapper.appendChild(titleWrapper);
var now = new Date();
// Define second, minute, hour, and day variables
var oneSecond = 1000; // 1,000 milliseconds
var oneMinute = oneSecond * 60;
var oneHour = oneMinute * 60;
var oneDay = oneHour * 24;
if (event.fullDayEvent) {
//subtract one second so that fullDayEvents end at 23:59:59, and not at 0:00:00 one the next day
event.endDate -= oneSecond;
if (event.today) {
timeWrapper.innerHTML = this.capFirst(this.translate("TODAY"));
} else if (event.startDate - now < oneDay && event.startDate - now > 0) {
timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW"));
} else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) {
if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") {
timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW"));
} else {
// Otherwise just say 'Today/Tomorrow at such-n-such time'
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar());
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
} else {
/* Check to see if the user displays absolute or relative dates with their events
@@ -242,42 +310,102 @@ Module.register("calendar", {
* 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.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
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat));
}
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
}
}
if (this.config.showEnd) {
timeWrapper.innerHTML += "-";
timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.fullDayEventDateFormat));
}
} else {
timeWrapper.innerHTML = this.capFirst(
this.translate("RUNNING", {
fallback: this.translate("RUNNING") + " {timeUntilEnd}",
timeUntilEnd: moment(event.endDate, "x").fromNow(true)
})
);
if (event.startDate >= new Date()) {
if (event.startDate - now < 2 * oneDay) {
// This event is within the next 48 hours (2 days)
if (event.startDate - now < this.config.getRelative * oneHour) {
// If event is within 6 hour, display 'in xxx' time format or moment.fromNow()
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
} else {
if (this.config.timeFormat === "absolute" && !this.config.nextDaysRelative) {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
} else {
// Otherwise just say 'Today/Tomorrow at such-n-such time'
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar());
}
}
} else {
/* 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
* 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()
*
* 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.urgency > 1 && event.startDate - now < this.config.urgency * oneDay) {
// This event falls within the config.urgency period that the user has set
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
}
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
}
} else {
timeWrapper.innerHTML = this.capFirst(
this.translate("RUNNING", {
fallback: this.translate("RUNNING") + " {timeUntilEnd}",
timeUntilEnd: moment(event.endDate, "x").fromNow(true)
})
);
}
if (this.config.showEnd) {
timeWrapper.innerHTML += "-";
timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.dateEndFormat));
}
}
//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
timeWrapper.className = "time light " + this.timeClassForUrl(event.url);
eventWrapper.appendChild(timeWrapper);
}
//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
//console.log(event);
timeWrapper.className = "time light";
eventWrapper.appendChild(timeWrapper);
wrapper.appendChild(eventWrapper);
// Create fade effect.
if (this.config.fade && this.config.fadePoint < 1) {
if (this.config.fadePoint < 0) {
this.config.fadePoint = 0;
}
var startingPoint = events.length * this.config.fadePoint;
var steps = events.length - startingPoint;
if (e >= startingPoint) {
var currentStep = e - startingPoint;
eventWrapper.style.opacity = 1 - (1 / steps * currentStep);
if (e >= startFade) {
currentFadeStep = e - startFade;
eventWrapper.style.opacity = 1 - (1 / fadeSteps) * currentFadeStep;
}
if (this.config.showLocation) {
if (event.location !== false) {
var locationRow = document.createElement("tr");
locationRow.className = "normal xsmall light";
if (this.config.displaySymbol) {
var symbolCell = document.createElement("td");
locationRow.appendChild(symbolCell);
}
var descCell = document.createElement("td");
descCell.className = "location";
descCell.colSpan = "2";
descCell.innerHTML = this.titleTransform(event.location, this.config.locationTitleReplace, this.config.wrapLocationEvents, this.config.maxLocationTitleLength, this.config.maxEventTitleLines);
locationRow.appendChild(descCell);
wrapper.appendChild(locationRow);
if (e >= startFade) {
currentFadeStep = e - startFade;
locationRow.style.opacity = 1 - (1 / fadeSteps) * currentFadeStep;
}
}
}
}
@@ -293,20 +421,17 @@ Module.register("calendar", {
* @param {number} timeFormat Specifies either 12 or 24 hour time format
* @returns {moment.LocaleSpecification}
*/
getLocaleSpecification: function(timeFormat) {
getLocaleSpecification: function (timeFormat) {
switch (timeFormat) {
case 12: {
return { longDateFormat: {LT: "h:mm A"} };
break;
}
case 24: {
return { longDateFormat: {LT: "HH:mm"} };
break;
}
default: {
return { longDateFormat: {LT: moment.localeData().longDateFormat("LT")} };
break;
}
case 12: {
return { longDateFormat: { LT: "h:mm A" } };
}
case 24: {
return { longDateFormat: { LT: "HH:mm" } };
}
default: {
return { longDateFormat: { LT: moment.localeData().longDateFormat("LT") } };
}
}
},
@@ -336,29 +461,81 @@ Module.register("calendar", {
createEventList: function () {
var events = [];
var today = moment().startOf("day");
var now = new Date();
var future = moment().startOf("day").add(this.config.maximumNumberOfDays, "days").toDate();
for (var c in this.calendarData) {
var calendar = this.calendarData[c];
for (var e in calendar) {
var event = calendar[e];
if(this.config.hidePrivate) {
if(event.class === "PRIVATE") {
// do not add the current event, skip it
continue;
var event = JSON.parse(JSON.stringify(calendar[e])); // clone object
if (event.endDate < now) {
continue;
}
if (this.config.hidePrivate) {
if (event.class === "PRIVATE") {
// do not add the current event, skip it
continue;
}
}
if (this.config.hideOngoing) {
if (event.startDate < now) {
continue;
}
}
if (this.listContainsEvent(events, event)) {
continue;
}
event.url = c;
event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000);
events.push(event);
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,
* 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;
if (this.config.sliceMultiDayEvents && maxCount > 1) {
var splitEvents = [];
var midnight = moment(event.startDate, "x").clone().startOf("day").add(1, "day").format("x");
var count = 1;
while (event.endDate > midnight) {
var thisEvent = JSON.parse(JSON.stringify(event)); // clone object
thisEvent.today = thisEvent.startDate >= today && thisEvent.startDate < today + 24 * 60 * 60 * 1000;
thisEvent.endDate = midnight;
thisEvent.title += " (" + count + "/" + maxCount + ")";
splitEvents.push(thisEvent);
event.startDate = midnight;
count += 1;
midnight = moment(midnight, "x").add(1, "day").format("x"); // next day
}
// Last day
event.title += " (" + count + "/" + maxCount + ")";
splitEvents.push(event);
for (event of splitEvents) {
if (event.endDate > now && event.endDate <= future) {
events.push(event);
}
}
} else {
events.push(event);
}
}
}
events.sort(function (a, b) {
return a.startDate - b.startDate;
});
return events.slice(0, this.config.maximumEntries);
},
listContainsEvent: function (eventList, event) {
for (var evt of eventList) {
if (evt.title === event.title && parseInt(evt.startDate) === parseInt(event.startDate)) {
return true;
}
}
return false;
},
/* createEventList(url)
* Requests node helper to add calendar url.
*
@@ -366,16 +543,22 @@ Module.register("calendar", {
*/
addCalendar: function (url, auth, calendarConfig) {
this.sendSocketNotification("ADD_CALENDAR", {
id: this.identifier,
url: url,
excludedEvents: calendarConfig.excludedEvents || this.config.excludedEvents,
maximumEntries: calendarConfig.maximumEntries || this.config.maximumEntries,
maximumNumberOfDays: calendarConfig.maximumNumberOfDays || this.config.maximumNumberOfDays,
fetchInterval: this.config.fetchInterval,
auth: auth
symbolClass: calendarConfig.symbolClass,
titleClass: calendarConfig.titleClass,
timeClass: calendarConfig.timeClass,
auth: auth,
broadcastPastEvents: calendarConfig.broadcastPastEvents || this.config.broadcastPastEvents
});
},
/* symbolsForUrl(url)
/**
* symbolsForUrl(url)
* Retrieves the symbols for a specific url.
*
* argument url string - Url to look for.
@@ -386,6 +569,53 @@ Module.register("calendar", {
return this.getCalendarProperty(url, "symbol", this.config.defaultSymbol);
},
/**
* symbolClassForUrl(url)
* Retrieves the symbolClass for a specific url.
*
* @param url string - Url to look for.
*
* @returns string
*/
symbolClassForUrl: function (url) {
return this.getCalendarProperty(url, "symbolClass", "");
},
/**
* titleClassForUrl(url)
* Retrieves the titleClass for a specific url.
*
* @param url string - Url to look for.
*
* @returns string
*/
titleClassForUrl: function (url) {
return this.getCalendarProperty(url, "titleClass", "");
},
/**
* timeClassForUrl(url)
* Retrieves the timeClass for a specific url.
*
* @param url string - Url to look for.
*
* @returns string
*/
timeClassForUrl: function (url) {
return this.getCalendarProperty(url, "timeClass", "");
},
/* calendarNameForUrl(url)
* Retrieves the calendar name for a specific url.
*
* argument url string - Url to look for.
*
* return string - The name of the calendar
*/
calendarNameForUrl: function (url) {
return this.getCalendarProperty(url, "name", "");
},
/* colorForUrl(url)
* Retrieves the color for a specific url.
*
@@ -434,9 +664,10 @@ Module.register("calendar", {
* @param {string} string Text string to shorten
* @param {number} maxLength The max length of the string
* @param {boolean} wrapEvents Wrap the text after the line has reached maxLength
* @param {number} maxTitleLines The max number of vertical lines before cutting event title
* @returns {string} The shortened string
*/
shorten: function (string, maxLength, wrapEvents) {
shorten: function (string, maxLength, wrapEvents, maxTitleLines) {
if (typeof string !== "string") {
return "";
}
@@ -445,16 +676,26 @@ Module.register("calendar", {
var temp = "";
var currentLine = "";
var words = string.split(" ");
var line = 0;
for (var i = 0; i < words.length; i++) {
var word = words[i];
if (currentLine.length + word.length < (typeof maxLength === "number" ? maxLength : 25) - 1) { // max - 1 to account for a space
currentLine += (word + " ");
if (currentLine.length + word.length < (typeof maxLength === "number" ? maxLength : 25) - 1) {
// max - 1 to account for a space
currentLine += word + " ";
} else {
line++;
if (line > maxTitleLines - 1) {
if (i < words.length) {
currentLine += "&hellip;";
}
break;
}
if (currentLine.length > 0) {
temp += (currentLine + "<br>" + word + " ");
temp += currentLine + "<br>" + word + " ";
} else {
temp += (word + "<br>");
temp += word + "<br>";
}
currentLine = "";
}
@@ -474,7 +715,6 @@ Module.register("calendar", {
* Capitalize the first letter of a string
* Return capitalized string
*/
capFirst: function (string) {
return string.charAt(0).toUpperCase() + string.slice(1);
},
@@ -488,20 +728,20 @@ Module.register("calendar", {
*
* return string - The transformed title.
*/
titleTransform: function (title) {
for (var needle in this.config.titleReplace) {
var replacement = this.config.titleReplace[needle];
titleTransform: function (title, titleReplace, wrapEvents, maxTitleLength, maxTitleLines) {
for (var needle in titleReplace) {
var replacement = titleReplace[needle];
var regParts = needle.match(/^\/(.+)\/([gim]*)$/);
if (regParts) {
// the parsed pattern is a regexp.
needle = new RegExp(regParts[1], regParts[2]);
// the parsed pattern is a regexp.
needle = new RegExp(regParts[1], regParts[2]);
}
title = title.replace(needle, replacement);
}
title = this.shorten(title, this.config.maxTitleLength, this.config.wrapEvents);
title = this.shorten(title, maxTitleLength, wrapEvents, maxTitleLines);
return title;
},
@@ -516,17 +756,17 @@ Module.register("calendar", {
for (var e in calendar) {
var event = cloneObject(calendar[e]);
event.symbol = this.symbolsForUrl(url);
event.calendarName = this.calendarNameForUrl(url);
event.color = this.colorForUrl(url);
delete event.url;
eventList.push(event);
}
}
eventList.sort(function(a,b) {
eventList.sort(function (a, b) {
return a.startDate - b.startDate;
});
this.sendNotification("CALENDAR_EVENTS", eventList);
}
});

View File

@@ -1,83 +1,88 @@
/* Magic Mirror
* Node Helper: Calendar - CalendarFetcher
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const Log = require("../../../js/logger.js");
const ical = require("ical");
const moment = require("moment");
const request = require("request");
var ical = require("./vendor/ical.js");
var moment = require("moment");
const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumberOfDays, auth, includePastEvents) {
const self = this;
var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth) {
var self = this;
let reloadTimer = null;
let events = [];
var reloadTimer = null;
var events = [];
var fetchFailedCallback = function() {};
var eventsReceivedCallback = function() {};
let fetchFailedCallback = function () {};
let eventsReceivedCallback = function () {};
/* fetchCalendar()
* Initiates calendar fetch.
*/
var fetchCalendar = function() {
const fetchCalendar = function () {
clearTimeout(reloadTimer);
reloadTimer = null;
nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
var opts = {
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
const opts = {
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
};
if (auth) {
if(auth.method === "bearer"){
if (auth.method === "bearer") {
opts.auth = {
bearer: auth.pass
}
}else{
};
} else {
opts.auth = {
user: auth.user,
pass: auth.pass
pass: auth.pass,
sendImmediately: auth.method !== "digest"
};
if(auth.method === "digest"){
opts.auth.sendImmediately = false;
}else{
opts.auth.sendImmediately = true;
}
}
}
ical.fromURL(url, opts, function(err, data) {
request(url, opts, function (err, r, requestData) {
if (err) {
fetchFailedCallback(self, err);
scheduleTimer();
return;
} else if (r.statusCode !== 200) {
fetchFailedCallback(self, r.statusCode + ": " + r.statusMessage);
scheduleTimer();
return;
}
// console.log(data);
newEvents = [];
const data = ical.parseICS(requestData);
const newEvents = [];
var limitFunction = function(date, i) {return i < maximumEntries;};
var eventDate = function(event, time) {
return (event[time].length === 8) ? moment(event[time], "YYYYMMDD") : moment(new Date(event[time]));
// 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
const limitFunction = function (date, i) {
return true;
};
for (var e in data) {
var event = data[e];
var now = new Date();
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.
const eventDate = function (event, time) {
return event[time].length === 8 ? moment(event[time], "YYYYMMDD") : moment(new Date(event[time]));
};
// FIXME:
// Ugly fix to solve the facebook birthday issue.
Object.entries(data).forEach(([key, event]) => {
const now = new Date();
const today = moment().startOf("day").toDate();
const 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.
let past = today;
if (includePastEvents) {
past = moment().startOf("day").subtract(maximumNumberOfDays, "days").toDate();
}
// FIXME: Ugly fix to solve the facebook birthday issue.
// Otherwise, the recurring events only show the birthday for next year.
var isFacebookBirthday = false;
let isFacebookBirthday = false;
if (typeof event.uid !== "undefined") {
if (event.uid.indexOf("@facebook.com") !== -1) {
isFacebookBirthday = true;
@@ -85,11 +90,13 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
}
if (event.type === "VEVENT") {
let startDate = eventDate(event, "start");
let endDate;
var startDate = eventDate(event, "start");
var endDate;
if (typeof event.end !== "undefined") {
endDate = eventDate(event, "end");
} else if (typeof event.duration !== "undefined") {
endDate = startDate.clone().add(moment.duration(event.duration));
} else {
if (!isFacebookBirthday) {
endDate = startDate;
@@ -98,48 +105,155 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
}
}
// calculate the duration f the event for use with recurring events.
var duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));
// calculate the duration of the event for use with recurring events.
let duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));
if (event.start.length === 8) {
startDate = startDate.startOf("day");
}
var title = "Event";
if (event.summary) {
title = (typeof event.summary.val !== "undefined") ? event.summary.val : event.summary;
} else if(event.description) {
title = event.description;
}
const title = getTitleFromEvent(event);
var excluded = false;
for (var f in excludedEvents) {
var filter = excludedEvents[f];
if (title.toLowerCase().includes(filter.toLowerCase())) {
excluded = true;
let excluded = false,
dateFilter = null;
for (let f in excludedEvents) {
let filter = excludedEvents[f],
testTitle = title.toLowerCase(),
until = null,
useRegex = false,
regexFlags = "g";
if (filter instanceof Object) {
if (typeof filter.until !== "undefined") {
until = filter.until;
}
if (typeof filter.regex !== "undefined") {
useRegex = filter.regex;
}
// If additional advanced filtering is added in, this section
// must remain last as we overwrite the filter object with the
// filterBy string
if (filter.caseSensitive) {
filter = filter.filterBy;
testTitle = title;
} else if (useRegex) {
filter = filter.filterBy;
testTitle = title;
regexFlags += "i";
} else {
filter = filter.filterBy.toLowerCase();
}
} else {
filter = filter.toLowerCase();
}
if (testTitleByFilter(testTitle, filter, useRegex, regexFlags)) {
if (until) {
dateFilter = until;
} else {
excluded = true;
}
break;
}
}
if (excluded) {
continue;
return;
}
var location = event.location || false;
var geo = event.geo || false;
var description = event.description || false;
const location = event.location || false;
const geo = event.geo || false;
const description = event.description || false;
if (typeof event.rrule != "undefined" && !isFacebookBirthday) {
var rule = event.rrule;
var dates = rule.between(today, future, true, limitFunction);
if (typeof event.rrule !== "undefined" && event.rrule !== null && !isFacebookBirthday) {
const rule = event.rrule;
let addedEvents = 0;
for (var d in dates) {
startDate = moment(new Date(dates[d]));
endDate = moment(parseInt(startDate.format("x")) + duration, "x");
if (endDate.format("x") > now) {
const pastMoment = moment(past);
const futureMoment = moment(future);
// can cause problems with e.g. birthdays before 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.origOptions.dtstart.setYear(1900);
rule.options.dtstart.setYear(1900);
}
// For recurring events, get the set of start dates that fall within the range
// of dates we're looking for.
// kblankenship1989 - to fix issue #1798, converting all dates to locale time first, then converting back to UTC time
const pastLocal = pastMoment.subtract(past.getTimezoneOffset(), "minutes").toDate();
const futureLocal = futureMoment.subtract(future.getTimezoneOffset(), "minutes").toDate();
const datesLocal = rule.between(pastLocal, futureLocal, true, limitFunction);
const dates = datesLocal.map(function (dateLocal) {
return moment(dateLocal).add(dateLocal.getTimezoneOffset(), "minutes").toDate();
});
// The "dates" array contains the set of dates within our desired date range range that are valid
// for the recurrence rule. *However*, it's possible for us to have a specific recurrence that
// had its date changed from outside the range to inside the range. For the time being,
// we'll handle this by adding *all* recurrence entries into the set of dates that we check,
// because the logic below will filter out any recurrences that don't actually belong within
// our display range.
// Would be great if there was a better way to handle this.
if (event.recurrences !== undefined) {
for (let r in event.recurrences) {
// Only add dates that weren't already in the range we added from the rrule so that
// we don"t double-add those events.
if (moment(new Date(r)).isBetween(pastMoment, futureMoment) !== true) {
dates.push(new Date(r));
}
}
}
// Loop through the set of date entries to see which recurrences should be added to our event list.
for (let d in dates) {
const date = dates[d];
// 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
// (see https://github.com/peterbraden/ical.js/pull/84 )
const dateKey = date.toISOString().substring(0, 10);
let curEvent = event;
let showRecurrence = true;
startDate = moment(date);
// 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) {
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
curEvent = curEvent.recurrences[dateKey];
startDate = moment(curEvent.start);
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.
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.
showRecurrence = false;
}
endDate = moment(parseInt(startDate.format("x")) + duration, "x");
if (startDate.format("x") === endDate.format("x")) {
endDate = endDate.endOf("day");
}
const recurrenceTitle = getTitleFromEvent(curEvent);
// If this recurrence ends before the start of the date range, or starts after the end of the date range, don"t add
// it to the event list.
if (endDate.isBefore(past) || startDate.isAfter(future)) {
showRecurrence = false;
}
if (timeFilterApplies(now, endDate, dateFilter)) {
showRecurrence = false;
}
if (showRecurrence === true) {
addedEvents++;
newEvents.push({
title: title,
title: recurrenceTitle,
startDate: startDate.format("x"),
endDate: endDate.format("x"),
fullDayEvent: isFullDayEvent(event),
@@ -151,28 +265,43 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
});
}
}
// end recurring event parsing
} else {
// console.log("Single event ...");
// Single event.
var fullDayEvent = (isFacebookBirthday) ? true : isFullDayEvent(event);
const fullDayEvent = isFacebookBirthday ? true : isFullDayEvent(event);
if (!fullDayEvent && endDate < new Date()) {
//console.log("It's not a fullday event, and it is in the past. So skip: " + title);
continue;
}
if (fullDayEvent && endDate <= today) {
//console.log("It's a fullday event, and it is before today. So skip: " + title);
continue;
if (includePastEvents) {
// Past event is too far in the past, so skip.
if (endDate < past) {
return;
}
} else {
// It's not a fullday event, and it is in the past, so skip.
if (!fullDayEvent && endDate < new Date()) {
return;
}
// It's a fullday event, and it is before today, So skip.
if (fullDayEvent && endDate <= today) {
return;
}
}
// It exceeds the maximumNumberOfDays limit, so skip.
if (startDate > future) {
//console.log("It exceeds the maximumNumberOfDays limit. So skip: " + title);
continue;
return;
}
if (timeFilterApplies(now, endDate, dateFilter)) {
return;
}
// Adjust start date so multiple day events will be displayed as happening today even though they started some days ago already
if (fullDayEvent && startDate <= today) {
startDate = moment(today);
}
// Every thing is good. Add it to the list.
newEvents.push({
title: title,
startDate: startDate.format("x"),
@@ -183,18 +312,15 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
geo: geo,
description: description
});
}
}
}
});
newEvents.sort(function(a, b) {
newEvents.sort(function (a, b) {
return a.startDate - b.startDate;
});
//console.log(newEvents);
events = newEvents.slice(0, maximumEntries);
events = newEvents;
self.broadcastEvents();
scheduleTimer();
@@ -204,10 +330,9 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
/* scheduleTimer()
* Schedule the timer for the next update.
*/
var scheduleTimer = function() {
//console.log('Schedule update timer.');
const scheduleTimer = function () {
clearTimeout(reloadTimer);
reloadTimer = setTimeout(function() {
reloadTimer = setTimeout(function () {
fetchCalendar();
}, reloadInterval);
};
@@ -215,20 +340,19 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
/* isFullDayEvent(event)
* Checks if an event is a fullday event.
*
* argument event obejct - The event object to check.
* argument event object - The event object to check.
*
* return bool - The event is a fullday event.
*/
var isFullDayEvent = function(event) {
if (event.start.length === 8) {
const isFullDayEvent = function (event) {
if (event.start.length === 8 || event.start.dateOnly) {
return true;
}
var start = event.start || 0;
var startDate = new Date(start);
var end = event.end || 0;
if (end - start === 24 * 60 * 60 * 1000 && startDate.getHours() === 0 && startDate.getMinutes() === 0) {
const start = event.start || 0;
const startDate = new Date(start);
const end = event.end || 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.
return true;
}
@@ -236,20 +360,76 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
return false;
};
/* timeFilterApplies()
* Determines if the user defined time filter should apply
*
* argument now Date - Date object using previously created object for consistency
* argument endDate Moment - Moment object representing the event end date
* argument filter string - The time to subtract from the end date to determine if an event should be shown
*
* return bool - The event should be filtered out
*/
const timeFilterApplies = function (now, endDate, filter) {
if (filter) {
const until = filter.split(" "),
value = parseInt(until[0]),
increment = until[1].slice(-1) === "s" ? until[1] : until[1] + "s", // Massage the data for moment js
filterUntil = moment(endDate.format()).subtract(value, increment);
return now < filterUntil.format("x");
}
return false;
};
/* getTitleFromEvent(event)
* Gets the title from the event.
*
* argument event object - The event object to check.
*
* return string - The title of the event, or "Event" if no title is found.
*/
const getTitleFromEvent = function (event) {
let title = "Event";
if (event.summary) {
title = typeof event.summary.val !== "undefined" ? event.summary.val : event.summary;
} else if (event.description) {
title = event.description;
}
return title;
};
const testTitleByFilter = function (title, filter, useRegex, regexFlags) {
if (useRegex) {
// Assume if leading slash, there is also trailing slash
if (filter[0] === "/") {
// Strip leading and trailing slashes
filter = filter.substr(1).slice(0, -1);
}
filter = new RegExp(filter, regexFlags);
return filter.test(title);
} else {
return title.includes(filter);
}
};
/* public methods */
/* startFetch()
* Initiate fetchCalendar();
*/
this.startFetch = function() {
this.startFetch = function () {
fetchCalendar();
};
/* broadcastItems()
* Broadcast the existing events.
*/
this.broadcastEvents = function() {
//console.log('Broadcasting ' + events.length + ' events.');
this.broadcastEvents = function () {
Log.info("Calendar-Fetcher: Broadcasting " + events.length + " events.");
eventsReceivedCallback(self);
};
@@ -258,7 +438,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
*
* argument callback function - The on success callback.
*/
this.onReceive = function(callback) {
this.onReceive = function (callback) {
eventsReceivedCallback = callback;
};
@@ -267,7 +447,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
*
* argument callback function - The on error callback.
*/
this.onError = function(callback) {
this.onError = function (callback) {
fetchFailedCallback = callback;
};
@@ -276,7 +456,7 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
*
* return string - The url of this fetcher.
*/
this.url = function() {
this.url = function () {
return url;
};
@@ -285,11 +465,9 @@ var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntri
*
* return array - The current available events for this fetcher.
*/
this.events = function() {
this.events = function () {
return events;
};
};
module.exports = CalendarFetcher;

View File

@@ -2,39 +2,37 @@
* 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.
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const CalendarFetcher = require("./calendarfetcher.js");
var CalendarFetcher = require("./calendarfetcher.js");
var url = "https://calendar.google.com/calendar/ical/pkm1t2uedjbp0uvq1o7oj1jouo%40group.calendar.google.com/private-08ba559f89eec70dd74bbd887d0a3598/basic.ics"; // Standard test URL
// var url = "https://www.googleapis.com/calendar/v3/calendars/primary/events/"; // URL for Bearer auth (must be configured in Google OAuth2 first)
var fetchInterval = 60 * 60 * 1000;
var maximumEntries = 10;
var maximumNumberOfDays = 365;
var user = "magicmirror";
var pass = "MyStrongPass";
var auth = {
const url = "https://calendar.google.com/calendar/ical/pkm1t2uedjbp0uvq1o7oj1jouo%40group.calendar.google.com/private-08ba559f89eec70dd74bbd887d0a3598/basic.ics"; // Standard test URL
//const url = "https://www.googleapis.com/calendar/v3/calendars/primary/events/"; // URL for Bearer auth (must be configured in Google OAuth2 first)
const fetchInterval = 60 * 60 * 1000;
const maximumEntries = 10;
const maximumNumberOfDays = 365;
const user = "magicmirror";
const pass = "MyStrongPass";
const auth = {
user: user,
pass: pass
};
console.log("Create fetcher ...");
fetcher = new CalendarFetcher(url, fetchInterval, maximumEntries, maximumNumberOfDays, auth);
const fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maximumNumberOfDays, auth);
fetcher.onReceive(function(fetcher) {
fetcher.onReceive(function (fetcher) {
console.log(fetcher.events());
console.log("------------------------------------------------------------");
});
fetcher.onError(function(fetcher, error) {
fetcher.onError(function (fetcher, error) {
console.log("Fetcher error:");
console.log(error);
});
fetcher.startFetch();
console.log("Create fetcher done! ");
console.log("Create fetcher done! ");

View File

@@ -1,30 +1,26 @@
/* Magic Mirror
* Node Helper: Calendar
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
var NodeHelper = require("node_helper");
var validUrl = require("valid-url");
var CalendarFetcher = require("./calendarfetcher.js");
const NodeHelper = require("node_helper");
const validUrl = require("valid-url");
const CalendarFetcher = require("./calendarfetcher.js");
const Log = require("../../../js/logger");
module.exports = NodeHelper.create({
// Override start method.
start: function() {
var events = [];
start: function () {
Log.log("Starting node helper for: " + this.name);
this.fetchers = [];
console.log("Starting node helper for: " + this.name);
},
// Override socketNotificationReceived method.
socketNotificationReceived: function(notification, payload) {
socketNotificationReceived: function (notification, payload) {
if (notification === "ADD_CALENDAR") {
//console.log('ADD_CALENDAR: ');
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth);
this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumNumberOfDays, payload.auth, payload.broadcastPastEvents, payload.id);
}
},
@@ -35,41 +31,40 @@ module.exports = NodeHelper.create({
* attribute url string - URL of the news feed.
* attribute reloadInterval number - Reload interval in milliseconds.
*/
createFetcher: function(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth) {
createFetcher: function (url, fetchInterval, excludedEvents, maximumNumberOfDays, auth, broadcastPastEvents, identifier) {
var self = this;
if (!validUrl.isUri(url)) {
self.sendSocketNotification("INCORRECT_URL", {url: url});
self.sendSocketNotification("INCORRECT_URL", { id: identifier, url: url });
return;
}
var fetcher;
if (typeof self.fetchers[url] === "undefined") {
console.log("Create new calendar fetcher for url: " + url + " - Interval: " + fetchInterval);
fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth);
fetcher.onReceive(function(fetcher) {
//console.log('Broadcast events.');
//console.log(fetcher.events());
if (typeof self.fetchers[identifier + url] === "undefined") {
Log.log("Create new calendar fetcher for url: " + url + " - Interval: " + fetchInterval);
fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumNumberOfDays, auth, broadcastPastEvents);
fetcher.onReceive(function (fetcher) {
self.sendSocketNotification("CALENDAR_EVENTS", {
id: identifier,
url: fetcher.url(),
events: fetcher.events()
});
});
fetcher.onError(function(fetcher, error) {
fetcher.onError(function (fetcher, error) {
Log.error("Calendar Error. Could not fetch calendar: ", fetcher.url(), error);
self.sendSocketNotification("FETCH_ERROR", {
id: identifier,
url: fetcher.url(),
error: error
});
});
self.fetchers[url] = fetcher;
self.fetchers[identifier + url] = fetcher;
} else {
//console.log('Use existing news fetcher for url: ' + url);
fetcher = self.fetchers[url];
Log.log("Use existing calendar fetcher for url: " + url);
fetcher = self.fetchers[identifier + url];
fetcher.broadcastEvents();
}

View File

@@ -1,6 +0,0 @@
language: node_js
node_js:
- "0.10"
- "0.12"
- "4.2"
install: npm install

View File

@@ -1,178 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -1,13 +0,0 @@
Copyright 2012 Peter Braden
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,13 +0,0 @@
var ical = require('ical')
, months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function(err, data){
for (var k in data){
if (data.hasOwnProperty(k)){
var ev = data[k]
console.log("Conference", ev.summary, 'is in', ev.location, 'on the', ev.start.getDate(), 'of', months[ev.start.getMonth()] );
}
}
})

View File

@@ -1,319 +0,0 @@
(function(name, definition) {
/****************
* A tolerant, minimal icalendar parser
* (http://tools.ietf.org/html/rfc5545)
*
* <peterbraden@peterbraden.co.uk>
* **************/
if (typeof module !== 'undefined') {
module.exports = definition();
} else if (typeof define === 'function' && typeof define.amd === 'object'){
define(definition);
} else {
this[name] = definition();
}
}('ical', function(){
// Unescape Text re RFC 4.3.11
var text = function(t){
t = t || "";
return (t
.replace(/\\\,/g, ',')
.replace(/\\\;/g, ';')
.replace(/\\[nN]/g, '\n')
.replace(/\\\\/g, '\\')
)
}
var parseParams = function(p){
var out = {}
for (var i = 0; i<p.length; i++){
if (p[i].indexOf('=') > -1){
var segs = p[i].split('=');
out[segs[0]] = parseValue(segs.slice(1).join('='));
}
}
return out || sp
}
var parseValue = function(val){
if ('TRUE' === val)
return true;
if ('FALSE' === val)
return false;
var number = Number(val);
if (!isNaN(number))
return number;
return val;
}
var storeParam = function(name){
return function(val, params, curr){
var data;
if (params && params.length && !(params.length==1 && params[0]==='CHARSET=utf-8')){
data = {params:parseParams(params), val:text(val)}
}
else
data = text(val)
var current = curr[name];
if (Array.isArray(current)){
current.push(data);
return curr;
}
if (current != null){
curr[name] = [current, data];
return curr;
}
curr[name] = data;
return curr
}
}
var addTZ = function(dt, name, params){
var p = parseParams(params);
if (params && p){
dt[name].tz = p.TZID
}
return dt
}
var dateParam = function(name){
return function(val, params, curr){
// Store as string - worst case scenario
storeParam(name)(val, undefined, curr)
if (params && params[0] === "VALUE=DATE") {
// Just Date
var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(val);
if (comps !== null) {
// No TZ info - assume same timezone as this computer
curr[name] = new Date(
comps[1],
parseInt(comps[2], 10)-1,
comps[3]
);
return addTZ(curr, name, params);
}
}
//typical RFC date-time format
var comps = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z)?$/.exec(val);
if (comps !== null) {
if (comps[7] == 'Z'){ // GMT
curr[name] = new Date(Date.UTC(
parseInt(comps[1], 10),
parseInt(comps[2], 10)-1,
parseInt(comps[3], 10),
parseInt(comps[4], 10),
parseInt(comps[5], 10),
parseInt(comps[6], 10 )
));
// TODO add tz
} else {
curr[name] = new Date(
parseInt(comps[1], 10),
parseInt(comps[2], 10)-1,
parseInt(comps[3], 10),
parseInt(comps[4], 10),
parseInt(comps[5], 10),
parseInt(comps[6], 10)
);
}
}
return addTZ(curr, name, params)
}
}
var exdateParam = function(name){
return function(val, params, curr){
var date = dateParam(name)(val, params, curr);
if (date.exdates === undefined) {
date.exdates = [];
}
date.exdates.push(date.exdate);
return date;
}
}
var geoParam = function(name){
return function(val, params, curr){
storeParam(val, params, curr)
var parts = val.split(';');
curr[name] = {lat:Number(parts[0]), lon:Number(parts[1])};
return curr
}
}
var categoriesParam = function (name) {
var separatorPattern = /\s*,\s*/g;
return function (val, params, curr) {
storeParam(val, params, curr)
if (curr[name] === undefined)
curr[name] = val ? val.split(separatorPattern) : []
else
if (val)
curr[name] = curr[name].concat(val.split(separatorPattern))
return curr
}
}
var addFBType = function(fb, params){
var p = parseParams(params);
if (params && p){
fb.type = p.FBTYPE || "BUSY"
}
return fb;
}
var freebusyParam = function (name) {
return function(val, params, curr){
var fb = addFBType({}, params);
curr[name] = curr[name] || []
curr[name].push(fb);
storeParam(val, params, fb);
var parts = val.split('/');
['start', 'end'].forEach(function (name, index) {
dateParam(name)(parts[index], params, fb);
});
return curr;
}
}
return {
objectHandlers : {
'BEGIN' : function(component, params, curr, stack){
stack.push(curr)
return {type:component, params:params}
}
, 'END' : function(component, params, curr, stack){
// prevents the need to search the root of the tree for the VCALENDAR object
if (component === "VCALENDAR") {
//scan all high level object in curr and drop all strings
var key,
obj;
for (key in curr) {
if(curr.hasOwnProperty(key)) {
obj = curr[key];
if (typeof obj === 'string') {
delete curr[key];
}
}
}
return curr
}
var par = stack.pop()
if (curr.uid)
par[curr.uid] = curr
else
par[Math.random()*100000] = curr // Randomly assign ID : TODO - use true GUID
return par
}
, 'SUMMARY' : storeParam('summary')
, 'DESCRIPTION' : storeParam('description')
, 'URL' : storeParam('url')
, 'UID' : storeParam('uid')
, 'LOCATION' : storeParam('location')
, 'DTSTART' : dateParam('start')
, 'DTEND' : dateParam('end')
, 'EXDATE' : exdateParam('exdate')
,' CLASS' : storeParam('class')
, 'TRANSP' : storeParam('transparency')
, 'GEO' : geoParam('geo')
, 'PERCENT-COMPLETE': storeParam('completion')
, 'COMPLETED': dateParam('completed')
, 'CATEGORIES': categoriesParam('categories')
, 'FREEBUSY': freebusyParam('freebusy')
},
handleObject : function(name, val, params, ctx, stack, line){
var self = this
if(self.objectHandlers[name])
return self.objectHandlers[name](val, params, ctx, stack, line)
//handling custom properties
if(name.match(/X\-[\w\-]+/) && stack.length > 0) {
//trimming the leading and perform storeParam
name = name.substring(2);
return (storeParam(name))(val, params, ctx, stack, line);
}
return storeParam(name.toLowerCase())(val, params, ctx);
},
parseICS : function(str){
var self = this
var lines = str.split(/\r?\n/)
var ctx = {}
var stack = []
for (var i = 0, ii = lines.length, l = lines[0]; i<ii; i++, l=lines[i]){
//Unfold : RFC#3.1
while (lines[i+1] && /[ \t]/.test(lines[i+1][0])) {
l += lines[i+1].slice(1)
i += 1
}
var kv = l.split(":")
if (kv.length < 2){
// Invalid line - must have k&v
continue;
}
// Although the spec says that vals with colons should be quote wrapped
// in practise nobody does, so we assume further colons are part of the
// val
var value = kv.slice(1).join(":")
, kp = kv[0].split(";")
, name = kp[0]
, params = kp.slice(1)
ctx = self.handleObject(name, value, params, ctx, stack, l) || {}
}
// type and params are added to the list of items, get rid of them.
delete ctx.type
delete ctx.params
return ctx
}
}
}))

View File

@@ -1,8 +0,0 @@
module.exports = require('./ical')
var node = require('./node-ical')
// Copy node functions across to exports
for (var i in node){
module.exports[i] = node[i]
}

View File

@@ -1,50 +0,0 @@
var ical = require('./ical')
, request = require('request')
, fs = require('fs')
exports.fromURL = function(url, opts, cb){
if (!cb)
return;
request(url, opts, function(err, r, data){
if (err)
return cb(err, null);
cb(undefined, ical.parseICS(data));
})
}
exports.parseFile = function(filename){
return ical.parseICS(fs.readFileSync(filename, 'utf8'))
}
var rrule = require('rrule-alt').RRule
var rrulestr = rrule.rrulestr
ical.objectHandlers['RRULE'] = function(val, params, curr, stack, line){
curr.rrule = line;
return curr
}
var originalEnd = ical.objectHandlers['END'];
ical.objectHandlers['END'] = function(val, params, curr, stack){
if (curr.rrule) {
var rule = curr.rrule;
if (rule.indexOf('DTSTART') === -1) {
if (curr.start.length === 8) {
var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(curr.start);
if (comps) {
curr.start = new Date (comps[1], comps[2] - 1, comps[3]);
}
}
rule += ' DTSTART:' + curr.start.toISOString().replace(/[-:]/g, '');
rule = rule.replace(/\.[0-9]{3}/, '');
}
for (var i in curr.exdates) {
rule += ' EXDATE:' + curr.exdates[i].toISOString().replace(/[-:]/g, '');
rule = rule.replace(/\.[0-9]{3}/, '');
}
curr.rrule = rrulestr(rule);
}
return originalEnd.call(this, val, params, curr, stack);
}

View File

@@ -1,28 +0,0 @@
{
"name": "ical",
"version": "0.5.0",
"main": "index.js",
"description": "A tolerant, minimal icalendar parser",
"keywords": [
"ical",
"ics",
"calendar"
],
"homepage": "https://github.com/peterbraden/ical.js",
"author": "Peter Braden <peterbraden@peterbraden.co.uk> (peterbraden.co.uk)",
"repository": {
"type": "git",
"url": "git://github.com/peterbraden/ical.js.git"
},
"dependencies": {
"request": "2.68.0",
"rrule": "2.0.0"
},
"devDependencies": {
"vows": "0.7.0",
"underscore": "1.3.0"
},
"scripts": {
"test": "./node_modules/vows/bin/vows ./test/test.js"
}
}

View File

@@ -1,51 +0,0 @@
# ical.js #
(Formerly node-ical)
[![Build Status](https://travis-ci.org/peterbraden/ical.js.png)](https://travis-ci.org/peterbraden/ical.js)
A tolerant, minimal icalendar parser for javascript/node
(http://tools.ietf.org/html/rfc5545)
## Install - Node.js ##
ical.js is availble on npm:
npm install ical
## API ##
ical.parseICS(str)
Parses a string with an ICS File
var data = ical.parseFile(filename)
Reads in the specified iCal file, parses it and returns the parsed data
ical.fromURL(url, options, function(err, data) {} )
Use the request library to fetch the specified URL (```opts``` gets passed on to the ```request()``` call), and call the function with the result (either an error or the data).
## Example 1 - Print list of upcoming node conferences (see example.js)
```javascript
var ical = require('ical')
, months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function(err, data) {
for (var k in data){
if (data.hasOwnProperty(k)) {
var ev = data[k]
console.log("Conference",
ev.summary,
'is in',
ev.location,
'on the', ev.start.getDate(), 'of', months[ev.start.getMonth()]);
}
}
});
```

View File

@@ -1,393 +0,0 @@
/****
* Tests
*
*
***/
process.env.TZ = 'America/San_Francisco';
var ical = require('../index')
var vows = require('vows')
, assert = require('assert')
, _ = require('underscore')
vows.describe('node-ical').addBatch({
'when parsing test1.ics (node conferences schedule from lanyrd.com, modified)': {
topic: function () {
return ical.parseFile('./test/test1.ics')
}
,'we get 9 events': function (topic) {
var events = _.select(_.values(topic), function(x){ return x.type==='VEVENT'})
assert.equal (events.length, 9);
}
,'event 47f6e' : {
topic: function(events){
return _.select(_.values(events),
function(x){
return x.uid ==='47f6ea3f28af2986a2192fa39a91fa7d60d26b76'})[0]
}
,'is in fort lauderdale' : function(topic){
assert.equal(topic.location, "Fort Lauderdale, United States")
}
,'starts Tue, 29 Nov 2011' : function(topic){
assert.equal(topic.start.toDateString(), new Date(2011,10,29).toDateString())
}
}
, 'event 480a' : {
topic: function(events){
return _.select(_.values(events),
function(x){
return x.uid ==='480a3ad48af5ed8965241f14920f90524f533c18'})[0]
}
, 'has a summary (invalid colon handling tolerance)' : function(topic){
assert.equal(topic.summary, '[Async]: Everything Express')
}
}
, 'event d4c8' :{
topic : function(events){
return _.select(_.values(events),
function(x){
return x.uid === 'd4c826dfb701f611416d69b4df81caf9ff80b03a'})[0]
}
, 'has a start datetime' : function(topic){
assert.equal(topic.start.toDateString(), new Date(Date.UTC(2011, 2, 12, 20, 0, 0)).toDateString())
}
}
, 'event sdfkf09fsd0 (Invalid Date)' :{
topic : function(events){
return _.select(_.values(events),
function(x){
return x.uid === 'sdfkf09fsd0'})[0]
}
, 'has a start datetime' : function(topic){
assert.equal(topic.start, "Next Year")
}
}
}
, 'with test2.ics (testing ical features)' : {
topic: function () {
return ical.parseFile('./test/test2.ics')
}
, 'todo item uid4@host1.com' : {
topic : function(items){
return items['uid4@host1.com']
}
, 'is a VTODO' : function(topic){
assert.equal(topic.type, 'VTODO')
}
}
, 'vfreebusy' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.type === 'VFREEBUSY';
})[0];
}
, 'has a URL' : function(topic) {
assert.equal(topic.url, 'http://www.host.com/calendar/busytime/jsmith.ifb');
}
}
, 'vfreebusy first freebusy' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.type === 'VFREEBUSY';
})[0].freebusy[0];
}
, 'has undefined type defaulting to busy' : function(topic) {
assert.equal(topic.type, "BUSY");
}
, 'has an start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 1998);
assert.equal(topic.start.getUTCMonth(), 2);
assert.equal(topic.start.getUTCDate(), 14);
assert.equal(topic.start.getUTCHours(), 23);
assert.equal(topic.start.getUTCMinutes(), 30);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 1998);
assert.equal(topic.end.getUTCMonth(), 2);
assert.equal(topic.end.getUTCDate(), 15);
assert.equal(topic.end.getUTCHours(), 00);
assert.equal(topic.end.getUTCMinutes(), 30);
}
}
}
, 'with test3.ics (testing tvcountdown.com)' : {
topic: function() {
return ical.parseFile('./test/test3.ics');
}
, 'event -83' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.uid === '20110505T220000Z-83@tvcountdown.com';
})[0];
}
, 'has a start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2011);
assert.equal(topic.start.getMonth(), 4);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 2011);
assert.equal(topic.end.getMonth(), 4);
}
}
}
, 'with test4.ics (testing tripit.com)' : {
topic: function() {
return ical.parseFile('./test/test4.ics');
}
, 'event c32a5...' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.uid === 'c32a5eaba2354bb29e012ec18da827db90550a3b@tripit.com';
})[0];
}
, 'has a start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2011);
assert.equal(topic.start.getMonth(), 09);
assert.equal(topic.start.getDate(), 11);
}
, 'has a summary' : function(topic){
// escaped commas and semicolons should be replaced
assert.equal(topic.summary, 'South San Francisco, CA, October 2011;')
}
, 'has a description' : function(topic){
var desired = 'John Doe is in South San Francisco, CA from Oct 11 ' +
'to Oct 13, 2011\nView and/or edit details in TripIt : http://www.tripit.c' +
'om/trip/show/id/23710889\nTripIt - organize your travel at http://www.trip' +
'it.com\n'
assert.equal(topic.description, desired)
}
, 'has a geolocation' : function(topic){
assert.ok(topic.geo, 'no geo param')
assert.equal(topic.geo.lat, 37.654656)
assert.equal(topic.geo.lon, -122.40775)
}
, 'has transparency' : function(topic){
assert.equal(topic.transparency, 'TRANSPARENT')
}
}
}
, 'with test5.ics (testing meetup.com)' : {
topic: function () {
return ical.parseFile('./test/test5.ics')
}
, 'event nsmxnyppbfc@meetup.com' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.uid === 'event_nsmxnyppbfc@meetup.com';
})[0];
}
, 'has a start' : function(topic){
assert.equal(topic.start.tz, 'America/Phoenix')
assert.equal(topic.start.toISOString(), new Date(2011, 10, 09, 19, 0,0).toISOString())
}
}
}
, 'with test6.ics (testing assembly.org)' : {
topic: function () {
return ical.parseFile('./test/test6.ics')
}
, 'event with no ID' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.summary === 'foobar Summer 2011 starts!';
})[0];
}
, 'has a start' : function(topic){
assert.equal(topic.start.toISOString(), new Date(2011, 07, 04, 12, 0,0).toISOString())
}
}
, 'event with rrule' :{
topic: function(events){
return _.select(_.values(events), function(x){
return x.summary == "foobarTV broadcast starts"
})[0];
}
, "Has an RRULE": function(topic){
assert.notEqual(topic.rrule, undefined);
}
, "RRule text": function(topic){
assert.equal(topic.rrule.toText(), "every 5 weeks on Monday, Friday until January 30, 2013")
}
}
}
, 'with test7.ics (testing dtstart of rrule)' :{
topic: function() {
return ical.parseFile('./test/test7.ics');
},
'recurring yearly event (14 july)': {
topic: function(events){
var ev = _.values(events)[0];
return ev.rrule.between(new Date(2013, 0, 1), new Date(2014, 0, 1));
},
'dt start well set': function(topic) {
assert.equal(topic[0].toDateString(), new Date(2013, 6, 14).toDateString());
}
}
}
, "with test 8.ics (VTODO completion)": {
topic: function() {
return ical.parseFile('./test/test8.ics');
},
'grabbing VTODO task': {
topic: function(topic) {
return _.values(topic)[0];
},
'task completed': function(task){
assert.equal(task.completion, 100);
assert.equal(task.completed.toISOString(), new Date(2013, 06, 16, 10, 57, 45).toISOString());
}
}
}
, "with test 9.ics (VEVENT with VALARM)": {
topic: function() {
return ical.parseFile('./test/test9.ics');
},
'grabbing VEVENT task': {
topic: function(topic) {
return _.values(topic)[0];
},
'task completed': function(task){
assert.equal(task.summary, "Event with an alarm");
}
}
}
, 'with test 11.ics (VEVENT with custom properties)': {
topic: function() {
return ical.parseFile('./test10.ics');
},
'grabbing custom properties': {
topic: function(topic) {
}
}
},
'with test10.ics': {
topic: function () {
return ical.parseFile('./test/test10.ics');
},
'when categories present': {
topic: function (t) {return _.values(t)[0]},
'should be a list': function (e) {
assert(e.categories instanceof [].constructor);
},
'should contain individual category values': function (e) {
assert.deepEqual(e.categories, ['cat1', 'cat2', 'cat3']);
}
},
'when categories present with trailing whitespace': {
topic: function (t) {return _.values(t)[1]},
'should contain individual category values without whitespace': function (e) {
assert.deepEqual(e.categories, ['cat1', 'cat2', 'cat3']);
}
},
'when categories present but empty': {
topic: function (t) {return _.values(t)[2]},
'should be an empty list': function (e) {
assert.deepEqual(e.categories, []);
}
},
'when categories present but singular': {
topic: function (t) {return _.values(t)[3]},
'should be a list of single item': function (e) {
assert.deepEqual(e.categories, ['lonely-cat']);
}
},
'when categories present on multiple lines': {
topic: function (t) {return _.values(t)[4]},
'should contain the category values in an array': function (e) {
assert.deepEqual(e.categories, ['cat1', 'cat2', 'cat3']);
}
}
},
'with test11.ics (testing zimbra freebusy)': {
topic: function () {
return ical.parseFile('./test/test11.ics');
},
'freebusy params' : {
topic: function(events) {
return _.values(events)[0];
}
, 'has a URL' : function(topic) {
assert.equal(topic.url, 'http://mail.example.com/yvr-2a@example.com/20140416');
}
, 'has an ORGANIZER' : function(topic) {
assert.equal(topic.organizer, 'mailto:yvr-2a@example.com');
}
, 'has an start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2014);
assert.equal(topic.start.getMonth(), 3);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 2014);
assert.equal(topic.end.getMonth(), 6);
}
}
, 'freebusy busy events' : {
topic: function(events) {
return _.select(_.values(events)[0].freebusy, function(x) {
return x.type === 'BUSY';
})[0];
}
, 'has an start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2014);
assert.equal(topic.start.getMonth(), 3);
assert.equal(topic.start.getUTCHours(), 15);
assert.equal(topic.start.getUTCMinutes(), 15);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 2014);
assert.equal(topic.end.getMonth(), 3);
assert.equal(topic.end.getUTCHours(), 19);
assert.equal(topic.end.getUTCMinutes(), 00);
}
}
},
'url request errors' : {
topic : function () {
ical.fromURL('http://not.exist/', {}, this.callback);
}
, 'are passed back to the callback' : function (err, result) {
assert.instanceOf(err, Error);
if (!err){
console.log(">E:", err, result)
}
}
}
}).export(module)
//ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics',
// {},
// function(err, data){
// console.log("OUT:", data)
// })

View File

@@ -1,78 +0,0 @@
BEGIN:VCALENDAR
PRODID:-//lanyrd.com//Lanyrd//EN
X-ORIGINAL-URL:http://lanyrd.com/topics/nodejs/nodejs.ics
X-WR-CALNAME;CHARSET=utf-8:Node.js conferences
VERSION:2.0
METHOD:PUBLISH
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Dyncon 2011
LOCATION;CHARSET=utf-8:Stockholm, Sweden
URL:http://lanyrd.com/2011/dyncon/
UID:d4c826dfb701f611416d69b4df81caf9ff80b03a
DTSTART:20110312T200000Z
DTEND;VALUE=DATE:20110314
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:[Async]: Everything Express
LOCATION;CHARSET=utf-8:Brighton, United Kingdom
URL:http://lanyrd.com/2011/asyncjs-express/
UID:480a3ad48af5ed8965241f14920f90524f533c18
DTSTART;VALUE=DATE:20110324
DTEND;VALUE=DATE:20110325
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:JSConf US 2011
LOCATION;CHARSET=utf-8:Portland, United States
URL:http://lanyrd.com/2011/jsconf/
UID:ed334cc85db5ebdff5ff5a630a7a48631a677dbe
DTSTART;VALUE=DATE:20110502
DTEND;VALUE=DATE:20110504
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:NodeConf 2011
LOCATION;CHARSET=utf-8:Portland, United States
URL:http://lanyrd.com/2011/nodeconf/
UID:25169a7b1ba5c248278f47120a40878055dc8c15
DTSTART;VALUE=DATE:20110505
DTEND;VALUE=DATE:20110506
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:BrazilJS
LOCATION;CHARSET=utf-8:Fortaleza, Brazil
URL:http://lanyrd.com/2011/braziljs/
UID:dafee3be83624f3388c5635662229ff11766bb9c
DTSTART;VALUE=DATE:20110513
DTEND;VALUE=DATE:20110515
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Falsy Values
LOCATION;CHARSET=utf-8:Warsaw, Poland
URL:http://lanyrd.com/2011/falsy-values/
UID:73cad6a09ac4e7310979c6130f871d17d990b5ad
DTSTART;VALUE=DATE:20110518
DTEND;VALUE=DATE:20110521
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:nodecamp.eu
LOCATION;CHARSET=utf-8:Cologne, Germany
URL:http://lanyrd.com/2011/nodecampde/
UID:b728a5fdb5f292b6293e4a2fd97a1ccfc69e9d6f
DTSTART;VALUE=DATE:20110611
DTEND;VALUE=DATE:20110613
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Rich Web Experience 2011
LOCATION;CHARSET=utf-8:Fort Lauderdale, United States
URL:http://lanyrd.com/2011/rich-web-experience/
UID:47f6ea3f28af2986a2192fa39a91fa7d60d26b76
DTSTART;VALUE=DATE:20111129
DTEND;VALUE=DATE:20111203
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Foobar
UID:sdfkf09fsd0
DTSTART;VALUE=DATE:Next Year
DTEND;VALUE=DATE:20111203
END:VEVENT
END:VCALENDAR

View File

@@ -1,34 +0,0 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:1
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:cat1,cat2,cat3
END:VEVENT
BEGIN:VEVENT
UID:2
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:cat1 , cat2, cat3
END:VEVENT
BEGIN:VEVENT
UID:3
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:
END:VEVENT
BEGIN:VEVENT
UID:4
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:lonely-cat
END:VEVENT
BEGIN:VEVENT
UID:5
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:cat1
CATEGORIES:cat2
CATEGORIES:cat3
END:VEVENT
END:VCALENDAR

View File

@@ -1,41 +0,0 @@
BEGIN:VCALENDAR
PRODID:Zimbra-Calendar-Provider
VERSION:2.0
METHOD:PUBLISH
BEGIN:VFREEBUSY
ORGANIZER:mailto:yvr-2a@example.com
DTSTAMP:20140516T235436Z
DTSTART:20140415T235436Z
DTEND:20140717T235436Z
URL:http://mail.example.com/yvr-2a@example.com/20140416
FREEBUSY;FBTYPE=BUSY:20140416T151500Z/20140416T190000Z
FREEBUSY;FBTYPE=BUSY:20140416T195500Z/20140416T231500Z
FREEBUSY;FBTYPE=BUSY:20140417T193000Z/20140417T203000Z
FREEBUSY;FBTYPE=BUSY:20140421T210000Z/20140421T213000Z
FREEBUSY;FBTYPE=BUSY:20140423T180000Z/20140423T190000Z
FREEBUSY;FBTYPE=BUSY:20140423T200000Z/20140423T210000Z
FREEBUSY;FBTYPE=BUSY:20140423T223500Z/20140423T231500Z
FREEBUSY;FBTYPE=BUSY:20140424T155000Z/20140424T165500Z
FREEBUSY;FBTYPE=BUSY:20140424T170000Z/20140424T183000Z
FREEBUSY;FBTYPE=BUSY:20140424T195000Z/20140424T230000Z
FREEBUSY;FBTYPE=BUSY:20140425T144500Z/20140425T161500Z
FREEBUSY;FBTYPE=BUSY:20140425T180000Z/20140425T194500Z
FREEBUSY;FBTYPE=BUSY:20140425T223000Z/20140425T230000Z
FREEBUSY;FBTYPE=BUSY:20140428T151500Z/20140428T163000Z
FREEBUSY;FBTYPE=BUSY:20140428T170000Z/20140428T173000Z
FREEBUSY;FBTYPE=BUSY:20140428T195500Z/20140428T213000Z
FREEBUSY;FBTYPE=BUSY:20140428T231000Z/20140428T234000Z
FREEBUSY;FBTYPE=BUSY:20140429T152500Z/20140429T170000Z
FREEBUSY;FBTYPE=BUSY:20140429T180000Z/20140429T183000Z
FREEBUSY;FBTYPE=BUSY:20140429T201500Z/20140429T230000Z
FREEBUSY;FBTYPE=BUSY:20140430T162500Z/20140430T165500Z
FREEBUSY;FBTYPE=BUSY:20140430T180000Z/20140430T190000Z
FREEBUSY;FBTYPE=BUSY:20140501T170000Z/20140501T173000Z
FREEBUSY;FBTYPE=BUSY:20140501T175000Z/20140501T190000Z
FREEBUSY;FBTYPE=BUSY:20140501T232000Z/20140501T235000Z
FREEBUSY;FBTYPE=BUSY:20140502T163500Z/20140502T173000Z
FREEBUSY;FBTYPE=BUSY:20140505T165500Z/20140505T173000Z
FREEBUSY;FBTYPE=BUSY:20140505T201500Z/20140505T203000Z
FREEBUSY;FBTYPE=BUSY:20140505T210000Z/20140505T213000Z
END:VFREEBUSY
END:VCALENDAR

View File

@@ -1,83 +0,0 @@
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
X-WR-TIMEZONE;VALUE=TEXT:US/Pacific
METHOD:PUBLISH
PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
X-WR-CALNAME;VALUE=TEXT:Example
VERSION:2.0
BEGIN:VEVENT
SEQUENCE:5
DTSTART;TZID=US/Pacific:20021028T140000
DTSTAMP:20021028T011706Z
SUMMARY:Coffee with Jason
UID:EC9439B1-FF65-11D6-9973-003065F99D04
DTEND;TZID=US/Pacific:20021028T150000
END:VEVENT
BEGIN:VALARM
TRIGGER;VALUE=DURATION:-P1D
ACTION:DISPLAY
DESCRIPTION:Event reminder
END:VALARM
BEGIN:VEVENT
SEQUENCE:1
DTSTAMP:20021128T012034Z
SUMMARY:Code Review
UID:EC944331-FF65-11D6-9973-003065F99D04
DTSTART;TZID=US/Pacific:20021127T120000
DURATION:PT1H
END:VEVENT
BEGIN:VEVENT
SEQUENCE:1
DTSTAMP:20021028T012034Z
SUMMARY:Dinner with T
UID:EC944CFA-FF65-11D6-9973-003065F99D04
DTSTART;TZID=US/Pacific:20021216T200000
DURATION:PT1H
END:VEVENT
BEGIN:VTODO
DTSTAMP:19980130T134500Z
SEQUENCE:2
UID:uid4@host1.com
ORGANIZER:MAILTO:unclesam@us.gov
ATTENDEE;PARTSTAT=ACCEPTED:MAILTO:jqpublic@host.com
DUE:19980415T235959
STATUS:NEEDS-ACTION
SUMMARY:Submit Income Taxes
END:VTODO
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:19980403T120000
ATTACH;FMTTYPE=audio/basic:http://host.com/pub/audio-
files/ssbanner.aud
REPEAT:4
DURATION:PT1H
END:VALARM
BEGIN:VJOURNAL
DTSTAMP:19970324T120000Z
UID:uid5@host1.com
ORGANIZER:MAILTO:jsmith@host.com
STATUS:DRAFT
CLASS:PUBLIC
CATEGORY:Project Report, XYZ, Weekly Meeting
DESCRIPTION:Project xyz Review Meeting Minutes\n
Agenda\n1. Review of project version 1.0 requirements.\n2.
Definition
of project processes.\n3. Review of project schedule.\n
Participants: John Smith, Jane Doe, Jim Dandy\n-It was
decided that the requirements need to be signed off by
product marketing.\n-Project processes were accepted.\n
-Project schedule needs to account for scheduled holidays
and employee vacation time. Check with HR for specific
dates.\n-New schedule will be distributed by Friday.\n-
Next weeks meeting is cancelled. No meeting until 3/23.
END:VJOURNAL
BEGIN:VFREEBUSY
ORGANIZER:MAILTO:jsmith@host.com
DTSTART:19980313T141711Z
DTEND:19980410T141711Z
FREEBUSY:19980314T233000Z/19980315T003000Z
FREEBUSY:19980316T153000Z/19980316T163000Z
FREEBUSY:19980318T030000Z/19980318T040000Z
URL:http://www.host.com/calendar/busytime/jsmith.ifb
END:VFREEBUSY
END:VCALENDAR

View File

@@ -1,226 +0,0 @@
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:tvcountdown.com
X-WR-CALNAME:tvcountdown.com
VERSION:2.0
METHOD:PUBLISH
X-WR-TIMEZONE:US/Eastern
X-WR-CALNAME;VALUE=TEXT:tvcountdown.com
X-WR-CALDESC:
BEGIN:VEVENT
UID:20110519T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110519T200000
DTEND;VALUE=DATE-TIME:20110519T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E24 - The Roomate Transmogrfication
END:VEVENT
BEGIN:VEVENT
UID:20110512T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110512T200000
DTEND;VALUE=DATE-TIME:20110512T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E23 - The Engagement Reaction
END:VEVENT
BEGIN:VEVENT
UID:20110505T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110505T220000
DTEND;VALUE=DATE-TIME:20110505T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E23 - Respawn
END:VEVENT
BEGIN:VEVENT
UID:20110505T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110505T200000
DTEND;VALUE=DATE-TIME:20110505T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E22 - The Wildebeest Implementation
END:VEVENT
BEGIN:VEVENT
UID:20110504T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110504T230000
DTEND;VALUE=DATE-TIME:20110504T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E59 - David Barton
END:VEVENT
BEGIN:VEVENT
UID:20110503T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110503T230000
DTEND;VALUE=DATE-TIME:20110503T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E58 - Rachel Maddow
END:VEVENT
BEGIN:VEVENT
UID:20110502T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110502T230000
DTEND;VALUE=DATE-TIME:20110502T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E57 - Philip K. Howard
END:VEVENT
BEGIN:VEVENT
UID:20110428T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110428T230000
DTEND;VALUE=DATE-TIME:20110428T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E56 - William Cohan
END:VEVENT
BEGIN:VEVENT
UID:20110428T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110428T220000
DTEND;VALUE=DATE-TIME:20110428T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E22 - Everything Sunny All the Time Always
END:VEVENT
BEGIN:VEVENT
UID:20110428T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110428T200000
DTEND;VALUE=DATE-TIME:20110428T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E21 - The Agreement Dissection
END:VEVENT
BEGIN:VEVENT
UID:20110427T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110427T230000
DTEND;VALUE=DATE-TIME:20110427T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E55 - Sen. Bernie Sanders
END:VEVENT
BEGIN:VEVENT
UID:20110426T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110426T230000
DTEND;VALUE=DATE-TIME:20110426T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E54 - Elizabeth Warren
END:VEVENT
BEGIN:VEVENT
UID:20110425T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110425T230000
DTEND;VALUE=DATE-TIME:20110425T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E53 - Gigi Ibrahim
END:VEVENT
BEGIN:VEVENT
UID:20110421T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110421T220000
DTEND;VALUE=DATE-TIME:20110421T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E21 - 100th Episode Part 2 of 2
END:VEVENT
BEGIN:VEVENT
UID:20110421T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110421T220000
DTEND;VALUE=DATE-TIME:20110421T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E20 - 100th Episode Part 1 of 2
END:VEVENT
BEGIN:VEVENT
UID:20110414T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110414T230000
DTEND;VALUE=DATE-TIME:20110414T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E52 - Ricky Gervais
END:VEVENT
BEGIN:VEVENT
UID:20110414T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110414T220000
DTEND;VALUE=DATE-TIME:20110414T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E19 - I Heart Connecticut
END:VEVENT
BEGIN:VEVENT
UID:20110413T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110413T230000
DTEND;VALUE=DATE-TIME:20110413T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E51 - Tracy Morgan
END:VEVENT
BEGIN:VEVENT
UID:20110412T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110412T230000
DTEND;VALUE=DATE-TIME:20110412T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E50 - Gov. Deval Patrick
END:VEVENT
BEGIN:VEVENT
UID:20110411T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110411T230000
DTEND;VALUE=DATE-TIME:20110411T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E49 - Foo Fighters
END:VEVENT
BEGIN:VEVENT
UID:20110407T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110407T230000
DTEND;VALUE=DATE-TIME:20110407T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E48 - Jamie Oliver
END:VEVENT
BEGIN:VEVENT
UID:20110407T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110407T200000
DTEND;VALUE=DATE-TIME:20110407T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E20 - The Herb Garden Germination
END:VEVENT
BEGIN:VEVENT
UID:20110406T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110406T230000
DTEND;VALUE=DATE-TIME:20110406T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E47 - Mike Huckabee
END:VEVENT
BEGIN:VEVENT
UID:20110405T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110405T230000
DTEND;VALUE=DATE-TIME:20110405T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E46 - Colin Quinn
END:VEVENT
BEGIN:VEVENT
UID:20110404T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110404T230000
DTEND;VALUE=DATE-TIME:20110404T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E45 - Billy Crystal
END:VEVENT
BEGIN:VEVENT
UID:20110331T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110331T230000
DTEND;VALUE=DATE-TIME:20110331T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E44 - Norm MacDonald
END:VEVENT
BEGIN:VEVENT
UID:20110331T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110331T200000
DTEND;VALUE=DATE-TIME:20110331T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E19 - The Zarnecki Incursion
END:VEVENT
END:VCALENDAR

View File

@@ -1,747 +0,0 @@
BEGIN:VCALENDAR
X-WR-CALNAME:John Doe (TripIt)
X-WR-CALDESC:TripIt Calendar
X-PUBLISHED-TTL:PT15M
PRODID:-//John Doe/NONSGML Bennu 0.1//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:c32a5eaba2354bb29e012ec18da827db90550a3b@tripit.com
DTSTART;VALUE=DATE:20111011
DTEND;VALUE=DATE:20111014
SUMMARY:South San Francisco\, CA\, October 2011\;
LOCATION:South San Francisco\, CA
GEO:37.654656;-122.40775
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in South San Francisco\, CA from Oct 11
to Oct 13\, 2011\nView and/or edit details in TripIt : http://www.tripit.c
om/trip/show/id/23710889\nTripIt - organize your travel at http://www.trip
it.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
TRANSP:TRANSPARENT
UID:item-ee275ccffa83f492d9eb63b01953b39f18d4f944@tripit.com
DTSTART:20111011T100500
DTEND:20111011T110500
SUMMARY:Directions from SFO to Embassy Suites San Francisco Airport - Sout
h San Francisco
LOCATION:250 GATEWAY BLVD\, South San Francisco\, CA\, 94080
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/1234\n \n[Directions] 10/11/2011 10:05am - Directions from S
FO to Embassy Suites San Francisco Airport - South San Francisco \nfrom: S
FO \nto: 250 GATEWAY BLVD\, South San Francisco\, CA\, 94080 \nView direct
ions here: http://maps.google.com/maps?output=mobile&saddr=SFO&daddr=250+G
ATEWAY+BLVD%2C+South+San+Francisco%2C+CA%2C+94080 \n \n \n\nTripIt - organ
ize your travel at http://www.tripit.com
GEO:37.655634;-122.401273
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111011T165500Z
SUMMARY:US403 PHX to SFO
LOCATION:Phoenix (PHX)
UID:item-c576afd397cf1f90578b4ba35e781b61ba8897db@tripit.com
DTSTART:20111011T144500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/1234\n \n[Flight] 10/11/2011 US Airways(US) #403 dep PHX 7:4
5am MST arr SFO 9:55am PDT\; John Doe\; seat(s) 8B\; conf #DXH9K
Z\, BXQ9WH \nBooked on http://www.americanexpress-travel.com/\; Reference
#: 4127 8626 9715\; http://www.americanexpress-travel.com/\; US:1-800-297-
2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at htt
p://www.tripit.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-e99a90ee1c7e4f5b68a4e551009e5bb6c475940c@tripit.com
DTSTART:20111011T172500Z
DTEND:20111011T182500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/1234\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #R9508361 \np
ickup 10/11/2011 10:25am\; dropoff 10/13/2011 6:49pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4127 8626 9715\; ht
tp://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582
-2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Embassy Suites San Francisco Airport - South San Francis
co
TRANSP:TRANSPARENT
UID:item-7f3288d418bed063cc82b4512e792fbb5d8ae761@tripit.com
DTSTART:20111011T185500Z
DTEND:20111011T195500Z
LOCATION:250 GATEWAY BLVD\, South San Francisco\, CA\, 94080
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Lodging] Embassy Suites San Francisco Airport - So
uth San Francisco\; primary guest John Doe\; conf #R9508361 \n25
0 GATEWAY BLVD\, South San Francisco\, CA\, 94080\; tel 1.650.589.3400 \na
rrive 10/11/2011\; depart 10/13/2011\; rooms: 1 \nBooked on http://www.ame
ricanexpress-travel.com/\; Reference #: 4127 8626 9715\; http://www.americ
anexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n \n \n\
nTripIt - organize your travel at http://www.tripit.com
GEO:37.655634;-122.401273
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Embassy Suites San Francisco Airport - South San Franci
sco
TRANSP:TRANSPARENT
UID:item-5eb4cb5fc25c55b0423921e18336e57f8c34598d@tripit.com
DTSTART:20111014T011900Z
DTEND:20111014T021900Z
LOCATION:250 GATEWAY BLVD\, South San Francisco\, CA\, 94080
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Lodging] Embassy Suites San Francisco Airport - So
uth San Francisco\; primary guest John Doe\; conf #R9508361 \n25
0 GATEWAY BLVD\, South San Francisco\, CA\, 94080\; tel 1.650.589.3400 \na
rrive 10/11/2011\; depart 10/13/2011\; rooms: 1 \nBooked on http://www.ame
ricanexpress-travel.com/\; Reference #: 4127 8626 9715\; http://www.americ
anexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n \n \n\
nTripIt - organize your travel at http://www.tripit.com
GEO:37.655634;-122.401273
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-11fdbf5d02e84646025716d9f9c7a4158e1fb025@tripit.com
DTSTART:20111014T014900Z
DTEND:20111014T024900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #R9508361 \np
ickup 10/11/2011 10:25am\; dropoff 10/13/2011 6:49pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4127 8626 9715\; ht
tp://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582
-2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111014T051900Z
SUMMARY:CO6256 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-cb485a571a01972d6bdc74c2b829905d6e3786bf@tripit.com
DTSTART:20111014T031900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Flight] 10/13/2011 Continental Airlines(CO) #6256
dep SFO 8:19pm PDT arr PHX 10:19pm MST\; John Doe\; conf #DXH9KZ
\, BXQ9WH(Operated by United Airlines flight 6256) \nBooked on http://www.
americanexpress-travel.com/\; Reference #: 4127 8626 9715\; http://www.ame
ricanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n \n
\n\nTripIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:c7b133db1e7be2713a4a63b75dcbad209690cab5@tripit.com
DTSTART;VALUE=DATE:20111023
DTEND;VALUE=DATE:20111028
SUMMARY:Santa Barbara\, CA\, October 2011
LOCATION:Santa Barbara\, CA
GEO:34.420831;-119.69819
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in Santa Barbara\, CA from Oct 23 to Oct
27\, 2011\nView and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\nTripIt - organize your travel at http://www.tripit.com
\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111023T191200Z
SUMMARY:US2719 PHX to SBA
LOCATION:Phoenix (PHX)
UID:item-c4375369e9070fcc04df39ed18c4d93087577591@tripit.com
DTSTART:20111023T173500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Flight] 10/23/2011 US Airways(US) #2719 dep PHX 10
:35am MST arr SBA 12:12pm PDT\; John Doe Ticket #0378717202638\;
conf #A44XS5\, PRX98G\, FYYJZ4 \nBooked on http://www.americanexpress-tra
vel.com/\; Reference #: 7128 8086 8504\; http://www.americanexpress-travel
.com/\; US:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $699.99 \n
\n \n\nTripIt - organize your travel at http://www.tripit.com
GEO:34.427778;-119.839444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
TRANSP:TRANSPARENT
UID:item-962e4f045d12149319d1837ec096bf43770abd6e@tripit.com
DTSTART:20111025T094000
DTEND:20111025T104000
SUMMARY:Directions from Hertz to Sofitel San Francisco Bay
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Directions] 10/25/2011 9:40am - Directions from He
rtz to Sofitel San Francisco Bay \nfrom: 780 McDonnell Road\, San Francisc
o\, CA\, 94128 \nto: 223 Twin Dolphin Drive\, Redwood City\, CA\, 94065 \n
View directions here: http://maps.google.com/maps?output=mobile&saddr=780+
McDonnell+Road%2C+San+Francisco%2C+CA%2C+94128&daddr=223+Twin+Dolphin+Driv
e%2C+Redwood+City%2C+CA%2C+94065 \n \n \n\nTripIt - organize your travel a
t http://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111025T162600Z
SUMMARY:UA5304 SBA to SFO
LOCATION:Santa Barbara (SBA)
UID:item-ae300a6934c3820974dba2c9c5b8fae843c67693@tripit.com
DTSTART:20111025T150900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Flight] 10/25/2011 United Airlines(UA) #5304 dep S
BA 8:09am PDT arr SFO 9:26am PDT\; John Doe Ticket #037871720263
8\; seat(s) 11B\; conf #A44XS5\, PRX98G\, FYYJZ4 \nBooked on http://www.am
ericanexpress-travel.com/\; Reference #: 7128 8086 8504\; http://www.ameri
canexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716\; Total
Cost: $699.99 \n \n \n\nTripIt - organize your travel at http://www.tripit
.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Hertz
TRANSP:TRANSPARENT
UID:item-2a9fd5a57a4cdda4677fc6ce23738e1954fdbe2a@tripit.com
DTSTART:20111025T163000Z
DTEND:20111025T173000Z
LOCATION:780 McDonnell Road\, San Francisco\, CA\, 94128
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Car Rental] Hertz\; San Francisco International Ai
rport\; primary driver John Doe\; conf #F2633064194 \n780 McDonn
ell Road\, San Francisco\, CA\, 94128 \npickup 10/25/2011 9:30am\; dropoff
10/27/2011 7:00pm \nToyota Corolla or similar\; 84.57 USD \nBooked on htt
p://www.hertz.com/\; Reference #: F2633064194\; http://www.hertz.com/\; 80
0-654-3131\; Booking Rate: 84.57 USD\; Total Cost: 333.76 USD \n \n \n\nTr
ipIt - organize your travel at http://www.tripit.com
GEO:37.6297569;-122.4000351
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
TRANSP:TRANSPARENT
UID:item-98dfcb0bcfdcffcce9c58a84947212ed67cadda6@tripit.com
DTSTART:20111025T163600Z
DTEND:20111025T173600Z
SUMMARY:Directions from SFO to Sofitel San Francisco Bay
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Directions] 10/25/2011 9:36am - Directions from SF
O to Sofitel San Francisco Bay \nfrom: SFO \nto: 223 Twin Dolphin Drive\,
Redwood City\, CA\, 94065 \nView directions here: http://maps.google.com/m
aps?output=mobile&saddr=SFO&daddr=223+Twin+Dolphin+Drive%2C+Redwood+City%2
C+CA%2C+94065 \n \n \n\nTripIt - organize your travel at http://www.tripit
.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-8de3937b336c333faf2d55ad0a41c5ca6cc02393@tripit.com
DTSTART:20111025T220000Z
DTEND:20111025T230000Z
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #F80-0GMW \n223 Twin Dolphin Drive\, Redwood Ci
ty\, CA\, 94065\; tel (+1)650/598-9000 \narrive 10/25/2011\; depart 10/27/
2011\; rooms: 1 \nBooked on http://www.sofitel.com/\; http://www.sofitel.c
om/\; Total Cost: 564.00 USD \n \n \n\nTripIt - organize your travel at ht
tp://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-f3ade58646964bde101616a6d26ea7784a1a81e8@tripit.com
DTSTART:20111027T190000Z
DTEND:20111027T200000Z
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #F80-0GMW \n223 Twin Dolphin Drive\, Redwood Ci
ty\, CA\, 94065\; tel (+1)650/598-9000 \narrive 10/25/2011\; depart 10/27/
2011\; rooms: 1 \nBooked on http://www.sofitel.com/\; http://www.sofitel.c
om/\; Total Cost: 564.00 USD \n \n \n\nTripIt - organize your travel at ht
tp://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Hertz
TRANSP:TRANSPARENT
UID:item-50620273fea0614d37775649034d5e1de92ae361@tripit.com
DTSTART:20111028T020000Z
DTEND:20111028T030000Z
LOCATION:780 McDonnell Road\, San Francisco\, CA\, 94128
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Car Rental] Hertz\; San Francisco International Ai
rport\; primary driver John Doe\; conf #F2633064194 \n780 McDonn
ell Road\, San Francisco\, CA\, 94128 \npickup 10/25/2011 9:30am\; dropoff
10/27/2011 7:00pm \nToyota Corolla or similar\; 84.57 USD \nBooked on htt
p://www.hertz.com/\; Reference #: F2633064194\; http://www.hertz.com/\; 80
0-654-3131\; Booking Rate: 84.57 USD\; Total Cost: 333.76 USD \n \n \n\nTr
ipIt - organize your travel at http://www.tripit.com
GEO:37.6297569;-122.4000351
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111028T051900Z
SUMMARY:CO6256 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-71d327f30d8beeaf7bf50c8fa63ce16005b9b0df@tripit.com
DTSTART:20111028T031900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Flight] 10/27/2011 Continental Airlines(CO) #6256
dep SFO 8:19pm PDT arr PHX 10:19pm MST\; John Doe Ticket #037871
7202638\; seat(s) 17D\; conf #A44XS5\, PRX98G\, FYYJZ4(Operated by United
Airlines flight 6256) \nBooked on http://www.americanexpress-travel.com/\;
Reference #: 7128 8086 8504\; http://www.americanexpress-travel.com/\; US
:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $699.99 \n \n \n\nTri
pIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:2d4b446e63a94ade7dab0f0e9546b2d1965f011c@tripit.com
DTSTART;VALUE=DATE:20111108
DTEND;VALUE=DATE:20111111
SUMMARY:Redwood City\, CA\, November 2011
LOCATION:Redwood City\, CA
GEO:37.485215;-122.236355
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in Redwood City\, CA from Nov 8 to Nov 1
0\, 2011\nView and/or edit details in TripIt : http://www.tripit.com/trip/
show/id/24913749\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111108T175700Z
SUMMARY:US403 PHX to SFO
LOCATION:Phoenix (PHX)
UID:item-7de7d829b2f95991de6d01c3d68f24b84770168c@tripit.com
DTSTART:20111108T154500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Flight] 11/8/2011 US Airways(US) #403 dep PHX 8:45
am MST arr SFO 9:57am PST\; John Doe\; seat(s) 21C\; conf #FJDX0
J\, I2W8HW \nBooked on http://www.americanexpress-travel.com/\; Reference
#: 4129 9623 4732\; http://www.americanexpress-travel.com/\; US:1-800-297-
2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at htt
p://www.tripit.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-1ac6982fefdd79bc5ea849785f415a6291c450b1@tripit.com
DTSTART:20111108T182700Z
DTEND:20111108T192700Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #Q0058133 \np
ickup 11/8/2011 10:27am\; dropoff 11/10/2011 6:25pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4129 9623 4732\; htt
p://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-
2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-126e584ffbefbec32a15ca503f0bdf8d3f9cc2f4@tripit.com
DTSTART:20111108T195700Z
DTEND:20111108T205700Z
LOCATION:223 TWIN DOLPHIN DR\, Redwood City\, CA\, 94065-1514
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #Q0058133 \n223 TWIN DOLPHIN DR\, Redwood City\
, CA\, 94065-1514\; tel 1.650.598.9000 \narrive 11/8/2011\; depart 11/10/2
011\; rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Refere
nce #: 4129 9623 4732\; http://www.americanexpress-travel.com/\; US:1-800-
297-2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at
http://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-ff48c502022356ccaa862ebb61761a0de08a1ce9@tripit.com
DTSTART:20111111T015500Z
DTEND:20111111T025500Z
LOCATION:223 TWIN DOLPHIN DR\, Redwood City\, CA\, 94065-1514
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #Q0058133 \n223 TWIN DOLPHIN DR\, Redwood City\
, CA\, 94065-1514\; tel 1.650.598.9000 \narrive 11/8/2011\; depart 11/10/2
011\; rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Refere
nce #: 4129 9623 4732\; http://www.americanexpress-travel.com/\; US:1-800-
297-2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at
http://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-c0273c03ddbb68a9b05d5d43a489bc318136ca42@tripit.com
DTSTART:20111111T022500Z
DTEND:20111111T032500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #Q0058133 \np
ickup 11/8/2011 10:27am\; dropoff 11/10/2011 6:25pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4129 9623 4732\; htt
p://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-
2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111111T055400Z
SUMMARY:CO496 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-3473cf9275326ac393b37859df3b04306b4849aa@tripit.com
DTSTART:20111111T035500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Flight] 11/10/2011 Continental Airlines(CO) #496 d
ep SFO 7:55pm PST arr PHX 10:54pm MST\; John Doe\; seat(s) 26B\;
conf #FJDX0J\, I2W8HW(Operated by United Airlines flight 496) \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4129 9623 4732\; ht
tp://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582
-2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:4ee5ded058432990e3d8808f48ca851e04923b6d@tripit.com
DTSTART;VALUE=DATE:20111129
DTEND;VALUE=DATE:20111202
SUMMARY:Milpitas\, CA\, November 2011
LOCATION:Milpitas\, CA
GEO:37.428272;-121.906624
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in Milpitas\, CA from Nov 29 to Dec 1\,
2011\nView and/or edit details in TripIt : http://www.tripit.com/trip/show
/id/25671681\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111129T172400Z
SUMMARY:US282 PHX to SJC
LOCATION:Phoenix (PHX)
UID:item-644d5973b50d521d50e475ccf5321605d54bd0d5@tripit.com
DTSTART:20111129T152500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Flight] 11/29/2011 US Airways(US) #282 dep PHX 8:2
5am MST arr SJC 9:24am PST\; John Doe\; seat(s) 17C\; conf #DQKD
GY \nBooked on http://www.americanexpress-travel.com/\; Reference #: 4131
3301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2977\, O
utside:210-582-2716 \n \n \n\nTripIt - organize your travel at http://www.
tripit.com
GEO:37.361111;-121.925556
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-10368bbdbc9b6f26f83098500633cc4eb604c751@tripit.com
DTSTART:20111129T175400Z
DTEND:20111129T185400Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Car Rental] Alamo\; San Jose International Airport
\; primary driver John Doe\; conf #372828149COUNT \npickup 11/29
/2011 9:54am\; dropoff 12/1/2011 5:45pm \nIntermediate \nBooked on http://
www.americanexpress-travel.com/\; Reference #: 4131 3301 9911\; http://www
.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n
\n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: The Beverly Heritage Hotel
TRANSP:TRANSPARENT
UID:item-98d8638d3f1c011d03cb8f58b3a14a0f1203339b@tripit.com
DTSTART:20111129T192400Z
DTEND:20111129T202400Z
LOCATION:1820 Barber Lane\, Milpitas\, CA\, 95035
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Lodging] The Beverly Heritage Hotel\; primary gues
t John Doe\; conf #372828149COUNT \n1820 Barber Lane\, Milpitas\
, CA\, 95035\; tel 1.408.943.9080 \narrive 11/29/2011\; depart 12/1/2011\;
rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Reference #
: 4131 3301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2
977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at http
://www.tripit.com
GEO:37.4010467;-121.9116284
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111201T194400Z
SUMMARY:US273 SJC to PHX
LOCATION:San Jose (SJC)
UID:item-7b9ee9bb4edfe69743e32b33f9be55753956a883@tripit.com
DTSTART:20111201T175900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Flight] 12/1/2011 US Airways(US) #273 dep SJC 9:59
am PST arr PHX 12:44pm MST\; John Doe Ticket #0378727451156\; co
nf #EMF71T \nBooked on http://www.americanexpress-travel.com/\; Reference
#: 5133 5264 1627\; http://www.americanexpress-travel.com/\; US:1-800-297-
2977\, Outside:210-582-2716\; Total Cost: $316.69 \n \n \n\nTripIt - organ
ize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: The Beverly Heritage Hotel
TRANSP:TRANSPARENT
UID:item-f79f203072002b8f06598dcb2be0e36af17b625b@tripit.com
DTSTART:20111202T011500Z
DTEND:20111202T021500Z
LOCATION:1820 Barber Lane\, Milpitas\, CA\, 95035
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Lodging] The Beverly Heritage Hotel\; primary gues
t John Doe\; conf #372828149COUNT \n1820 Barber Lane\, Milpitas\
, CA\, 95035\; tel 1.408.943.9080 \narrive 11/29/2011\; depart 12/1/2011\;
rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Reference #
: 4131 3301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2
977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at http
://www.tripit.com
GEO:37.4010467;-121.9116284
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-69f526ad49fa8ca0a74486f4fc77cc3f9d23a72f@tripit.com
DTSTART:20111202T014500Z
DTEND:20111202T024500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Car Rental] Alamo\; San Jose International Airport
\; primary driver John Doe\; conf #372828149COUNT \npickup 11/29
/2011 9:54am\; dropoff 12/1/2011 5:45pm \nIntermediate \nBooked on http://
www.americanexpress-travel.com/\; Reference #: 4131 3301 9911\; http://www
.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n
\n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111202T045900Z
SUMMARY:US288 SJC to PHX
LOCATION:San Jose (SJC)
UID:item-dab68a87c8dd49064ab0ba1dec5ba75ba46ff1d3@tripit.com
DTSTART:20111202T031500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Flight] 12/1/2011 US Airways(US) #288 dep SJC 7:15
pm PST arr PHX 9:59pm MST\; John Doe\; seat(s) 13C\; conf #DQKDG
Y \nBooked on http://www.americanexpress-travel.com/\; Reference #: 4131 3
301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2977\, Ou
tside:210-582-2716 \n \n \n\nTripIt - organize your travel at http://www.t
ripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:67d48ddde166a2e9bbac2cf7d93fe493b0860008@tripit.com
DTSTART;VALUE=DATE:20111213
DTEND;VALUE=DATE:20111216
SUMMARY:San Jose\, CA\, December 2011
LOCATION:San Jose\, CA
GEO:37.339386;-121.894955
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in San Jose\, CA from Dec 13 to Dec 15\,
2011\nView and/or edit details in TripIt : http://www.tripit.com/trip/sho
w/id/27037117\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111213T172400Z
SUMMARY:US282 PHX to SJC
LOCATION:Phoenix (PHX)
UID:item-2b1b9021be548a87dd335f190b60ab78c33b619d@tripit.com
DTSTART:20111213T152500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Flight] 12/13/2011 US Airways(US) #282 dep PHX 8:2
5am MST arr SJC 9:24am PST\; John Doe Ticket #0378728465928\; se
at(s) 15C\; conf #GGNV29 \nBooked on http://www.americanexpress-travel.com
/\; Reference #: 3134 0525 5102\; http://www.americanexpress-travel.com/\;
US:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $406.39 \n \n \n\n
TripIt - organize your travel at http://www.tripit.com
GEO:37.361111;-121.925556
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Advantage
TRANSP:TRANSPARENT
UID:item-619d345bb08aaef68e8767b672277243697f5bff@tripit.com
DTSTART:20111213T180000Z
DTEND:20111213T190000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Car Rental] Advantage\; San Jose International Air
port\; primary driver John Doe\; conf #F31539020E7 \npickup 12/1
3/2011 10:00am\; dropoff 12/15/2011 7:00pm \nStandard Convertible \nRefere
nce #: 3134 0526 3890 \n \n \n\nTripIt - organize your travel at http://ww
w.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Crestview Hotel:
TRANSP:TRANSPARENT
UID:item-fbe6c08e7523c82fac69b40ad1d0899f3d8d5982@tripit.com
DTSTART:20111213T192400Z
DTEND:20111213T202400Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Lodging] Crestview Hotel:\; conf #CR31342159 \ntel
650-966-8848 \narrive 12/13/2011\; depart 12/15/2011 \nBooking Rate: 153.
30 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Crestview Hotel:
TRANSP:TRANSPARENT
UID:item-7ed8b84628e650a6b37161c7825bac9e72add49f@tripit.com
DTSTART:20111216T011500Z
DTEND:20111216T021500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Lodging] Crestview Hotel:\; conf #CR31342159 \ntel
650-966-8848 \narrive 12/13/2011\; depart 12/15/2011 \nBooking Rate: 153.
30 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Advantage
TRANSP:TRANSPARENT
UID:item-623b54ebe07ffd48845f1a120a86940ce79c698b@tripit.com
DTSTART:20111216T030000Z
DTEND:20111216T040000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Car Rental] Advantage\; San Jose International Air
port\; primary driver John Doe\; conf #F31539020E7 \npickup 12/1
3/2011 10:00am\; dropoff 12/15/2011 7:00pm \nStandard Convertible \nRefere
nce #: 3134 0526 3890 \n \n \n\nTripIt - organize your travel at http://ww
w.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111216T045900Z
SUMMARY:US288 SJC to PHX
LOCATION:San Jose (SJC)
UID:item-52481e672972d2e88d5eaa5cf49bb801562c6014@tripit.com
DTSTART:20111216T031500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Flight] 12/15/2011 US Airways(US) #288 dep SJC 7:1
5pm PST arr PHX 9:59pm MST\; John Doe Ticket #0378728465928\; se
at(s) 7B\; conf #GGNV29 \nBooked on http://www.americanexpress-travel.com/
\; Reference #: 3134 0525 5102\; http://www.americanexpress-travel.com/\;
US:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $406.39 \n \n \n\nT
ripIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:7299ff29daed7d5c3e2ed4acc74deec5b7942bd5@tripit.com
DTSTART;VALUE=DATE:20120103
DTEND;VALUE=DATE:20120106
SUMMARY:San Francisco\, CA\, January 2012
LOCATION:San Francisco\, CA
GEO:37.774929;-122.419415
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in San Francisco\, CA from Jan 3 to Jan
5\, 2012\nView and/or edit details in TripIt : http://www.tripit.com/trip/
show/id/27863159\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20120103T175700Z
SUMMARY:US403 PHX to SFO
LOCATION:Phoenix (PHX)
UID:item-f099e76114bf43ef3b122432579d8b40995412a7@tripit.com
DTSTART:20120103T154500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Flight] 1/3/2012 US Airways(US) #403 dep PHX 8:45a
m MST arr SFO 9:57am PST\; John Doe Ticket #0378731791515\; conf
#FH9B72\, L4F9M5 \nBooked on http://www.americanexpress-travel.com/\; Ref
erence #: 6135 7391 6119\; http://www.americanexpress-travel.com/\; US:1-8
00-297-2977\, Outside:210-582-2716\; Total Cost: $668.39 \n \n \n\nTripIt
- organize your travel at http://www.tripit.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-fae4b4b07b66fc87df125238e0aaf645106cf4f3@tripit.com
DTSTART:20120103T180000Z
DTEND:20120103T190000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Car Rental] Alamo\; San Francisco International Ai
rport\; primary driver John Doe\; conf #373525981COUNT \npickup
1/3/2012 10:00am\; dropoff 1/5/2012 6:00pm \nCompact \nReference #: 6135 7
391 6898 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Grand Hotel Sunnyvale
TRANSP:TRANSPARENT
UID:item-d89a856eb9da9dfdcb4da46f42e49af3a838fcbb@tripit.com
DTSTART:20120103T195700Z
DTEND:20120103T205700Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Lodging] Grand Hotel Sunnyvale\; conf #22084SY0361
18 \ntel 1-408-7208500 \narrive 1/3/2012\; depart 1/5/2012 \nBooking Rate:
USD 169.00 \nPolicies: Guarantee to valid form of payment is required at
time of booking\; Cancel 1 day prior to arrival date to avoid penalty of 1
Nights Room Charge. Change fee may apply for early departures and changes
made to confirmed reservations.\; \n \n \n\nTripIt - organize your travel
at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Grand Hotel Sunnyvale
TRANSP:TRANSPARENT
UID:item-6edc82f6411fd0b66f2f7f6baafa41623a8623a9@tripit.com
DTSTART:20120106T010900Z
DTEND:20120106T020900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Lodging] Grand Hotel Sunnyvale\; conf #22084SY0361
18 \ntel 1-408-7208500 \narrive 1/3/2012\; depart 1/5/2012 \nBooking Rate:
USD 169.00 \nPolicies: Guarantee to valid form of payment is required at
time of booking\; Cancel 1 day prior to arrival date to avoid penalty of 1
Nights Room Charge. Change fee may apply for early departures and changes
made to confirmed reservations.\; \n \n \n\nTripIt - organize your travel
at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-58a31b96066ffd09b800af49de59a84f7b7a3a06@tripit.com
DTSTART:20120106T020000Z
DTEND:20120106T030000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Car Rental] Alamo\; San Francisco International Ai
rport\; primary driver John Doe\; conf #373525981COUNT \npickup
1/3/2012 10:00am\; dropoff 1/5/2012 6:00pm \nCompact \nReference #: 6135 7
391 6898 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20120106T050500Z
SUMMARY:CO496 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-7884351ce42d503b90ccc48c33c7c30bd4f44767@tripit.com
DTSTART:20120106T030900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Flight] 1/5/2012 Continental Airlines(CO) #496 dep
SFO 7:09pm PST arr PHX 10:05pm MST\; John Doe Ticket #037873179
1515\; conf #FH9B72\, L4F9M5(Operated by United Airlines flight 496) \nBoo
ked on http://www.americanexpress-travel.com/\; Reference #: 6135 7391 611
9\; http://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:2
10-582-2716\; Total Cost: $668.39 \n \n \n\nTripIt - organize your travel
at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
END:VCALENDAR

View File

@@ -1,41 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Meetup//RemoteApi//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-ORIGINAL-URL:http://www.meetup.com/events/ical/8333638/dfdba2e469216075
3404f737feace78d526ff0ce/going
X-WR-CALNAME:My Meetups
X-MS-OLK-FORCEINSPECTOROPEN:TRUE
BEGIN:VTIMEZONE
TZID:America/Phoenix
TZURL:http://tzurl.org/zoneinfo-outlook/America/Phoenix
X-LIC-LOCATION:America/Phoenix
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0700
TZNAME:MST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20111106T155927Z
DTSTART;TZID=America/Phoenix:20111109T190000
DTEND;TZID=America/Phoenix:20111109T210000
STATUS:CONFIRMED
SUMMARY:Phoenix Drupal User Group Monthly Meetup
DESCRIPTION:Phoenix Drupal User Group\nWednesday\, November 9 at 7:00 PM\
n\nCustomizing node display with template pages in Drupal 6\n\n Jon Shee
han and Matthew Berry of the Office of Knowledge Enterprise Development
(OKED) Knowledge...\n\nDetails: http://www.meetup.com/Phoenix-Drupal-Use
r-Group/events/33627272/
CLASS:PUBLIC
CREATED:20100630T083023Z
GEO:33.56;-111.90
LOCATION:Open Source Project Tempe (1415 E University Dr. #103A\, Tempe\,
AZ 85281)
URL:http://www.meetup.com/Phoenix-Drupal-User-Group/events/33627272/
LAST-MODIFIED:20111102T213309Z
UID:event_nsmxnyppbfc@meetup.com
END:VEVENT
END:VCALENDAR

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:ownCloud Calendar 0.6.3
X-WR-CALNAME:Fête Nationale - Férié
BEGIN:VEVENT
CREATED:20090502T140513Z
DTSTAMP:20111106T124709Z
UID:FA9831E7-C238-4FEC-95E5-CD46BD466421
SUMMARY:Fête Nationale - Férié
RRULE:FREQ=YEARLY
DTSTART;VALUE=DATE:20120714
DTEND;VALUE=DATE:20120715
TRANSP:OPAQUE
SEQUENCE:5
END:VEVENT
END:VCALENDAR

View File

@@ -1,23 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:ownCloud Calendar 0.6.3
X-WR-CALNAME:Default calendar
BEGIN:VTODO
CREATED;VALUE=DATE-TIME:20130714T092804Z
UID:0aa462f13c
LAST-MODIFIED;VALUE=DATE-TIME:20130714T092804Z
DTSTAMP;VALUE=DATE-TIME:20130714T092804Z
CATEGORIES:Projets
SUMMARY:Migrer le blog
PERCENT-COMPLETE:100
COMPLETED;VALUE=DATE-TIME;TZID=Europe/Monaco:20130716T105745
END:VTODO
BEGIN:VTODO
CREATED;VALUE=DATE-TIME:20130714T092912Z
UID:5e05bbcf34
LAST-MODIFIED;VALUE=DATE-TIME:20130714T092912Z
DTSTAMP;VALUE=DATE-TIME:20130714T092912Z
SUMMARY:Créer test unitaire erreur ical
CATEGORIES:Projets
END:VTODO
END:VCALENDAR

View File

@@ -1,21 +0,0 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:eb9e1bd2-ceba-499f-be77-f02773954c72
SUMMARY:Event with an alarm
DESCRIPTION:This is an event with an alarm.
ORGANIZER="mailto:stomlinson@mozilla.com"
DTSTART;TZID="America/Los_Angeles":20130418T110000
DTEND;TZID="America/Los_Angeles":20130418T120000
STATUS:CONFIRMED
CLASS:PUBLIC
TRANSP:OPAQUE
LAST-MODIFIED:20130418T175632Z
DTSTAMP:20130418T175632Z
SEQUENCE:3
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;RELATED=START:-PT5M
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR

View File

@@ -1,41 +1,6 @@
# Module: Clock
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.
## Using the module
To use this module, add it to the modules array in the `config/config.js` file:
````javascript
modules: [
{
module: "clock",
position: "top_left", // This can be any of the regions.
config: {
// The config property is optional.
// See 'Configuration options' for more information.
}
}
]
````
## Configuration options
The following properties can be configured:
| Option | Description
| ----------------- | -----------
| `timeFormat` | Use 12 or 24 hour format. <br><br> **Possible values:** `12` or `24` <br> **Default value:** uses value of _config.timeFormat_
| `displaySeconds` | Display seconds. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
| `showPeriod` | Show the period (am/pm) with 12 hour format. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
| `showPeriodUpper` | Show the period (AM/PM) with 12 hour format as uppercase. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
| `clockBold` | Remove the colon and bold the minutes to make a more modern look. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
| `showDate` | Turn off or on the Date section. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `true`
| `showWeek` | Turn off or on the Week section. <br><br> **Possible values:** `true` or `false` <br> **Default value:** `false`
| `dateFormat` | Configure the date format as you like. <br><br> **Possible values:** [Docs](http://momentjs.com/docs/#/displaying/format/) <br> **Default value:** `"dddd, LL"`
| `displayType` | Display a digital clock, analog clock, or both together. <br><br> **Possible values:** `digital`, `analog`, or `both` <br> **Default value:** `digital`
| `analogSize` | **Specific to the analog clock.** Defines how large the analog display is. <br><br> **Possible values:** A positive number of pixels` <br> **Default value:** `200px`
| `analogFace` | **Specific to the analog clock.** Specifies which clock face to use. <br><br> **Possible values:** `simple` for a simple border, `none` for no face or border, or `face-###` (where ### is currently a value between 001 and 012, inclusive) <br> **Default value:** `simple`
| `secondsColor` | **Specific to the analog clock.** Specifies what color to make the 'seconds' hand. <br><br> **Possible values:** `any HTML RGB Color` <br> **Default value:** `#888888`
| `analogPlacement` | **Specific to the analog clock. _(requires displayType set to `'both'`)_** Specifies where the analog clock is in relation to the digital clock <br><br> **Possible values:** `top`, `right`, `bottom`, or `left` <br> **Default value:** `bottom`
| `analogShowDate` | **Specific to the analog clock.** If the clock is used as a separate module and set to analog only, this configures whether a date is also displayed with the clock. <br><br> **Possible values:** `false`, `top`, or `bottom` <br> **Default value:** `top`
| `timezone` | Specific a timezone to show clock. <br><br> **Possible examples values:** `America/New_York`, `America/Santiago`, `Etc/GMT+10` <br> **Default value:** `none`. See more informations about configuration value [here](https://momentjs.com/timezone/docs/#/data-formats/packed-format/)
For configuration options, please check the [MagicMirror² documentation](https://docs.magicmirror.builders/modules/clock.html).

View File

@@ -1,11 +1,12 @@
/* global Log, Module, moment, config */
/* global SunCalc */
/* Magic Mirror
* Module: Clock
*
* By Michael Teeuw http://michaelteeuw.nl
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("clock",{
Module.register("clock", {
// Module config defaults.
defaults: {
displayType: "digital", // options: digital, analog, both
@@ -26,32 +27,68 @@ Module.register("clock",{
analogShowDate: "top", // options: false, 'top', or 'bottom'
secondsColor: "#888888",
timezone: null,
showSunTimes: false,
showMoonTimes: false,
lat: 47.630539,
lon: -122.344147
},
// Define required scripts.
getScripts: function() {
return ["moment.js", "moment-timezone.js"];
getScripts: function () {
return ["moment.js", "moment-timezone.js", "suncalc.js"];
},
// Define styles.
getStyles: function() {
getStyles: function () {
return ["clock_styles.css"];
},
// Define start sequence.
start: function() {
start: function () {
Log.info("Starting module: " + this.name);
// Schedule update interval.
var self = this;
setInterval(function() {
self.second = moment().second();
self.minute = moment().minute();
//Calculate how many ms should pass until next update depending on if seconds is displayed or not
var delayCalculator = function (reducedSeconds) {
var EXTRA_DELAY = 50; //Deliberate imperceptable delay to prevent off-by-one timekeeping errors
if (self.config.displaySeconds) {
return 1000 - moment().milliseconds() + EXTRA_DELAY;
} else {
return (60 - reducedSeconds) * 1000 - moment().milliseconds() + EXTRA_DELAY;
}
};
//A recursive timeout function instead of interval to avoid drifting
var notificationTimer = function () {
self.updateDom();
}, 1000);
//If seconds is displayed CLOCK_SECOND-notification should be sent (but not when CLOCK_MINUTE-notification is sent)
if (self.config.displaySeconds) {
self.second = moment().second();
if (self.second !== 0) {
self.sendNotification("CLOCK_SECOND", self.second);
setTimeout(notificationTimer, delayCalculator(0));
return;
}
}
//If minute changed or seconds isn't displayed send CLOCK_MINUTE-notification
self.minute = moment().minute();
self.sendNotification("CLOCK_MINUTE", self.minute);
setTimeout(notificationTimer, delayCalculator(0));
};
//Set the initial timeout with the amount of seconds elapsed as reducedSeconds so it will trigger when the minute changes
setTimeout(notificationTimer, delayCalculator(self.second));
// Set locale.
moment.locale(config.language);
},
// Override dom generator.
getDom: function() {
getDom: function () {
var wrapper = document.createElement("div");
/************************************
@@ -62,12 +99,16 @@ Module.register("clock",{
var timeWrapper = document.createElement("div");
var secondsWrapper = document.createElement("sup");
var periodWrapper = document.createElement("span");
var weekWrapper = document.createElement("div")
var sunWrapper = document.createElement("div");
var moonWrapper = document.createElement("div");
var weekWrapper = document.createElement("div");
// Style Wrappers
dateWrapper.className = "date normal medium";
timeWrapper.className = "time bright large light";
secondsWrapper.className = "dimmed";
weekWrapper.className = "week dimmed medium"
sunWrapper.className = "sun dimmed small";
moonWrapper.className = "moon dimmed small";
weekWrapper.className = "week dimmed medium";
// Set content of wrappers.
// The moment().format("h") method has a bug on the Raspberry Pi.
@@ -75,6 +116,7 @@ Module.register("clock",{
// See issue: https://github.com/MichMich/MagicMirror/issues/181
var timeString;
var now = moment();
this.lastDisplayedMinute = now.minute();
if (this.config.timezone) {
now.tz(this.config.timezone);
}
@@ -85,12 +127,12 @@ Module.register("clock",{
}
if (this.config.clockBold === true) {
timeString = now.format(hourSymbol + "[<span class=\"bold\">]mm[</span>]");
timeString = now.format(hourSymbol + '[<span class="bold">]mm[</span>]');
} else {
timeString = now.format(hourSymbol + ":mm");
}
if(this.config.showDate){
if (this.config.showDate) {
dateWrapper.innerHTML = now.format(this.config.dateFormat);
}
if (this.config.showWeek) {
@@ -110,19 +152,79 @@ Module.register("clock",{
timeWrapper.appendChild(periodWrapper);
}
function formatTime(config, time) {
var formatString = hourSymbol + ":mm";
if (config.showPeriod && config.timeFormat !== 24) {
formatString += config.showPeriodUpper ? "A" : "a";
}
return moment(time).format(formatString);
}
if (this.config.showSunTimes) {
const sunTimes = SunCalc.getTimes(now, this.config.lat, this.config.lon);
const isVisible = now.isBetween(sunTimes.sunrise, sunTimes.sunset);
var nextEvent;
if (now.isBefore(sunTimes.sunrise)) {
nextEvent = sunTimes.sunrise;
} else if (now.isBefore(sunTimes.sunset)) {
nextEvent = sunTimes.sunset;
} else {
const tomorrowSunTimes = SunCalc.getTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon);
nextEvent = tomorrowSunTimes.sunrise;
}
const untilNextEvent = moment.duration(moment(nextEvent).diff(now));
const untilNextEventString = untilNextEvent.hours() + "h " + untilNextEvent.minutes() + "m";
sunWrapper.innerHTML =
'<span class="' +
(isVisible ? "bright" : "") +
'"><i class="fa fa-sun-o" aria-hidden="true"></i> ' +
untilNextEventString +
"</span>" +
'<span><i class="fa fa-arrow-up" aria-hidden="true"></i>' +
formatTime(this.config, sunTimes.sunrise) +
"</span>" +
'<span><i class="fa fa-arrow-down" aria-hidden="true"></i>' +
formatTime(this.config, sunTimes.sunset) +
"</span>";
}
if (this.config.showMoonTimes) {
const moonIllumination = SunCalc.getMoonIllumination(now.toDate());
const moonTimes = SunCalc.getMoonTimes(now, this.config.lat, this.config.lon);
const moonRise = moonTimes.rise;
var moonSet;
if (moment(moonTimes.set).isAfter(moonTimes.rise)) {
moonSet = moonTimes.set;
} else {
const nextMoonTimes = SunCalc.getMoonTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon);
moonSet = nextMoonTimes.set;
}
const isVisible = now.isBetween(moonRise, moonSet) || moonTimes.alwaysUp === true;
const illuminatedFractionString = Math.round(moonIllumination.fraction * 100) + "%";
moonWrapper.innerHTML =
'<span class="' +
(isVisible ? "bright" : "") +
'"><i class="fa fa-moon-o" aria-hidden="true"></i> ' +
illuminatedFractionString +
"</span>" +
'<span><i class="fa fa-arrow-up" aria-hidden="true"></i> ' +
(moonRise ? formatTime(this.config, moonRise) : "...") +
"</span>" +
'<span><i class="fa fa-arrow-down" aria-hidden="true"></i> ' +
(moonSet ? formatTime(this.config, moonSet) : "...") +
"</span>";
}
/****************************************************************
* 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
// Calculate the degree offset for each hand of the clock
var now = moment();
if (this.config.timezone) {
now.tz(this.config.timezone);
}
var second = now.seconds() * 6,
var second = now.seconds() * 6,
minute = now.minute() * 6 + second / 60,
hour = ((now.hours() % 12) / 12) * 360 + 90 + minute / 12;
@@ -132,14 +234,14 @@ Module.register("clock",{
clockCircle.style.width = this.config.analogSize;
clockCircle.style.height = this.config.analogSize;
if (this.config.analogFace != "" && this.config.analogFace != "simple" && this.config.analogFace != "none") {
clockCircle.style.background = "url("+ this.data.path + "faces/" + this.config.analogFace + ".svg)";
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.backgroundSize = "100%";
// The following line solves issue: https://github.com/MichMich/MagicMirror/issues/611
clockCircle.style.border = "1px solid black";
} else if (this.config.analogFace != "none") {
// 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
} else if (this.config.analogFace !== "none") {
clockCircle.style.border = "2px solid white";
}
var clockFace = document.createElement("div");
@@ -177,6 +279,8 @@ Module.register("clock",{
// Display only a digital clock
wrapper.appendChild(dateWrapper);
wrapper.appendChild(timeWrapper);
wrapper.appendChild(sunWrapper);
wrapper.appendChild(moonWrapper);
wrapper.appendChild(weekWrapper);
} else if (this.config.displayType === "analog") {
// Display only an analog clock
@@ -202,20 +306,23 @@ Module.register("clock",{
// Both clocks have been configured, check position
var placement = this.config.analogPlacement;
analogWrapper = document.createElement("div");
var analogWrapper = document.createElement("div");
analogWrapper.id = "analog";
analogWrapper.style.cssFloat = "none";
analogWrapper.appendChild(clockCircle);
digitalWrapper = document.createElement("div");
var digitalWrapper = document.createElement("div");
digitalWrapper.id = "digital";
digitalWrapper.style.cssFloat = "none";
digitalWrapper.appendChild(dateWrapper);
digitalWrapper.appendChild(timeWrapper);
digitalWrapper.appendChild(sunWrapper);
digitalWrapper.appendChild(moonWrapper);
digitalWrapper.appendChild(weekWrapper);
var appendClocks = function(condition, pos1, pos2) {
var padding = [0,0,0,0];
padding[(placement === condition) ? pos1 : pos2] = "20px";
var appendClocks = function (condition, pos1, pos2) {
var padding = [0, 0, 0, 0];
padding[placement === condition ? pos1 : pos2] = "20px";
analogWrapper.style.padding = padding.join(" ");
if (placement === condition) {
wrapper.appendChild(analogWrapper);

View File

@@ -1,68 +1,72 @@
.clockCircle {
margin: 0 auto;
position: relative;
border-radius: 50%;
background-size: 100%;
}
.clockFace {
width: 100%;
height: 100%;
}
.clockFace::after {
position: absolute;
top: 50%;
left: 50%;
width: 6px;
height: 6px;
margin: -3px 0 0 -3px;
background: white;
border-radius: 3px;
content: "";
display: block;
}
.clockHour {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -2px 0 -2px -25%; /* numbers much match negative length & thickness */
padding: 2px 0 2px 25%; /* indicator length & thickness */
background: white;
-webkit-transform-origin: 100% 50%;
-ms-transform-origin: 100% 50%;
transform-origin: 100% 50%;
border-radius: 3px 0 0 3px;
}
.clockMinute {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -35% -2px 0; /* numbers must match negative length & thickness */
padding: 35% 2px 0; /* indicator length & thickness */
background: white;
-webkit-transform-origin: 50% 100%;
-ms-transform-origin: 50% 100%;
transform-origin: 50% 100%;
border-radius: 3px 0 0 3px;
}
.clockSecond {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -38% -1px 0 0; /* numbers must match negative length & thickness */
padding: 38% 1px 0 0; /* indicator length & thickness */
background: #888;
-webkit-transform-origin: 50% 100%;
-ms-transform-origin: 50% 100%;
transform-origin: 50% 100%;
}
.clockCircle {
margin: 0 auto;
position: relative;
border-radius: 50%;
background-size: 100%;
}
.clockFace {
width: 100%;
height: 100%;
}
.clockFace::after {
position: absolute;
top: 50%;
left: 50%;
width: 6px;
height: 6px;
margin: -3px 0 0 -3px;
background: white;
border-radius: 3px;
content: "";
display: block;
}
.clockHour {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -2px 0 -2px -25%; /* numbers much match negative length & thickness */
padding: 2px 0 2px 25%; /* indicator length & thickness */
background: white;
transform-origin: 100% 50%;
border-radius: 3px 0 0 3px;
}
.clockMinute {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -35% -2px 0; /* numbers must match negative length & thickness */
padding: 35% 2px 0; /* indicator length & thickness */
background: white;
transform-origin: 50% 100%;
border-radius: 3px 0 0 3px;
}
.clockSecond {
width: 0;
height: 0;
position: absolute;
top: 50%;
left: 50%;
margin: -38% -1px 0 0; /* numbers must match negative length & thickness */
padding: 38% 1px 0 0; /* indicator length & thickness */
background: #888;
transform-origin: 50% 100%;
}
.module.clock .sun,
.module.clock .moon {
display: flex;
}
.module.clock .sun > *,
.module.clock .moon > * {
flex: 1;
}

View File

@@ -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

View File

@@ -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

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Some files were not shown because too many files have changed in this diff Show More