Merge pull request #14 from MichMich/v2-beta

Update from Master
This commit is contained in:
Paul-Vincent Roll 2016-04-03 20:05:55 +02:00
commit 053bdd0467
41 changed files with 146 additions and 184 deletions

View File

@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View File

@ -1,5 +1,5 @@
# MagicMirror V2 # MagicMirror V2
This version of the Magic Mirror software focusses on a modular plugin system. Besides that, the Magic Mirror software now also uses [Electron](http://electron.atom.io/), so no more webserver or browser installs necessary. This version of the Magic Mirror software focusses on a modular plugin system. Besides that, the Magic Mirror software now also uses [Electron](http://electron.atom.io/), so no more webserver or browser installs necessary.
#WARNING: THIS VERSION IS IN A VERY EARLY STAGE. IT IS NOT COMPLETED YET. PLEASE USE THE MASTER BRANCH. #WARNING: THIS VERSION IS IN A VERY EARLY STAGE. IT IS NOT COMPLETED YET. PLEASE USE THE MASTER BRANCH.
@ -28,7 +28,7 @@ Things that still have to be implemented or changed.
####Documentation ####Documentation
- Write all the documentation. :) - Write all the documentation. :)
##Modules ##Modules
### Default modules: ### Default modules:
- [**Clock**](modules/default/clock) - [**Clock**](modules/default/clock)
@ -47,6 +47,3 @@ Things that still have to be implemented or changed.
- **[MMM-Facial-Recognition by PaViRo](https://github.com/paviro/MMM-Facial-Recognition)** <br> Facial recognition and module swapping based on the current user ... - **[MMM-Facial-Recognition by PaViRo](https://github.com/paviro/MMM-Facial-Recognition)** <br> Facial recognition and module swapping based on the current user ...
- **[MMM-Wunderlist by PaViRo](https://github.com/paviro/MMM-Wunderlist)** <br> Displays your Wunderlist todos on your mirror ... - **[MMM-Wunderlist by PaViRo](https://github.com/paviro/MMM-Wunderlist)** <br> Displays your Wunderlist todos on your mirror ...

2
config/.gitignore vendored
View File

@ -1 +1 @@
config.js config.js

View File

@ -27,7 +27,7 @@ var config = {
config: { config: {
calendars: [ calendars: [
{ {
symbol: 'calendar-check-o ', symbol: 'calendar-check-o ',
url: 'webcal://www.calendarlabs.com/templates/ical/US-Holidays.ics' url: 'webcal://www.calendarlabs.com/templates/ical/US-Holidays.ics'
} }
] ]
@ -63,9 +63,9 @@ var config = {
} }
}, },
] ]
}; };
/*************** DO NOT EDIT THE LINE BELOW ***************/ /*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== 'undefined') {module.exports = config;} if (typeof module !== 'undefined') {module.exports = config;}

View File

@ -1,5 +1,8 @@
body { html {
cursor: none; cursor: none;
}
body {
margin: 60px; margin: 60px;
position: absolute; position: absolute;
height: calc(100% - 120px); height: calc(100% - 120px);
@ -135,4 +138,4 @@ sup {
width: 100%; width: 100%;
border-spacing: 0px; border-spacing: 0px;
border-collapse: separate; border-collapse: separate;
} }

View File

@ -200,4 +200,4 @@ Font data copyright Google 2012
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.

View File

@ -45,4 +45,3 @@
font-style: normal; font-style: normal;
} }

View File

@ -91,6 +91,3 @@
font-style: normal; font-style: normal;
} }

View File

@ -2,24 +2,24 @@
* By John Resig http://ejohn.org/ * By John Resig http://ejohn.org/
* MIT Licensed. * MIT Licensed.
*/ */
// Inspired by base2 and Prototype // Inspired by base2 and Prototype
(function(){ (function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing) // The base Class implementation (does nothing)
this.Class = function(){}; this.Class = function(){};
// Create a new Class that inherits from this class // Create a new Class that inherits from this class
Class.extend = function(prop) { Class.extend = function(prop) {
var _super = this.prototype; var _super = this.prototype;
// Instantiate a base class (but only create the instance, // Instantiate a base class (but only create the instance,
// don't run the init constructor) // don't run the init constructor)
initializing = true; initializing = true;
var prototype = new this(); var prototype = new this();
initializing = false; initializing = false;
// Copy the properties over onto the new prototype // Copy the properties over onto the new prototype
for (var name in prop) { for (var name in prop) {
// Check if we're overwriting an existing function // Check if we're overwriting an existing function
@ -28,42 +28,42 @@
(function(name, fn){ (function(name, fn){
return function() { return function() {
var tmp = this._super; var tmp = this._super;
// Add a new ._super() method that is the same method // Add a new ._super() method that is the same method
// but on the super-class // but on the super-class
this._super = _super[name]; this._super = _super[name];
// The method only need to be bound temporarily, so we // The method only need to be bound temporarily, so we
// remove it when we're done executing // remove it when we're done executing
var ret = fn.apply(this, arguments); var ret = fn.apply(this, arguments);
this._super = tmp; this._super = tmp;
return ret; return ret;
}; };
})(name, prop[name]) : })(name, prop[name]) :
prop[name]; prop[name];
} }
// The dummy class constructor // The dummy class constructor
function Class() { function Class() {
// All construction is actually done in the init method // All construction is actually done in the init method
if ( !initializing && this.init ) if ( !initializing && this.init )
this.init.apply(this, arguments); this.init.apply(this, arguments);
} }
// Populate our constructed prototype object // Populate our constructed prototype object
Class.prototype = prototype; Class.prototype = prototype;
// Enforce the constructor to be what we expect // Enforce the constructor to be what we expect
Class.prototype.constructor = Class; Class.prototype.constructor = Class;
// And make this class extendable // And make this class extendable
Class.extend = arguments.callee; Class.extend = arguments.callee;
return Class; return Class;
}; };
})(); })();
/*************** DO NOT EDIT THE LINE BELOW ***************/ /*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== 'undefined') {module.exports = Class;} if (typeof module !== 'undefined') {module.exports = Class;}

View File

@ -55,4 +55,4 @@ var defaults = {
/*************** DO NOT EDIT THE LINE BELOW ***************/ /*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== 'undefined') {module.exports = defaults;} if (typeof module !== 'undefined') {module.exports = defaults;}

View File

@ -61,7 +61,7 @@ function loadModule(module) {
var elements = module.split('/'); var elements = module.split('/');
var moduleName = elements[elements.length - 1]; var moduleName = elements[elements.length - 1];
var moduleFolder = __dirname + '/../modules/' + module; var moduleFolder = __dirname + '/../modules/' + module;
if (defaultModules.indexOf(moduleName) !== -1) { if (defaultModules.indexOf(moduleName) !== -1) {
moduleFolder = __dirname + '/../modules/default/' + module; moduleFolder = __dirname + '/../modules/default/' + module;
} }

View File

@ -41,7 +41,7 @@ var Loader = (function() {
} }
}; };
loadNextModule(); loadNextModule();
}; };
/* startModules() /* startModules()
@ -60,7 +60,7 @@ var Loader = (function() {
/* getAllModules() /* getAllModules()
* Retrieve list of all modules. * Retrieve list of all modules.
* *
* return array - module data as configured in config * return array - module data as configured in config
*/ */
var getAllModules = function() { var getAllModules = function() {
return config.modules; return config.modules;
@ -82,7 +82,7 @@ var Loader = (function() {
var elements = module.split('/'); var elements = module.split('/');
var moduleName = elements[elements.length - 1]; var moduleName = elements[elements.length - 1];
var moduleFolder = config.paths.modules + '/' + module; var moduleFolder = config.paths.modules + '/' + module;
if (defaultModules.indexOf(moduleName) !== -1) { if (defaultModules.indexOf(moduleName) !== -1) {
moduleFolder = config.paths.modules + '/default/' + module; moduleFolder = config.paths.modules + '/default/' + module;
} }
@ -130,8 +130,8 @@ var Loader = (function() {
afterLoad(); afterLoad();
}); });
} }
}; };
/* bootstrapModule(module, mObj) /* bootstrapModule(module, mObj)
* Bootstrap modules by setting the module data and loading the scripts & styles. * Bootstrap modules by setting the module data and loading the scripts & styles.
@ -154,8 +154,8 @@ var Loader = (function() {
callback(); callback();
}); });
}); });
}; };
/* loadFile(fileName) /* loadFile(fileName)
@ -194,7 +194,7 @@ var Loader = (function() {
}; };
document.getElementsByTagName("head")[0].appendChild(stylesheet); document.getElementsByTagName("head")[0].appendChild(stylesheet);
break; break;
} }
}; };
@ -249,10 +249,3 @@ var Loader = (function() {
}; };
})(); })();

View File

@ -9,7 +9,7 @@
*/ */
// This logger is very simple, but needs to be extended. // 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. // This system can eventually be used to push the log messages to an external target.

View File

@ -15,13 +15,13 @@ var MM = (function() {
/* Private Methods */ /* Private Methods */
/* createDomObjects() /* createDomObjects()
* Create dom objects for all modules that * Create dom objects for all modules that
* are configured for a specific position. * are configured for a specific position.
*/ */
var createDomObjects = function() { var createDomObjects = function() {
for (var m in modules) { for (var m in modules) {
var module = modules[m]; var module = modules[m];
if (typeof module.data.position === 'string') { if (typeof module.data.position === 'string') {
var wrapper = selectWrapper(module.data.position); var wrapper = selectWrapper(module.data.position);
@ -47,13 +47,11 @@ var MM = (function() {
moduleContent.className = "module-content"; moduleContent.className = "module-content";
dom.appendChild(moduleContent); dom.appendChild(moduleContent);
updateDom(module, 0); updateDom(module, 0);
} }
} }
sendNotification('DOM_OBJECTS_CREATED'); sendNotification('DOM_OBJECTS_CREATED');
}; };
/* selectWrapper(position) /* selectWrapper(position)
@ -99,7 +97,6 @@ var MM = (function() {
if (!module.hidden) { if (!module.hidden) {
if (!moduleNeedsUpdate(module, newContent)) { if (!moduleNeedsUpdate(module, newContent)) {
return; return;
} }
@ -173,7 +170,7 @@ var MM = (function() {
// the .display property. // the .display property.
moduleWrapper.style.position = 'absolute'; moduleWrapper.style.position = 'absolute';
if (typeof callback === 'function') { callback(); } if (typeof callback === 'function') { callback(); }
}, speed); }, speed);
} }
}; };
@ -194,10 +191,9 @@ var MM = (function() {
moduleWrapper.style.opacity = 1; moduleWrapper.style.opacity = 1;
setTimeout(function() { setTimeout(function() {
if (typeof callback === 'function') { callback(); } if (typeof callback === 'function') { callback(); }
}, speed); }, speed);
} }
}; };
@ -216,14 +212,14 @@ var MM = (function() {
/* setSelectionMethodsForModules() /* setSelectionMethodsForModules()
* Adds special selectors on a collection of modules. * Adds special selectors on a collection of modules.
* *
* argument modules array - Array of modules. * argument modules array - Array of modules.
*/ */
var setSelectionMethodsForModules = function(modules) { var setSelectionMethodsForModules = function(modules) {
/* withClass(className) /* withClass(className)
* filters a collection of modules based on classname(s). * filters a collection of modules based on classname(s).
* *
* argument className string/array - one or multiple classnames. (array or space devided) * argument className string/array - one or multiple classnames. (array or space devided)
* *
* return array - Filtered collection of modules. * return array - Filtered collection of modules.
@ -245,7 +241,7 @@ var MM = (function() {
if (classes.indexOf(searchClass.toLowerCase()) !== -1) { if (classes.indexOf(searchClass.toLowerCase()) !== -1) {
newModules.push(module); newModules.push(module);
} }
} }
} }
setSelectionMethodsForModules(newModules); setSelectionMethodsForModules(newModules);
@ -254,7 +250,7 @@ var MM = (function() {
/* exceptWithClass(className) /* exceptWithClass(className)
* filters a collection of modules based on classname(s). (NOT) * filters a collection of modules based on classname(s). (NOT)
* *
* argument className string/array - one or multiple classnames. (array or space devided) * argument className string/array - one or multiple classnames. (array or space devided)
* *
* return array - Filtered collection of modules. * return array - Filtered collection of modules.
@ -280,7 +276,7 @@ var MM = (function() {
} }
if (!foundClass) { if (!foundClass) {
newModules.push(module); newModules.push(module);
} }
} }
setSelectionMethodsForModules(newModules); setSelectionMethodsForModules(newModules);
@ -289,7 +285,7 @@ var MM = (function() {
/* exceptModule(module) /* exceptModule(module)
* Removes a module instance from the collection. * Removes a module instance from the collection.
* *
* argument module Module object - The module instance to remove from the collection. * argument module Module object - The module instance to remove from the collection.
* *
* return array - Filtered collection of modules. * return array - Filtered collection of modules.
@ -310,7 +306,7 @@ var MM = (function() {
/* enumerate(callback) /* enumerate(callback)
* Walks thru a collection of modules and executes the callback with the module as an argument. * Walks thru a collection of modules and executes the callback with the module as an argument.
* *
* argument callback function - The function to execute with the module as an argument. * argument callback function - The function to execute with the module as an argument.
*/ */
var enumerate = function(callback) { var enumerate = function(callback) {
@ -320,8 +316,6 @@ var MM = (function() {
} }
}; };
if (typeof modules.withClass === 'undefined') { Object.defineProperty(modules, 'withClass', {value: withClass, 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.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.exceptModule === 'undefined') { Object.defineProperty(modules, 'exceptModule', {value: exceptModule, enumerable: false}); }
@ -329,8 +323,6 @@ var MM = (function() {
}; };
return { return {
/* Public Methods */ /* Public Methods */
@ -399,7 +391,7 @@ var MM = (function() {
Log.error('updateDom: Sender should be a module.'); Log.error('updateDom: Sender should be a module.');
return; return;
} }
// Further implementation is done in the private method. // Further implementation is done in the private method.
updateDom(module, speed); updateDom(module, speed);
}, },
@ -442,8 +434,3 @@ var MM = (function() {
})(); })();
MM.init(); MM.init();

View File

@ -57,11 +57,11 @@ var Module = Class.extend({
*/ */
getDom: function() { getDom: function() {
var nameWrapper = document.createElement("div"); var nameWrapper = document.createElement("div");
var name = document.createTextNode(this.name); var name = document.createTextNode(this.name);
nameWrapper.appendChild(name); nameWrapper.appendChild(name);
var identifierWrapper = document.createElement("div"); var identifierWrapper = document.createElement("div");
var identifier = document.createTextNode(this.identifier); var identifier = document.createTextNode(this.identifier);
identifierWrapper.appendChild(identifier); identifierWrapper.appendChild(identifier);
identifierWrapper.className = "small dimmed"; identifierWrapper.className = "small dimmed";
@ -69,7 +69,7 @@ var Module = Class.extend({
div.appendChild(nameWrapper); div.appendChild(nameWrapper);
div.appendChild(identifierWrapper); div.appendChild(identifierWrapper);
return div; return div;
}, },
/* notificationReceived(notification, payload, sender) /* notificationReceived(notification, payload, sender)
@ -99,7 +99,6 @@ var Module = Class.extend({
}, },
/********************************************* /*********************************************
* The methods below don't need subclassing. * * The methods below don't need subclassing. *
*********************************************/ *********************************************/
@ -262,12 +261,12 @@ Module.create = function(name) {
if (obj === null || typeof obj !== 'object') { if (obj === null || typeof obj !== 'object') {
return obj; return obj;
} }
var temp = obj.constructor(); // give temp the original obj's constructor var temp = obj.constructor(); // give temp the original obj's constructor
for (var key in obj) { for (var key in obj) {
temp[key] = cloneObject(obj[key]); temp[key] = cloneObject(obj[key]);
} }
return temp; return temp;
} }
@ -278,13 +277,10 @@ Module.create = function(name) {
var ModuleClass = Module.extend(clonedDefinition); var ModuleClass = Module.extend(clonedDefinition);
return new ModuleClass(); return new ModuleClass();
}; };
Module.register = function(name, moduleDefinition) { Module.register = function(name, moduleDefinition) {
Log.log('Module registered: ' + name); Log.log('Module registered: ' + name);
Module.definitions[name] = moduleDefinition; Module.definitions[name] = moduleDefinition;
}; };

View File

@ -31,4 +31,4 @@ var Server = function(config, callback) {
} }
}; };
module.exports = Server; module.exports = Server;

View File

@ -7,8 +7,6 @@
* MIT Licensed. * MIT Licensed.
*/ */
var MMSocket = function(moduleName) { var MMSocket = function(moduleName) {
var self = this; var self = this;
@ -18,7 +16,7 @@ var MMSocket = function(moduleName) {
} }
self.moduleName = moduleName; self.moduleName = moduleName;
self.socket = io('http://localhost:8080'); self.socket = io('http://localhost:8080');
self.socket.on('notification', function (data) { self.socket.on('notification', function (data) {
@ -35,6 +33,4 @@ var MMSocket = function(moduleName) {
}); });
} }
}; };
}; };

View File

@ -39,4 +39,4 @@ var MMSocket = function(moduleName) {
} }
socket.emit(notification, payload); socket.emit(notification, payload);
}; };
}; };

View File

@ -1,6 +1,6 @@
# Module: Calendar # Module: Calendar
The `calendar` module is one of the default modules of the MagicMirror. The `calendar` module is one of the default modules of the MagicMirror.
This module displays events from a public .ical calendar. It can combine multiple calendars. This module displays events from a public .ical calendar. It can combine multiple calendars.
## Using the module ## Using the module
@ -13,7 +13,7 @@ modules: [
config: { config: {
// The config property is optional. // The config property is optional.
// If no config is set, an example calendar is shown. // If no config is set, an example calendar is shown.
// See 'Configuration options' for more information. // See 'Configuration options' for more information.
} }
} }
] ]
@ -40,6 +40,12 @@ The following properties can be configured:
<br><b>Default value:</b> <code>10</code> <br><b>Default value:</b> <code>10</code>
</td> </td>
</tr> </tr>
<tr>
<td><code>maximumNumberOfDays</code></td>
<td>The maximum number of days in the future.<br>
<br><b>Default value:</b> <code>365</code>
</td>
</tr>
<tr> <tr>
<td><code>displaySymbol</code></td> <td><code>displaySymbol</code></td>
<td>Display a symbol in front of an entry.<br> <td>Display a symbol in front of an entry.<br>
@ -100,7 +106,7 @@ The following properties can be configured:
<td><code>titleReplace</code></td> <td><code>titleReplace</code></td>
<td>An object of textual replacements applied to the tile of the event. This allow to remove or replace certains words in the title.<br> <td>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><b>Example:</b> <br> <br><b>Example:</b> <br>
<code> <code>
titleReplace: {'Birthday of ' : '', 'foo':'bar'} titleReplace: {'Birthday of ' : '', 'foo':'bar'}
</code> </code>
@ -149,4 +155,4 @@ config: {
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -20,4 +20,4 @@
.calendar .time { .calendar .time {
padding-left: 30px; padding-left: 30px;
text-align: right; text-align: right;
} }

View File

@ -12,12 +12,13 @@ Module.register('calendar',{
// Define module defaults // Define module defaults
defaults: { defaults: {
maximumEntries: 10, // Total Maximum Entries maximumEntries: 10, // Total Maximum Entries
maximumNumberOfDays: 365,
displaySymbol: true, displaySymbol: true,
defaultSymbol: 'calendar', // Fontawsome Symbol see http://fontawesome.io/cheatsheet/ defaultSymbol: 'calendar', // Fontawsome Symbol see http://fontawesome.io/cheatsheet/
maxTitleLength: 25, maxTitleLength: 25,
fetchInterval: 5 * 60 * 1000, // Update every 5 minutes. fetchInterval: 5 * 60 * 1000, // Update every 5 minutes.
animationSpeed: 2000, animationSpeed: 2000,
fade: true, fade: true,
fadePoint: 0.25, // Start on 1/4th of the list. fadePoint: 0.25, // Start on 1/4th of the list.
calendars: [ calendars: [
{ {
@ -58,7 +59,7 @@ Module.register('calendar',{
// Override socket notification handler. // Override socket notification handler.
socketNotificationReceived: function(notification, payload) { socketNotificationReceived: function(notification, payload) {
if (notification === 'CALENDAR_EVENTS') { if (notification === 'CALENDAR_EVENTS') {
if (this.hasCalendarURL(payload.url)) { if (this.hasCalendarURL(payload.url)) {
this.calendarData[payload.url] = payload.events; this.calendarData[payload.url] = payload.events;
} }
@ -180,6 +181,7 @@ Module.register('calendar',{
this.sendSocketNotification('ADD_CALENDAR', { this.sendSocketNotification('ADD_CALENDAR', {
url: url, url: url,
maximumEntries: this.config.maximumEntries, maximumEntries: this.config.maximumEntries,
maximumNumberOfDays: this.config.maximumNumberOfDays,
fetchInterval: this.config.fetchInterval fetchInterval: this.config.fetchInterval
}); });
}, },
@ -237,4 +239,4 @@ Module.register('calendar',{
title = this.shorten(title, this.config.maxTitleLength); title = this.shorten(title, this.config.maxTitleLength);
return title; return title;
} }
}); });

View File

@ -10,7 +10,7 @@ var ical = require('ical');
var moment = require('moment'); var moment = require('moment');
var validUrl = require('valid-url'); var validUrl = require('valid-url');
var CalendarFetcher = function(url, reloadInterval, maximumEntries) { var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumberOfDays) {
var self = this; var self = this;
var reloadTimer = null; var reloadTimer = null;
@ -42,7 +42,8 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries) {
for (var e in data) { for (var e in data) {
var event = data[e]; var event = data[e];
var today = moment().startOf('day');
if (event.type === 'VEVENT') { if (event.type === 'VEVENT') {
var startDate = (event.start.length === 8) ? moment(event.start, 'YYYYMMDD') : moment(new Date(event.start)); var startDate = (event.start.length === 8) ? moment(event.start, 'YYYYMMDD') : moment(new Date(event.start));
@ -54,6 +55,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries) {
// This causes the times of the recurring event to be incorrect. // This causes the times of the recurring event to be incorrect.
// By adjusting the timeset property, this issue is solved. // By adjusting the timeset property, this issue is solved.
var now = new Date(); var now = new Date();
if (rule.timeset[0].hour == now.getHours(), if (rule.timeset[0].hour == now.getHours(),
rule.timeset[0].minute == now.getMinutes(), rule.timeset[0].minute == now.getMinutes(),
rule.timeset[0].second == now.getSeconds()) { rule.timeset[0].second == now.getSeconds()) {
@ -62,11 +64,8 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries) {
rule.timeset[0].minute = startDate.format('m'); rule.timeset[0].minute = startDate.format('m');
rule.timeset[0].second = startDate.format('s'); rule.timeset[0].second = startDate.format('s');
} }
var oneYear = new Date();
oneYear.setFullYear(oneYear.getFullYear() + 1);
var dates = rule.between(new Date(), oneYear, true, limitFunction); var dates = rule.between(new Date(), today.add(maximumNumberOfDays, 'days') , true, limitFunction);
//console.log(dates); //console.log(dates);
for (var d in dates) { for (var d in dates) {
startDate = moment(new Date(dates[d])); startDate = moment(new Date(dates[d]));
@ -78,8 +77,8 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries) {
} else { } else {
// Single event. // Single event.
var today = moment().startOf('day');
if (startDate > today) { if (startDate > today && startDate <= today.add(maximumNumberOfDays, 'days')) {
newEvents.push({ newEvents.push({
title: event.summary, title: event.summary,
startDate: startDate.format('x') startDate: startDate.format('x')
@ -92,7 +91,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries) {
newEvents.sort(function(a,b) { newEvents.sort(function(a,b) {
return a.startDate - b.startDate; return a.startDate - b.startDate;
}); });
events = newEvents.slice(0, maximumEntries); events = newEvents.slice(0, maximumEntries);
self.broadcastEvents(); self.broadcastEvents();
@ -180,14 +179,14 @@ module.exports = NodeHelper.create({
console.log('Starting node helper for: ' + this.name); console.log('Starting node helper for: ' + this.name);
}, },
// Override socketNotificationReceived method. // Override socketNotificationReceived method.
socketNotificationReceived: function(notification, payload) { socketNotificationReceived: function(notification, payload) {
if (notification === 'ADD_CALENDAR') { if (notification === 'ADD_CALENDAR') {
//console.log('ADD_CALENDAR: '); //console.log('ADD_CALENDAR: ');
this.createFetcher(payload.url, payload.fetchInterval, payload.maximumEntries); this.createFetcher(payload.url, payload.fetchInterval, payload.maximumEntries, payload.maximumNumberOfDays);
} }
}, },
@ -199,7 +198,7 @@ module.exports = NodeHelper.create({
* attribute reloadInterval number - Reload interval in milliseconds. * attribute reloadInterval number - Reload interval in milliseconds.
*/ */
createFetcher: function(url, fetchInterval, maximumEntries) { createFetcher: function(url, fetchInterval, maximumEntries, maximumNumberOfDays) {
var self = this; var self = this;
if (!validUrl.isUri(url)){ if (!validUrl.isUri(url)){
@ -210,8 +209,8 @@ module.exports = NodeHelper.create({
var fetcher; var fetcher;
if (typeof self.fetchers[url] === 'undefined') { if (typeof self.fetchers[url] === 'undefined') {
console.log('Create new calendar fetcher for url: ' + url + ' - Interval: ' + fetchInterval); console.log('Create new calendar fetcher for url: ' + url + ' - Interval: ' + fetchInterval);
fetcher = new CalendarFetcher(url, fetchInterval, maximumEntries); fetcher = new CalendarFetcher(url, fetchInterval, maximumEntries, maximumNumberOfDays);
fetcher.onReceive(function(fetcher) { fetcher.onReceive(function(fetcher) {
//console.log('Broadcast events.'); //console.log('Broadcast events.');
//console.log(fetcher.events()); //console.log(fetcher.events());
@ -239,4 +238,3 @@ module.exports = NodeHelper.create({
fetcher.startFetch(); fetcher.startFetch();
} }
}); });

View File

@ -12,7 +12,7 @@ modules: [
position: 'top_left', // This can be any of the regions. position: 'top_left', // This can be any of the regions.
config: { config: {
// The config property is optional. // The config property is optional.
// See 'Configuration options' for more information. // See 'Configuration options' for more information.
} }
} }
] ]

View File

@ -33,7 +33,7 @@ Module.register('clock',{
// Set locale. // Set locale.
moment.locale(config.language); moment.locale(config.language);
}, },
// Override dom generator. // Override dom generator.
getDom: function() { getDom: function() {
@ -52,16 +52,15 @@ Module.register('clock',{
dateWrapper.innerHTML = moment().format('dddd, LL'); dateWrapper.innerHTML = moment().format('dddd, LL');
timeWrapper.innerHTML = moment().format((this.config.timeFormat === 24) ? 'HH:mm' : ('hh:mm')); timeWrapper.innerHTML = moment().format((this.config.timeFormat === 24) ? 'HH:mm' : ('hh:mm'));
secondsWrapper.innerHTML = moment().format('ss'); secondsWrapper.innerHTML = moment().format('ss');
// Combine wrappers. // Combine wrappers.
wrapper.appendChild(dateWrapper); wrapper.appendChild(dateWrapper);
wrapper.appendChild(timeWrapper); wrapper.appendChild(timeWrapper);
if (this.config.displaySeconds) { if (this.config.displaySeconds) {
timeWrapper.appendChild(secondsWrapper); timeWrapper.appendChild(secondsWrapper);
} }
// Return the wrapper to the dom. // Return the wrapper to the dom.
return wrapper; return wrapper;
} }
}); });

View File

@ -1,6 +1,6 @@
# Module: Compliments # Module: Compliments
The `compliments` module is one of the default modules of the MagicMirror. The `compliments` module is one of the default modules of the MagicMirror.
This module displays a random compliment. This module displays a random compliment.
## Using the module ## Using the module
@ -14,7 +14,7 @@ modules: [
config: { config: {
// The config property is optional. // The config property is optional.
// If no config is set, an example calendar is shown. // If no config is set, an example calendar is shown.
// See 'Configuration options' for more information. // See 'Configuration options' for more information.
} }
} }
] ]
@ -84,4 +84,4 @@ config: {
] ]
} }
} }
```` ````

View File

@ -40,7 +40,7 @@ Module.register('compliments',{
// Define start sequence. // Define start sequence.
start: function() { start: function() {
Log.info('Starting module: ' + this.name); Log.info('Starting module: ' + this.name);
this.lastComplimentIndex = -1; this.lastComplimentIndex = -1;
// Schedule update timer. // Schedule update timer.
@ -105,19 +105,18 @@ Module.register('compliments',{
var index = this.randomIndex(compliments); var index = this.randomIndex(compliments);
return compliments[index]; return compliments[index];
}, },
// Override dom generator. // Override dom generator.
getDom: function() { getDom: function() {
var complimentText = this.randomCompliment(); var complimentText = this.randomCompliment();
var compliment = document.createTextNode(complimentText); var compliment = document.createTextNode(complimentText);
var wrapper = document.createElement("div"); var wrapper = document.createElement("div");
wrapper.className = 'thin xlarge bright'; wrapper.className = 'thin xlarge bright';
wrapper.appendChild(compliment); wrapper.appendChild(compliment);
return wrapper; return wrapper;
} }
});
});

View File

@ -12,7 +12,7 @@ modules: [
position: 'top_right', // This can be any of the regions. position: 'top_right', // This can be any of the regions.
// Best results in left or right regions. // Best results in left or right regions.
config: { config: {
// See 'Configuration options' for more information. // See 'Configuration options' for more information.
location: 'Amsterdam,Netherlands', location: 'Amsterdam,Netherlands',
appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key. appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key.
} }
@ -140,6 +140,6 @@ The following properties can be configured:
}</code> }</code>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -6,4 +6,4 @@
-ms-transform: translate(0px,-3px); /* IE 9 */ -ms-transform: translate(0px,-3px); /* IE 9 */
-webkit-transform: translate(0px,-3px); /* Safari */ -webkit-transform: translate(0px,-3px); /* Safari */
transform: translate(0px,-3px); transform: translate(0px,-3px);
} }

View File

@ -65,7 +65,7 @@ Module.register('currentweather',{
// Set locale. // Set locale.
moment.locale(config.language); moment.locale(config.language);
this.windSpeed = null; this.windSpeed = null;
this.sunriseSunsetTime = null; this.sunriseSunsetTime = null;
this.sunriseSunsetIcon = null; this.sunriseSunsetIcon = null;
@ -76,7 +76,7 @@ Module.register('currentweather',{
this.scheduleUpdate(this.config.initialLoadDelay); this.scheduleUpdate(this.config.initialLoadDelay);
this.updateTimer = null; this.updateTimer = null;
}, },
// Override dom generator. // Override dom generator.
@ -110,7 +110,7 @@ Module.register('currentweather',{
small.appendChild(windIcon); small.appendChild(windIcon);
var windSpeed = document.createElement("span"); var windSpeed = document.createElement("span");
windSpeed.innerHTML = " " + this.windSpeed; windSpeed.innerHTML = " " + this.windSpeed;
small.appendChild(windSpeed); small.appendChild(windSpeed);
var spacer = document.createElement("span"); var spacer = document.createElement("span");
@ -122,7 +122,7 @@ Module.register('currentweather',{
small.appendChild(sunriseSunsetIcon); small.appendChild(sunriseSunsetIcon);
var sunriseSunsetTime = document.createElement("span"); var sunriseSunsetTime = document.createElement("span");
sunriseSunsetTime.innerHTML = " " + this.sunriseSunsetTime; sunriseSunsetTime.innerHTML = " " + this.sunriseSunsetTime;
small.appendChild(sunriseSunsetTime); small.appendChild(sunriseSunsetTime);
var large = document.createElement("div"); var large = document.createElement("div");
@ -134,7 +134,7 @@ Module.register('currentweather',{
var temperature = document.createElement("span"); var temperature = document.createElement("span");
temperature.className = "bright"; temperature.className = "bright";
temperature.innerHTML = " " + this.temperature + '&deg;'; temperature.innerHTML = " " + this.temperature + '&deg;';
large.appendChild(temperature); large.appendChild(temperature);
wrapper.appendChild(small); wrapper.appendChild(small);
@ -206,7 +206,7 @@ Module.register('currentweather',{
var now = moment().format('x'); var now = moment().format('x');
var sunrise = moment(data.sys.sunrise*1000).format('x'); var sunrise = moment(data.sys.sunrise*1000).format('x');
var sunset = moment(data.sys.sunset*1000).format('x'); var sunset = moment(data.sys.sunset*1000).format('x');
if (sunrise < now && sunset > now) { if (sunrise < now && sunset > now) {
this.sunriseSunsetTime = moment(data.sys.sunset*1000).format((this.config.timeFormat === 24) ? 'HH:mm' : 'hh:mm a'); this.sunriseSunsetTime = moment(data.sys.sunset*1000).format((this.config.timeFormat === 24) ? 'HH:mm' : 'hh:mm a');
@ -230,7 +230,7 @@ Module.register('currentweather',{
var nextLoad = this.config.updateInterval; var nextLoad = this.config.updateInterval;
if (typeof delay !== 'undefined' && delay >= 0) { if (typeof delay !== 'undefined' && delay >= 0) {
nextLoad = delay; nextLoad = delay;
} }
var self = this; var self = this;
setTimeout(function() { setTimeout(function() {
@ -268,4 +268,3 @@ Module.register('currentweather',{
return parseFloat(temperature).toFixed(1); return parseFloat(temperature).toFixed(1);
} }
}); });

View File

@ -20,4 +20,4 @@ var defaultModules = [
/*************** DO NOT EDIT THE LINE BELOW ***************/ /*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== 'undefined') {module.exports = defaultModules;} if (typeof module !== 'undefined') {module.exports = defaultModules;}

View File

@ -9,7 +9,7 @@ modules: [
module: 'helloworld', module: 'helloworld',
position: 'bottom_bar', // This can be any of the regions. position: 'bottom_bar', // This can be any of the regions.
config: { config: {
// See 'Configuration options' for more information. // See 'Configuration options' for more information.
text: 'Hello world!', text: 'Hello world!',
} }
} }
@ -46,6 +46,6 @@ The following properties can be configured:
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -19,9 +19,8 @@ Module.register('helloworld',{
getDom: function() { getDom: function() {
var wrapper = document.createElement("div"); var wrapper = document.createElement("div");
wrapper.className = this.config.classes; wrapper.className = this.config.classes;
wrapper.innerHTML = this.config.text; wrapper.innerHTML = this.config.text;
return wrapper; return wrapper;
} }
}); });

View File

@ -13,7 +13,7 @@ modules: [
config: { config: {
// The config property is optional. // The config property is optional.
// If no config is set, an example calendar is shown. // If no config is set, an example calendar is shown.
// See 'Configuration options' for more information. // See 'Configuration options' for more information.
} }
} }
] ]
@ -40,7 +40,7 @@ The following properties can be configured:
<br><b>Default value:</b> <code>'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml'</code> <br><b>Default value:</b> <code>'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml'</code>
</td> </td>
</tr> </tr>
<tr> <tr>
<td><code>showPublishDate</code></td> <td><code>showPublishDate</code></td>
<td>Display the publish date of an headline.<br> <td>Display the publish date of an headline.<br>
@ -48,7 +48,7 @@ The following properties can be configured:
<br><b>Default value:</b> <code>true</code> or <code>false</code> <br><b>Default value:</b> <code>true</code> or <code>false</code>
</td> </td>
</tr> </tr>
<tr> <tr>
<td><code>reloadInterval</code></td> <td><code>reloadInterval</code></td>
<td>How often does the content needs to be fetched? (Milliseconds)<br> <td>How often does the content needs to be fetched? (Milliseconds)<br>
@ -70,7 +70,6 @@ The following properties can be configured:
<br><b>Default value:</b> <code>2000</code> (2.5 seconds) <br><b>Default value:</b> <code>2000</code> (2.5 seconds)
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -5,7 +5,7 @@
* MIT Licensed. * MIT Licensed.
*/ */
var NewsFetcher = require('./newsfetcher.js'); var NewsFetcher = require('./newsfetcher.js');
/* Fetcher /* Fetcher
* Responsible for requesting an update on the set interval and broadcasting the data. * Responsible for requesting an update on the set interval and broadcasting the data.
@ -20,7 +20,7 @@ var Fetcher = function(url, reloadInterval) {
if (reloadInterval < 1000) { if (reloadInterval < 1000) {
reloadInterval = 1000; reloadInterval = 1000;
} }
var reloadTimer = null; var reloadTimer = null;
var items = []; var items = [];

View File

@ -14,8 +14,8 @@ Module.register('newsfeed',{
feedUrl: 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml', feedUrl: 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml',
showPublishDate: true, showPublishDate: true,
reloadInterval: 5 * 60 * 1000, // every 5 minutes reloadInterval: 5 * 60 * 1000, // every 5 minutes
updateInterval: 7.5 * 1000, updateInterval: 7.5 * 1000,
animationSpeed: 2.5 * 1000, animationSpeed: 2.5 * 1000,
}, },
// Define required scripts. // Define required scripts.
@ -29,7 +29,7 @@ Module.register('newsfeed',{
// Set locale. // Set locale.
moment.locale(config.language); moment.locale(config.language);
this.newsItems = []; this.newsItems = [];
this.loaded = false; this.loaded = false;
this.activeItem = 0; this.activeItem = 0;
@ -61,7 +61,7 @@ Module.register('newsfeed',{
} }
if (this.newsItems.length > 0) { if (this.newsItems.length > 0) {
if (this.config.showPublishDate) { if (this.config.showPublishDate) {
var timestamp = document.createElement("div"); var timestamp = document.createElement("div");
timestamp.className = "light small dimmed"; timestamp.className = "light small dimmed";
@ -119,5 +119,3 @@ Module.register('newsfeed',{
return string.charAt(0).toUpperCase() + string.slice(1); return string.charAt(0).toUpperCase() + string.slice(1);
} }
}); });

View File

@ -6,7 +6,7 @@
*/ */
var FeedMe = require('feedme'); var FeedMe = require('feedme');
var request = require('request'); var request = require('request');
var NewsFetcher = function() { var NewsFetcher = function() {
var self = this; var self = this;
@ -40,8 +40,8 @@ var NewsFetcher = function() {
* Fetch the new news items. * Fetch the new news items.
* *
* attribute url string - The url to fetch. * attribute url string - The url to fetch.
* attribute success function(items) - Callback on succes. * attribute success function(items) - Callback on succes.
* attribute error function(error) - Callback on error. * attribute error function(error) - Callback on error.
*/ */
self.fetchNews = function(url, success, error) { self.fetchNews = function(url, success, error) {
self.successCallback = success; self.successCallback = success;
@ -50,4 +50,4 @@ var NewsFetcher = function() {
}; };
}; };
module.exports = NewsFetcher; module.exports = NewsFetcher;

View File

@ -7,7 +7,7 @@
var NodeHelper = require('node_helper'); var NodeHelper = require('node_helper');
var validUrl = require('valid-url'); var validUrl = require('valid-url');
var Fetcher = require('./fetcher.js'); var Fetcher = require('./fetcher.js');
module.exports = NodeHelper.create({ module.exports = NodeHelper.create({
// Subclass start method. // Subclass start method.
@ -44,7 +44,7 @@ module.exports = NodeHelper.create({
if (typeof self.fetchers[url] === 'undefined') { if (typeof self.fetchers[url] === 'undefined') {
console.log('Create new news fetcher for url: ' + url + ' - Interval: ' + reloadInterval); console.log('Create new news fetcher for url: ' + url + ' - Interval: ' + reloadInterval);
fetcher = new Fetcher(url, reloadInterval); fetcher = new Fetcher(url, reloadInterval);
fetcher.onReceive(function(fetcher) { fetcher.onReceive(function(fetcher) {
self.sendSocketNotification('NEWS_ITEMS', { self.sendSocketNotification('NEWS_ITEMS', {
url: fetcher.url(), url: fetcher.url(),
@ -70,7 +70,3 @@ module.exports = NodeHelper.create({
fetcher.startFetch(); fetcher.startFetch();
} }
}); });

View File

@ -12,7 +12,7 @@ modules: [
position: 'top_right', // This can be any of the regions. position: 'top_right', // This can be any of the regions.
// Best results in left or right regions. // Best results in left or right regions.
config: { config: {
// See 'Configuration options' for more information. // See 'Configuration options' for more information.
location: 'Amsterdam,Netherlands', location: 'Amsterdam,Netherlands',
appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key. appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key.
} }
@ -148,6 +148,6 @@ The following properties can be configured:
}</code> }</code>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -11,4 +11,4 @@
.weatherforecast .min-temp { .weatherforecast .min-temp {
padding-left: 20px; padding-left: 20px;
padding-right: 0px; padding-right: 0px;
} }

View File

@ -18,7 +18,7 @@ Module.register('weatherforecast',{
animationSpeed: 1000, animationSpeed: 1000,
timeFormat: config.timeFormat, timeFormat: config.timeFormat,
lang: config.language, lang: config.language,
fade: true, fade: true,
fadePoint: 0.25, // Start on 1/4th of the list. fadePoint: 0.25, // Start on 1/4th of the list.
initialLoadDelay: 2500, // 2.5 seconds delay. This delay is used to keep the OpenWeather API happy. initialLoadDelay: 2500, // 2.5 seconds delay. This delay is used to keep the OpenWeather API happy.
@ -67,7 +67,7 @@ Module.register('weatherforecast',{
// Set locale. // Set locale.
moment.locale(config.language); moment.locale(config.language);
this.forecast = []; this.forecast = [];
this.loaded = false; this.loaded = false;
this.scheduleUpdate(this.config.initialLoadDelay); this.scheduleUpdate(this.config.initialLoadDelay);
@ -144,10 +144,10 @@ Module.register('weatherforecast',{
} }
} }
} }
return table; return table;
@ -238,7 +238,7 @@ Module.register('weatherforecast',{
var nextLoad = this.config.updateInterval; var nextLoad = this.config.updateInterval;
if (typeof delay !== 'undefined' && delay >= 0) { if (typeof delay !== 'undefined' && delay >= 0) {
nextLoad = delay; nextLoad = delay;
} }
var self = this; var self = this;
clearTimeout(this.updateTimer); clearTimeout(this.updateTimer);
@ -277,4 +277,3 @@ Module.register('weatherforecast',{
return parseFloat(temperature).toFixed(1); return parseFloat(temperature).toFixed(1);
} }
}); });

2
vendor/vendor.js vendored
View File

@ -11,4 +11,4 @@ var vendor = {
'moment.js' : 'moment/moment-with-locales.min.js', 'moment.js' : 'moment/moment-with-locales.min.js',
'weather-icons.css': 'weather-icons/weather-icons.css', 'weather-icons.css': 'weather-icons/weather-icons.css',
'font-awesome.css': 'font-awesome-4.5.0/css/font-awesome.min.css' 'font-awesome.css': 'font-awesome-4.5.0/css/font-awesome.min.css'
}; };